diff --git a/apps/web/.gitignore b/apps/web/.gitignore
new file mode 100644
index 0000000..41bc172
--- /dev/null
+++ b/apps/web/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+node_modules/
+dist/
+test-results/
+playwright-report/
diff --git a/apps/web/README.md b/apps/web/README.md
new file mode 100644
index 0000000..7dbf7eb
--- /dev/null
+++ b/apps/web/README.md
@@ -0,0 +1,73 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
+
+## React Compiler
+
+The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
+
+```js
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+
+ // Remove tseslint.configs.recommended and replace with this
+ tseslint.configs.recommendedTypeChecked,
+ // Alternatively, use this for stricter rules
+ tseslint.configs.strictTypeChecked,
+ // Optionally, add this for stylistic rules
+ tseslint.configs.stylisticTypeChecked,
+
+ // Other configs...
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+```
+
+You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
+
+```js
+// eslint.config.js
+import reactX from 'eslint-plugin-react-x'
+import reactDom from 'eslint-plugin-react-dom'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+ // Enable lint rules for React
+ reactX.configs['recommended-typescript'],
+ // Enable lint rules for React DOM
+ reactDom.configs.recommended,
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+```
diff --git a/apps/web/eslint.config.js b/apps/web/eslint.config.js
new file mode 100644
index 0000000..5e6b472
--- /dev/null
+++ b/apps/web/eslint.config.js
@@ -0,0 +1,23 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ js.configs.recommended,
+ tseslint.configs.recommended,
+ reactHooks.configs.flat.recommended,
+ reactRefresh.configs.vite,
+ ],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ },
+])
diff --git a/apps/web/index.html b/apps/web/index.html
new file mode 100644
index 0000000..b35acdb
--- /dev/null
+++ b/apps/web/index.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HMS 健康管理平台
+
+
+
+
+
+
diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json
new file mode 100644
index 0000000..181277a
--- /dev/null
+++ b/apps/web/package-lock.json
@@ -0,0 +1,8482 @@
+{
+ "name": "web",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "web",
+ "version": "0.0.0",
+ "dependencies": {
+ "@ant-design/charts": "^2.6.7",
+ "@ant-design/icons": "^6.1.1",
+ "@dnd-kit/core": "^6.3.1",
+ "@dnd-kit/sortable": "^10.0.0",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-react": "^1.0.6",
+ "@xyflow/react": "^12.10.2",
+ "antd": "^6.3.5",
+ "axios": "^1.15.0",
+ "dayjs": "^1.11.20",
+ "dompurify": "^3.4.5",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "react-router-dom": "^7.14.0",
+ "snabbdom": "^3.6.3",
+ "zustand": "^5.0.12"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.39.4",
+ "@playwright/test": "^1.52.0",
+ "@tailwindcss/vite": "^4.2.2",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@types/dompurify": "^3.2.0",
+ "@types/node": "^24.12.2",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.1",
+ "@vitest/coverage-v8": "^4.1.5",
+ "eslint": "^9.39.4",
+ "eslint-plugin-react-hooks": "^7.0.1",
+ "eslint-plugin-react-refresh": "^0.5.2",
+ "globals": "^17.4.0",
+ "jsdom": "^29.0.2",
+ "msw": "^2.13.6",
+ "tailwindcss": "^4.2.2",
+ "typescript": "~6.0.2",
+ "typescript-eslint": "^8.58.0",
+ "vite": "^8.0.4",
+ "vitest": "^4.1.5"
+ }
+ },
+ "node_modules/@adobe/css-tools": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz",
+ "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@ant-design/charts": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/@ant-design/charts/-/charts-2.6.7.tgz",
+ "integrity": "sha512-XfmsnspUpfrMlRFGTwmHJ2TPKcosq5a5nSxAfIOpEXAvmJBT2N16oejGTZhUFTzba8W3XtBOziwRAXmDmLUqvA==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/graphs": "^2.1.1",
+ "@ant-design/plots": "^2.6.7",
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.4",
+ "react-dom": ">=16.8.4"
+ }
+ },
+ "node_modules/@ant-design/charts-util": {
+ "version": "0.0.1-alpha.7",
+ "resolved": "https://registry.npmjs.org/@ant-design/charts-util/-/charts-util-0.0.1-alpha.7.tgz",
+ "integrity": "sha512-Yh0o6EdO6SvdSnStFZMbnUzjyymkVzV+TQ9ymVW9hlVgO/fUkUII3JYSdV+UVcFnYwUF0YiDKuSTLCZNAzg2bQ==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.4",
+ "react-dom": ">=16.8.4"
+ }
+ },
+ "node_modules/@ant-design/colors": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-8.0.1.tgz",
+ "integrity": "sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/fast-color": "^3.0.0"
+ }
+ },
+ "node_modules/@ant-design/cssinjs": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-2.1.2.tgz",
+ "integrity": "sha512-2Hy8BnCEH31xPeSLbhhB2ctCPXE2ZnASdi+KbSeS79BNbUhL9hAEe20SkUk+BR8aKTmqb6+FKFruk7w8z0VoRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "@emotion/hash": "^0.8.0",
+ "@emotion/unitless": "^0.7.5",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "stylis": "^4.3.4"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@ant-design/cssinjs-utils": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-2.1.2.tgz",
+ "integrity": "sha512-5fTHQ158jJJ5dC/ECeyIdZUzKxE/mpEMRZxthyG1sw/AKRHKgJBg00Yi6ACVXgycdje7KahRNvNET/uBccwCnA==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/cssinjs": "^2.1.2",
+ "@babel/runtime": "^7.23.2",
+ "@rc-component/util": "^1.4.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/@ant-design/fast-color": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-3.0.1.tgz",
+ "integrity": "sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.x"
+ }
+ },
+ "node_modules/@ant-design/graphs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@ant-design/graphs/-/graphs-2.1.1.tgz",
+ "integrity": "sha512-qT3Oo8BWeoAmZEy9gfR6uIk+rczbNJ3sWXKonoOD5koATWv7dY0kgvS1JnhdM1QW4FkfPPJTeQVSlRRUtvWDwA==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/charts-util": "0.0.1-alpha.7",
+ "@antv/g6": "^5.0.44",
+ "@antv/g6-extension-react": "^0.2.0",
+ "@antv/graphin": "^3.0.4",
+ "lodash": "^4.17.21",
+ "styled-components": "^6.1.15"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.4",
+ "react-dom": ">=16.8.4"
+ }
+ },
+ "node_modules/@ant-design/icons": {
+ "version": "6.2.5",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-6.2.5.tgz",
+ "integrity": "sha512-0hKtoKqTjGFOndUyJLJmC9Cg6k4rEO7rLo6xmgbNJH+/ZX1C57RVals2v1j1knHl9n7Q+sBOveTvn931wLOCKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/colors": "^8.0.1",
+ "@ant-design/icons-svg": "^4.4.2",
+ "@rc-component/util": "^1.11.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@ant-design/icons-svg": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
+ "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==",
+ "license": "MIT"
+ },
+ "node_modules/@ant-design/plots": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/@ant-design/plots/-/plots-2.6.8.tgz",
+ "integrity": "sha512-QsunUs2d5rbq/1BwVhga/siA5H50OaG23YopMYwPD4sPsza6NQzPQ8FM3elNIsD/BIk298tihqX1cJ/MmvVJbQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/charts-util": "0.0.3",
+ "@antv/event-emitter": "^0.1.3",
+ "@antv/g": "^6.1.7",
+ "@antv/g2": "^5.2.7",
+ "@antv/g2-extension-plot": "^0.2.1",
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.4",
+ "react-dom": ">=16.8.4"
+ }
+ },
+ "node_modules/@ant-design/plots/node_modules/@ant-design/charts-util": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@ant-design/charts-util/-/charts-util-0.0.3.tgz",
+ "integrity": "sha512-x1H7UT6t4dXAyGRoHqlOnEsEqBSTANFGTZEAMI0CWYhYUpp13n0o9grl9oPtoL6FEQMjUBTY+zGJKlHkz8smMw==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.4",
+ "react-dom": ">=16.8.4"
+ }
+ },
+ "node_modules/@ant-design/react-slick": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-2.0.0.tgz",
+ "integrity": "sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.28.4",
+ "clsx": "^2.1.1",
+ "json2mq": "^0.2.0",
+ "throttle-debounce": "^5.0.0"
+ },
+ "peerDependencies": {
+ "react": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@antv/algorithm": {
+ "version": "0.1.26",
+ "resolved": "https://registry.npmjs.org/@antv/algorithm/-/algorithm-0.1.26.tgz",
+ "integrity": "sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/util": "^2.0.13",
+ "tslib": "^2.0.0"
+ }
+ },
+ "node_modules/@antv/algorithm/node_modules/@antv/util": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz",
+ "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==",
+ "license": "ISC",
+ "dependencies": {
+ "csstype": "^3.0.8",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@antv/component": {
+ "version": "2.1.11",
+ "resolved": "https://registry.npmjs.org/@antv/component/-/component-2.1.11.tgz",
+ "integrity": "sha512-dTdz8VAd3rpjOaGEZTluz82mtzrP4XCtNlNQyrxY7VNRNcjtvpTLDn57bUL2lRu1T+iklKvgbE2llMriWkq9vQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g": "^6.1.11",
+ "@antv/scale": "^0.4.16",
+ "@antv/util": "^3.3.10",
+ "svg-path-parser": "^1.1.0"
+ }
+ },
+ "node_modules/@antv/component/node_modules/@antv/scale": {
+ "version": "0.4.16",
+ "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.4.16.tgz",
+ "integrity": "sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/util": "^3.3.7",
+ "color-string": "^1.5.5",
+ "fecha": "^4.2.1"
+ }
+ },
+ "node_modules/@antv/coord": {
+ "version": "0.4.7",
+ "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.4.7.tgz",
+ "integrity": "sha512-UTbrMLhwJUkKzqJx5KFnSRpU3BqrdLORJbwUbHK2zHSCT3q3bjcFA//ZYLVfIlwqFDXp/hzfMyRtp0c77A9ZVA==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/scale": "^0.4.12",
+ "@antv/util": "^2.0.13",
+ "gl-matrix": "^3.4.3"
+ }
+ },
+ "node_modules/@antv/coord/node_modules/@antv/scale": {
+ "version": "0.4.16",
+ "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.4.16.tgz",
+ "integrity": "sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/util": "^3.3.7",
+ "color-string": "^1.5.5",
+ "fecha": "^4.2.1"
+ }
+ },
+ "node_modules/@antv/coord/node_modules/@antv/scale/node_modules/@antv/util": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.11.tgz",
+ "integrity": "sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "gl-matrix": "^3.3.0",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@antv/coord/node_modules/@antv/util": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz",
+ "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==",
+ "license": "ISC",
+ "dependencies": {
+ "csstype": "^3.0.8",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/@antv/event-emitter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz",
+ "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==",
+ "license": "MIT"
+ },
+ "node_modules/@antv/expr": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@antv/expr/-/expr-1.0.2.tgz",
+ "integrity": "sha512-vrfdmPHkTuiS5voVutKl2l06w1ihBh9A8SFdQPEE+2KMVpkymzGOF1eWpfkbGZ7tiFE15GodVdhhHomD/hdIwg==",
+ "license": "MIT"
+ },
+ "node_modules/@antv/g": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@antv/g/-/g-6.3.1.tgz",
+ "integrity": "sha512-WYEKqy86LHB2PzTmrZXrIsIe+3Epeds2f68zceQ+BJtRoGki7Sy4IhlC8LrUMztgfT1t3d/0L745NWZwITroKA==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g-lite": "2.7.0",
+ "@antv/util": "^3.3.5",
+ "@babel/runtime": "^7.25.6",
+ "gl-matrix": "^3.4.3",
+ "html2canvas": "^1.4.1"
+ }
+ },
+ "node_modules/@antv/g-canvas": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-2.2.0.tgz",
+ "integrity": "sha512-h7zVBBo2aO64DuGKvq9sG+yTU3sCUb9DALCVm7nz8qGPs8hhLuFOkKPEzUDNfNYZGJUGzY8UDtJ3QRGRFcvEQg==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g-lite": "2.7.0",
+ "@antv/g-math": "3.1.0",
+ "@antv/util": "^3.3.5",
+ "@babel/runtime": "^7.25.6",
+ "gl-matrix": "^3.4.3",
+ "tslib": "^2.5.3"
+ }
+ },
+ "node_modules/@antv/g-lite": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@antv/g-lite/-/g-lite-2.7.0.tgz",
+ "integrity": "sha512-uSzgHYa5bwR5L2Au7/5tsOhFmXKZKLPBH90+Q9bP9teVs5VT4kOAi0isPSpDI8uhdDC2/VrfTWu5K9HhWI6FWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g-math": "3.1.0",
+ "@antv/util": "^3.3.5",
+ "@antv/vendor": "^1.0.3",
+ "@babel/runtime": "^7.25.6",
+ "eventemitter3": "^5.0.1",
+ "gl-matrix": "^3.4.3",
+ "tslib": "^2.5.3"
+ }
+ },
+ "node_modules/@antv/g-math": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-3.1.0.tgz",
+ "integrity": "sha512-DtN1Gj/yI0UiK18nSBsZX8RK0LszGwqfb+cBYWgE+ddyTm8dZnW4tPUhV7QXePsS6/A5hHC+JFpAAK7OEGo5ZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/util": "^3.3.5",
+ "@babel/runtime": "^7.25.6",
+ "gl-matrix": "^3.4.3",
+ "tslib": "^2.5.3"
+ }
+ },
+ "node_modules/@antv/g-plugin-dragndrop": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@antv/g-plugin-dragndrop/-/g-plugin-dragndrop-2.1.1.tgz",
+ "integrity": "sha512-+aesDUJVQDs6UJ2bOBbDlaGAPCfHmU0MbrMTlQlfpwNplWueqtgVAZ3L57oZ2ZGHRWUHiRwZGPjXMBM3O2LELw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g-lite": "2.7.0",
+ "@antv/util": "^3.3.5",
+ "@babel/runtime": "^7.25.6",
+ "tslib": "^2.5.3"
+ }
+ },
+ "node_modules/@antv/g-svg": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-2.1.1.tgz",
+ "integrity": "sha512-gVzBkjqA8FzDTbkuIxj6L0Omz/X/hFbYLzK6alWr0sHTfywqP6czcjDUJU8DF2MRIY1Twy55uZYW4dqqLXOXXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g-lite": "2.7.0",
+ "@antv/util": "^3.3.5",
+ "@babel/runtime": "^7.25.6",
+ "gl-matrix": "^3.4.3",
+ "tslib": "^2.5.3"
+ }
+ },
+ "node_modules/@antv/g2": {
+ "version": "5.4.8",
+ "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-5.4.8.tgz",
+ "integrity": "sha512-IvgIpwmT4M5/QAd3Mn2WiHIDeBqFJ4WA2gcZhRRSZuZ2KmgCqZWZwwIT0hc+kIGxwYeDoCQqf//t6FMVu3ryBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/component": "^2.1.9",
+ "@antv/coord": "^0.4.7",
+ "@antv/event-emitter": "^0.1.3",
+ "@antv/expr": "^1.0.2",
+ "@antv/g": "^6.1.24",
+ "@antv/g-canvas": "^2.0.43",
+ "@antv/g-plugin-dragndrop": "^2.0.35",
+ "@antv/scale": "^0.5.1",
+ "@antv/util": "^3.3.10",
+ "@antv/vendor": "^1.0.11",
+ "flru": "^1.0.2",
+ "pdfast": "^0.2.0"
+ }
+ },
+ "node_modules/@antv/g2-extension-plot": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@antv/g2-extension-plot/-/g2-extension-plot-0.2.2.tgz",
+ "integrity": "sha512-KJXCXO7as+h0hDqirGXf1omrNuYzQmY3VmBmp7lIvkepbQ7sz3pPwy895r1FWETGF3vTk5UeFcAF5yzzBHWgbw==",
+ "dependencies": {
+ "@antv/g2": "^5.1.8",
+ "@antv/util": "^3.3.5",
+ "@antv/vendor": "^1.0.10"
+ }
+ },
+ "node_modules/@antv/g6": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@antv/g6/-/g6-5.1.1.tgz",
+ "integrity": "sha512-50bXxMUf4mChyOv4ePVeWZLwotih9VunKfp0a++Wofv/wCyY8fb9+CV2wouIBCOZnd5ydBRA4NNaX9yLJzqa2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/algorithm": "^0.1.26",
+ "@antv/component": "^2.1.7",
+ "@antv/event-emitter": "^0.1.3",
+ "@antv/g": "^6.1.28",
+ "@antv/g-canvas": "^2.0.48",
+ "@antv/g-plugin-dragndrop": "^2.0.38",
+ "@antv/graphlib": "^2.0.4",
+ "@antv/hierarchy": "^0.7.1",
+ "@antv/layout": "^2.0.0",
+ "@antv/util": "^3.3.11",
+ "bubblesets-js": "^2.3.4"
+ }
+ },
+ "node_modules/@antv/g6-extension-react": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/@antv/g6-extension-react/-/g6-extension-react-0.2.7.tgz",
+ "integrity": "sha512-X/zxGiL/kyJ+5xteX1+P2mI07oLw+zfvKcIHxfynL7IGCQCwQ6q91LkJaOlSDTuWhNRXwnwJ4Cf2Nt/9Dhq5Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g": "^6.1.24",
+ "@antv/g-svg": "^2.0.38"
+ },
+ "peerDependencies": {
+ "@antv/g6": "^5.1.0",
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/@antv/graphin": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@antv/graphin/-/graphin-3.0.5.tgz",
+ "integrity": "sha512-V/j8R8Ty44wUqxVIYLdpPuIO8WWCTIVq1eBJg5YRunL5t5o5qAFpC/qkQxslbBMWyKdIH0oWBnvHA74riGi7cw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/g6": "^5.0.28"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.1.0",
+ "react-dom": "^18.0.0 || ^19.1.0"
+ }
+ },
+ "node_modules/@antv/graphlib": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@antv/graphlib/-/graphlib-2.0.4.tgz",
+ "integrity": "sha512-zc/5oQlsdk42Z0ib1mGklwzhJ5vczLFiPa1v7DgJkTbgJ2YxRh9xdarf86zI49sKVJmgbweRpJs7Nu5bIiwv4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/event-emitter": "^0.1.3"
+ }
+ },
+ "node_modules/@antv/hierarchy": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.7.1.tgz",
+ "integrity": "sha512-7r22r+HxfcRZp79ZjGmsn97zgC1Iajrv0Mm9DIgx3lPfk+Kme2MG/+EKdZj1iEBsN0rJRzjWVPGL5YrBdVHchw==",
+ "license": "MIT"
+ },
+ "node_modules/@antv/layout": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@antv/layout/-/layout-2.0.0.tgz",
+ "integrity": "sha512-aCZ3UdNc40SfT7meFV7QTADY2HCnc0DShVw56CJNTI6oExUIVU736grPuL5Dhb8/JrVaU4Y83QPN/P7KafBzlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/event-emitter": "^0.1.3",
+ "@antv/expr": "^1.0.2",
+ "@antv/graphlib": "^2.0.0",
+ "@antv/util": "^3.3.2",
+ "comlink": "^4.4.1",
+ "d3-force": "^3.0.0",
+ "d3-force-3d": "^3.0.5",
+ "d3-octree": "^1.0.2",
+ "d3-quadtree": "^3.0.1",
+ "dagre": "^0.8.5",
+ "ml-matrix": "^6.10.4",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@antv/scale": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.5.2.tgz",
+ "integrity": "sha512-rTHRAwvpHWC5PGZF/mJ2ZuTDqwwvVBDRph0Uu5PV9BXwzV7K8+9lsqGJ+XHVLxe8c6bKog5nlzvV/dcYb0d5Ow==",
+ "license": "MIT",
+ "dependencies": {
+ "@antv/util": "^3.3.7",
+ "color-string": "^1.5.5",
+ "fecha": "^4.2.1"
+ }
+ },
+ "node_modules/@antv/util": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/@antv/util/-/util-3.3.11.tgz",
+ "integrity": "sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "gl-matrix": "^3.3.0",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@antv/vendor": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@antv/vendor/-/vendor-1.0.11.tgz",
+ "integrity": "sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==",
+ "license": "MIT AND ISC",
+ "dependencies": {
+ "@types/d3-array": "^3.2.1",
+ "@types/d3-color": "^3.1.3",
+ "@types/d3-dispatch": "^3.0.6",
+ "@types/d3-dsv": "^3.0.7",
+ "@types/d3-ease": "^3.0.2",
+ "@types/d3-fetch": "^3.0.7",
+ "@types/d3-force": "^3.0.10",
+ "@types/d3-format": "^3.0.4",
+ "@types/d3-geo": "^3.1.0",
+ "@types/d3-hierarchy": "^3.1.7",
+ "@types/d3-interpolate": "^3.0.4",
+ "@types/d3-path": "^3.1.0",
+ "@types/d3-quadtree": "^3.0.6",
+ "@types/d3-random": "^3.0.3",
+ "@types/d3-scale": "^4.0.9",
+ "@types/d3-scale-chromatic": "^3.1.0",
+ "@types/d3-shape": "^3.1.7",
+ "@types/d3-time": "^3.0.4",
+ "@types/d3-timer": "^3.0.2",
+ "d3-array": "^3.2.4",
+ "d3-color": "^3.1.0",
+ "d3-dispatch": "^3.0.1",
+ "d3-dsv": "^3.0.1",
+ "d3-ease": "^3.0.1",
+ "d3-fetch": "^3.0.1",
+ "d3-force": "^3.0.0",
+ "d3-force-3d": "^3.0.5",
+ "d3-format": "^3.1.0",
+ "d3-geo": "^3.1.1",
+ "d3-geo-projection": "^4.0.0",
+ "d3-hierarchy": "^3.1.2",
+ "d3-interpolate": "^3.0.1",
+ "d3-path": "^3.1.0",
+ "d3-quadtree": "^3.0.1",
+ "d3-random": "^3.0.1",
+ "d3-regression": "^1.3.10",
+ "d3-scale": "^4.0.2",
+ "d3-scale-chromatic": "^3.1.0",
+ "d3-shape": "^3.2.0",
+ "d3-time": "^3.1.0",
+ "d3-timer": "^3.0.1"
+ }
+ },
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "5.1.11",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz",
+ "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/generational-cache": "^1.0.1",
+ "@csstools/css-calc": "^3.2.0",
+ "@csstools/css-color-parser": "^4.1.0",
+ "@csstools/css-parser-algorithms": "^4.0.0",
+ "@csstools/css-tokenizer": "^4.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/dom-selector": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz",
+ "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/generational-cache": "^1.0.1",
+ "@asamuzakjp/nwsapi": "^2.3.9",
+ "bidi-js": "^1.0.3",
+ "css-tree": "^3.2.1",
+ "is-potential-custom-element-name": "^1.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/generational-cache": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz",
+ "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/nwsapi": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz",
+ "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
+ "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
+ "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@bramus/specificity": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz",
+ "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "css-tree": "^3.0.0"
+ },
+ "bin": {
+ "specificity": "bin/cli.js"
+ }
+ },
+ "node_modules/@csstools/color-helpers": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz",
+ "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=20.19.0"
+ }
+ },
+ "node_modules/@csstools/css-calc": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz",
+ "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^4.0.0",
+ "@csstools/css-tokenizer": "^4.0.0"
+ }
+ },
+ "node_modules/@csstools/css-color-parser": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz",
+ "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/color-helpers": "^6.0.2",
+ "@csstools/css-calc": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^4.0.0",
+ "@csstools/css-tokenizer": "^4.0.0"
+ }
+ },
+ "node_modules/@csstools/css-parser-algorithms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz",
+ "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-tokenizer": "^4.0.0"
+ }
+ },
+ "node_modules/@csstools/css-syntax-patches-for-csstree": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz",
+ "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "peerDependencies": {
+ "css-tree": "^3.2.1"
+ },
+ "peerDependenciesMeta": {
+ "css-tree": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@csstools/css-tokenizer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz",
+ "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ }
+ },
+ "node_modules/@dnd-kit/accessibility": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
+ "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/core": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
+ "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@dnd-kit/accessibility": "^3.1.1",
+ "@dnd-kit/utilities": "^3.2.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/sortable": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
+ "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@dnd-kit/utilities": "^3.2.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@dnd-kit/core": "^6.3.0",
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/utilities": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
+ "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
+ "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
+ "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
+ "license": "MIT"
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "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",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
+ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.5"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
+ "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.14.0",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.1",
+ "minimatch": "^3.1.5",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
+ "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@exodus/bytes": {
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz",
+ "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "@noble/hashes": "^1.8.0 || ^2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@noble/hashes": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@inquirer/ansi": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz",
+ "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz",
+ "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^11.2.1",
+ "@inquirer/type": "^4.0.7"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "11.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz",
+ "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.7",
+ "@inquirer/figures": "^2.0.7",
+ "@inquirer/type": "^4.0.7",
+ "cli-width": "^4.1.0",
+ "fast-wrap-ansi": "^0.2.0",
+ "mute-stream": "^3.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz",
+ "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz",
+ "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "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",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@mswjs/interceptors": {
+ "version": "0.41.9",
+ "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.41.9.tgz",
+ "integrity": "sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@open-draft/deferred-promise": "^2.2.0",
+ "@open-draft/logger": "^0.3.0",
+ "@open-draft/until": "^2.0.0",
+ "is-node-process": "^1.2.0",
+ "outvariant": "^1.4.3",
+ "strict-event-emitter": "^0.5.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@mswjs/interceptors/node_modules/@open-draft/deferred-promise": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz",
+ "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
+ "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@tybys/wasm-util": "^0.10.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ },
+ "peerDependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1"
+ }
+ },
+ "node_modules/@open-draft/deferred-promise": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-3.0.0.tgz",
+ "integrity": "sha512-XW375UK8/9SqUVNVa6M0yEy8+iTi4QN5VZ7aZuRFQmy76LRwI9wy5F4YIBU6T+eTe2/DNDo8tqu8RHlwLHM6RA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@open-draft/logger": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz",
+ "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-node-process": "^1.2.0",
+ "outvariant": "^1.4.0"
+ }
+ },
+ "node_modules/@open-draft/until": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz",
+ "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@oxc-project/types": {
+ "version": "0.133.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
+ "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.60.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz",
+ "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.60.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@rc-component/async-validator": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.1.0.tgz",
+ "integrity": "sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.24.4"
+ },
+ "engines": {
+ "node": ">=14.x"
+ }
+ },
+ "node_modules/@rc-component/cascader": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/cascader/-/cascader-1.15.0.tgz",
+ "integrity": "sha512-ZzpMtwFCRo3fbXHuDnncARJMZQjdqA2w7aDuPofNQt+aDx39st1hgfIpEwTBLhe2Hqsvs/zOr8RTtgxTkCPySw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/select": "~1.6.0",
+ "@rc-component/tree": "~1.3.0",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/checkbox": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/checkbox/-/checkbox-2.0.0.tgz",
+ "integrity": "sha512-3CXGPpAR9gsPKeO2N78HAPOzU30UdemD6HGJoWVJOpa6WleaGB5kzZj3v6bdTZab31YuWgY/RxV3VKPctn0DwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/collapse": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/collapse/-/collapse-1.2.0.tgz",
+ "integrity": "sha512-ZRYSKSS39qsFx93p26bde7JUZJshsUBEQRlRXPuJYlAiNX0vyYlF5TsAm8JZN3LcF8XvKikdzPbgAtXSbkLUkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.10.1",
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/color-picker": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-3.1.1.tgz",
+ "integrity": "sha512-OHaCHLHszCegdXmIq2ZRIZBN/EtpT6Wm8SG/gpzLATHbVKc/avvuKi+zlOuk05FTWvgaMmpxAko44uRJ3M+2pg==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/fast-color": "^3.0.1",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/context": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-2.0.1.tgz",
+ "integrity": "sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/dialog": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/dialog/-/dialog-1.9.0.tgz",
+ "integrity": "sha512-zbAAogkg4kkKum79sLE6M+vq1jSAW25zdkafrahgcTP9t9S//SD634Znd1A4c8F2Gc12ZKnehGLsVaaOvZzD2A==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.1.3",
+ "@rc-component/portal": "^2.1.0",
+ "@rc-component/util": "^1.9.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/drawer": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/drawer/-/drawer-1.4.2.tgz",
+ "integrity": "sha512-1ib+fZEp6FBu+YvcIktm+nCQ+Q+qIpwpoaJH6opGr4ofh2QMq+qdr5DLC4oCf5qf3pcWX9lUWPYX652k4ini8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/portal": "^2.1.3",
+ "@rc-component/util": "^1.9.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/dropdown": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/dropdown/-/dropdown-1.0.2.tgz",
+ "integrity": "sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/trigger": "^3.0.0",
+ "@rc-component/util": "^1.2.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.11.0",
+ "react-dom": ">=16.11.0"
+ }
+ },
+ "node_modules/@rc-component/form": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/form/-/form-1.8.2.tgz",
+ "integrity": "sha512-ZidCvOLmM9Xr+3vzk4UAoR7Aj1W/5IHyrzlBB7sNkygpTeRVrohQSo4TN7W/nARTH+nt8zSAPsn4BEl4zLEO2g==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/async-validator": "^5.1.0",
+ "@rc-component/util": "^1.11.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/image": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/image/-/image-1.9.0.tgz",
+ "integrity": "sha512-khF7w7xkBH5B1bsBcI1FSUZdkyd1aqpl2eYyILCqCzzQH3XdfehGUaZTnptyaJJfs09/R5hv9jXWyazOMFIClQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.0.0",
+ "@rc-component/portal": "^2.1.2",
+ "@rc-component/util": "^1.10.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/input": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/input/-/input-1.3.1.tgz",
+ "integrity": "sha512-iFvTUT9W+JC/MSin2aGAk8NqsVlTzcExNC9DZariON1IWirju9NoNeEk47an4Q8iHazkoVI/y1LnDi88+CPcig==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/resize-observer": "^1.1.1",
+ "@rc-component/util": "^1.11.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@rc-component/input-number": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/input-number/-/input-number-1.6.2.tgz",
+ "integrity": "sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/mini-decimal": "^1.0.1",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/mentions": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/mentions/-/mentions-1.9.0.tgz",
+ "integrity": "sha512-WUwfFKDSOF5S9UPsNsXcLYtzjTxBGsftTXWRbZuxX6BYrsySISTnujfJNgaaQ6qVzaCDJ35QUkZKvsYxip1C5g==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/input": "~1.3.0",
+ "@rc-component/menu": "~1.3.0",
+ "@rc-component/trigger": "^3.0.0",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/menu": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/menu/-/menu-1.3.1.tgz",
+ "integrity": "sha512-pSZl9nBPgKgxN0aaW7NilIBEwWsc+43S+ulGdWAg9afak96dNOGWsGx0DLLBB1VQsAJvo6bQMTDzXoPlEHsBEw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/overflow": "^1.0.0",
+ "@rc-component/trigger": "^3.0.0",
+ "@rc-component/util": "^1.11.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/mini-decimal": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.3.tgz",
+ "integrity": "sha512-bk/FJ09fLf+NLODMAFll6CfYrHPBioTedhW6lxDBuuWucJEqFUd4l/D/5JgIi3dina6sYahB8iuPAZTNz2pMxw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ }
+ },
+ "node_modules/@rc-component/motion": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/motion/-/motion-1.3.2.tgz",
+ "integrity": "sha512-itfd+GztzJYAb04Z4RkEub1TbJAfZc2Iuy8p44U44xD1F5+fNYFKI3897ijlbIyfvXkTmMm+KGcjkQQGMHywEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/mutate-observer": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-2.0.1.tgz",
+ "integrity": "sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/notification": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@rc-component/notification/-/notification-2.0.7.tgz",
+ "integrity": "sha512-nqZzpf6BPdaj+3ILx7si79LLmqPKyUmQoXa+/9gg0SkH0v1DbD66oJgRMSBEVnd/zUT3D4gwxWIHUKebYf2ZXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/util": "^1.11.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/overflow": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/overflow/-/overflow-1.0.1.tgz",
+ "integrity": "sha512-syfmgAABaHCnCDzPwHZ/2tuvIcpOO3jefYZMmfkN+pmo8HKTzsfhS57vxo4ksPdN0By+uWVJhJWNFozNBxi2eA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "@rc-component/resize-observer": "^1.0.1",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/pagination": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/pagination/-/pagination-1.2.0.tgz",
+ "integrity": "sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/picker": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/picker/-/picker-1.10.0.tgz",
+ "integrity": "sha512-vVOXP2RVWozwpERGUFAehVH1Jz6o/uRrAb9qSZm1LC+iJs8rvEwFo1bzz2jlOYV+uWwu0dIuG86tnDui14Ea0w==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/overflow": "^1.0.0",
+ "@rc-component/resize-observer": "^1.0.0",
+ "@rc-component/trigger": "^3.6.15",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=12.x"
+ },
+ "peerDependencies": {
+ "date-fns": ">= 2.x",
+ "dayjs": ">= 1.x",
+ "luxon": ">= 3.x",
+ "moment": ">= 2.x",
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ },
+ "peerDependenciesMeta": {
+ "date-fns": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rc-component/portal": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-2.2.0.tgz",
+ "integrity": "sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=12.x"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/progress": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/progress/-/progress-1.0.2.tgz",
+ "integrity": "sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/qrcode": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.1.1.tgz",
+ "integrity": "sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/rate": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/rate/-/rate-1.0.1.tgz",
+ "integrity": "sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/resize-observer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/resize-observer/-/resize-observer-1.1.2.tgz",
+ "integrity": "sha512-t/Bb0W8uvL4PYKAB3YcChC+DlHh0Wt5kM7q/J+0qpVEUMLe7Hk5zuvc9km0hMnTFPSx5Z7Wu/fzCLN6erVLE8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/segmented": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/segmented/-/segmented-1.3.0.tgz",
+ "integrity": "sha512-5J/bJ01mbDnoA6P/FW8SxUvKn+OgUSTZJPzCNnTBntG50tzoP7DydGhqxp7ggZXZls7me3mc2EQDXakU3iTVFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/@rc-component/select": {
+ "version": "1.6.15",
+ "resolved": "https://registry.npmjs.org/@rc-component/select/-/select-1.6.15.tgz",
+ "integrity": "sha512-SyVCWnqxCQZZcQvQJ/CxSjx2bGma6ds/HtnpkIfZVnt6RoEgbqUmHgD6vrzNarNXwbLXerwVzWwq8F3d1sst7g==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/overflow": "^1.0.0",
+ "@rc-component/trigger": "^3.0.0",
+ "@rc-component/util": "^1.3.0",
+ "@rc-component/virtual-list": "^1.0.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/@rc-component/slider": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/slider/-/slider-1.0.1.tgz",
+ "integrity": "sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/steps": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/steps/-/steps-1.2.2.tgz",
+ "integrity": "sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.2.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/switch": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rc-component/switch/-/switch-1.0.3.tgz",
+ "integrity": "sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/table": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/table/-/table-1.10.2.tgz",
+ "integrity": "sha512-b3PjqB9Gp25p5t/zq+9QrbXbodkptT8/zvLmwgd2FNPUUtaYyDnQqfxeD5a7ao8E8lpinLHsi2u2vdfPhyNvAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/context": "^2.0.1",
+ "@rc-component/resize-observer": "^1.0.0",
+ "@rc-component/util": "^1.11.1",
+ "@rc-component/virtual-list": "^1.0.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/tabs": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/tabs/-/tabs-1.9.1.tgz",
+ "integrity": "sha512-6mY08Fce6aNOHuGsxbzT+f2ekgL9mg1cGGHkittMlVGymjGg+kGupu5v90sRxcUd/paRU9jclLLXtF/PkK1FUA==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/dropdown": "~1.0.0",
+ "@rc-component/menu": "~1.3.0",
+ "@rc-component/motion": "^1.1.3",
+ "@rc-component/resize-observer": "^1.0.0",
+ "@rc-component/util": "^1.11.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/tooltip": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/tooltip/-/tooltip-1.4.0.tgz",
+ "integrity": "sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/trigger": "^3.7.1",
+ "@rc-component/util": "^1.3.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/tour": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-2.4.0.tgz",
+ "integrity": "sha512-aui4r4TqmTzwaBgcQxHYep8kM8PTjZFufjokObpy35KfFeZ0k9ArquWFZqegQlH24P14t+F0qO0mGTgzlav1yg==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/portal": "^2.2.0",
+ "@rc-component/trigger": "^3.0.0",
+ "@rc-component/util": "^1.7.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/tree": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@rc-component/tree/-/tree-1.3.2.tgz",
+ "integrity": "sha512-bJFj46wEkpBPnWyTm18XmgAgNQ/4YvprxMOPPY2a6rmhGJYxLuNKEFiL5Qej4Qctu9wHJm8WW+v2SYskafE0kA==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.0.0",
+ "@rc-component/util": "^1.11.1",
+ "@rc-component/virtual-list": "^1.2.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=10.x"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/@rc-component/tree-select": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/tree-select/-/tree-select-1.9.0.tgz",
+ "integrity": "sha512-GXcFe15a+trUl1/J3OHWQhsVWFpwFpGFK2cqYWZ1sK22Zs3KZTvMwDpzr75PIo1s6QVioVxpE/pRwRopkeDQ6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/select": "~1.6.0",
+ "@rc-component/tree": "~1.3.0",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-dom": "*"
+ }
+ },
+ "node_modules/@rc-component/trigger": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-3.9.1.tgz",
+ "integrity": "sha512-LNsYvz60mrLJ/kRvKcHE7boUvcQfVMCfRqZ71x3Fo9AOiZ1KKIEqkzMA8DNvz2V3Bcvir/vwQNn7JF1NPODQ7Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/motion": "^1.1.4",
+ "@rc-component/portal": "^2.2.0",
+ "@rc-component/resize-observer": "^1.1.1",
+ "@rc-component/util": "^1.2.1",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/upload": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/upload/-/upload-1.1.1.tgz",
+ "integrity": "sha512-GvYWSKeaJTOxxC5p6+nOSadzfvXA1h8C/iHFPFZX+szH3JUXrvs+DLiW8YUTBgvMh8m63mJeHrlYlJzAlg+pDA==",
+ "license": "MIT",
+ "dependencies": {
+ "@rc-component/util": "^1.11.1",
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/@rc-component/util": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@rc-component/util/-/util-1.11.1.tgz",
+ "integrity": "sha512-awVlI3ub2vqfqkYxOBc/uQ0efm3jw0wcrhtO/YWLyZfxiKXczKwNbVuhlnyxytDt7H9pbbVQiqr+O6MLATtRYg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-mobile": "^5.0.0",
+ "react-is": "^18.2.0"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rc-component/virtual-list": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@rc-component/virtual-list/-/virtual-list-1.2.0.tgz",
+ "integrity": "sha512-iavRm1Jo4GDbASQwdGa7jFyk93RvSOo9xHyBT4QL1pgFJj/Fdf1G+3RErH7/7BmAMvx2AkF62mjGYxDbXsK9TQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.0",
+ "@rc-component/resize-observer": "^1.0.1",
+ "@rc-component/util": "^1.4.0",
+ "clsx": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/@rolldown/binding-android-arm64": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
+ "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
+ "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
+ "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
+ "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
+ "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
+ "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
+ "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
+ "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
+ "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
+ "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
+ "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-openharmony-arm64": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
+ "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-wasm32-wasi": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
+ "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "1.10.0",
+ "@emnapi/runtime": "1.10.0",
+ "@napi-rs/wasm-runtime": "^1.1.4"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
+ "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
+ "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
+ "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.21.0",
+ "jiti": "^2.6.1",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz",
+ "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.0",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.0",
+ "@tailwindcss/oxide-darwin-x64": "4.3.0",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.0",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.0",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.0",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.0",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz",
+ "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz",
+ "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz",
+ "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz",
+ "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz",
+ "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz",
+ "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz",
+ "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz",
+ "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz",
+ "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz",
+ "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.10.0",
+ "@emnapi/runtime": "^1.10.0",
+ "@emnapi/wasi-threads": "^1.2.1",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz",
+ "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz",
+ "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.0.tgz",
+ "integrity": "sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.0",
+ "@tailwindcss/oxide": "4.3.0",
+ "tailwindcss": "4.3.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
+ }
+ },
+ "node_modules/@testing-library/dom": {
+ "version": "10.4.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
+ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/runtime": "^7.12.5",
+ "@types/aria-query": "^5.0.1",
+ "aria-query": "5.3.0",
+ "dom-accessibility-api": "^0.5.9",
+ "lz-string": "^1.5.0",
+ "picocolors": "1.1.1",
+ "pretty-format": "^27.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@testing-library/jest-dom": {
+ "version": "6.9.1",
+ "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz",
+ "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@adobe/css-tools": "^4.4.0",
+ "aria-query": "^5.0.0",
+ "css.escape": "^1.5.1",
+ "dom-accessibility-api": "^0.6.3",
+ "picocolors": "^1.1.1",
+ "redent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
+ "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
+ "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@testing-library/react": {
+ "version": "16.3.2",
+ "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz",
+ "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@testing-library/dom": "^10.0.0",
+ "@types/react": "^18.0.0 || ^19.0.0",
+ "@types/react-dom": "^18.0.0 || ^19.0.0",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@transloadit/prettier-bytes": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
+ "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==",
+ "license": "MIT"
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.2",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
+ "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/aria-query": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
+ "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@types/chai": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
+ }
+ },
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-dispatch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz",
+ "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-drag": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
+ "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-dsv": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz",
+ "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-fetch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz",
+ "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-dsv": "*"
+ }
+ },
+ "node_modules/@types/d3-force": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
+ "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-format": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz",
+ "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-geo": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz",
+ "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/geojson": "*"
+ }
+ },
+ "node_modules/@types/d3-hierarchy": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz",
+ "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-quadtree": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz",
+ "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-random": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz",
+ "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-selection": {
+ "version": "3.0.11",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz",
+ "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz",
+ "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-transition": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
+ "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-zoom": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz",
+ "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-interpolate": "*",
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/dompurify": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz",
+ "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==",
+ "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dompurify": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@types/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/geojson": {
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.12.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz",
+ "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.16.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.16",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.16.tgz",
+ "integrity": "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/set-cookie-parser": {
+ "version": "2.4.10",
+ "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.10.tgz",
+ "integrity": "sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/statuses": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.6.tgz",
+ "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz",
+ "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.60.1",
+ "@typescript-eslint/type-utils": "8.60.1",
+ "@typescript-eslint/utils": "8.60.1",
+ "@typescript-eslint/visitor-keys": "8.60.1",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.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.60.1",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "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"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz",
+ "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.60.1",
+ "@typescript-eslint/types": "8.60.1",
+ "@typescript-eslint/typescript-estree": "8.60.1",
+ "@typescript-eslint/visitor-keys": "8.60.1",
+ "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 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz",
+ "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.60.1",
+ "@typescript-eslint/types": "^8.60.1",
+ "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.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz",
+ "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.60.1",
+ "@typescript-eslint/visitor-keys": "8.60.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/tsconfig-utils": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz",
+ "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==",
+ "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.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz",
+ "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.60.1",
+ "@typescript-eslint/typescript-estree": "8.60.1",
+ "@typescript-eslint/utils": "8.60.1",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.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 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz",
+ "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==",
+ "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.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz",
+ "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.60.1",
+ "@typescript-eslint/tsconfig-utils": "8.60.1",
+ "@typescript-eslint/types": "8.60.1",
+ "@typescript-eslint/visitor-keys": "8.60.1",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.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.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
+ "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz",
+ "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.60.1",
+ "@typescript-eslint/types": "8.60.1",
+ "@typescript-eslint/typescript-estree": "8.60.1"
+ },
+ "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 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz",
+ "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.60.1",
+ "eslint-visitor-keys": "^5.0.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/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@uppy/companion-client": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-2.2.2.tgz",
+ "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
+ "license": "MIT",
+ "dependencies": {
+ "@uppy/utils": "^4.1.2",
+ "namespace-emitter": "^2.0.1"
+ }
+ },
+ "node_modules/@uppy/core": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/@uppy/core/-/core-2.3.4.tgz",
+ "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@transloadit/prettier-bytes": "0.0.7",
+ "@uppy/store-default": "^2.1.1",
+ "@uppy/utils": "^4.1.3",
+ "lodash.throttle": "^4.1.1",
+ "mime-match": "^1.0.2",
+ "namespace-emitter": "^2.0.1",
+ "nanoid": "^3.1.25",
+ "preact": "^10.5.13"
+ }
+ },
+ "node_modules/@uppy/store-default": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-2.1.1.tgz",
+ "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==",
+ "license": "MIT"
+ },
+ "node_modules/@uppy/utils": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-4.1.3.tgz",
+ "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash.throttle": "^4.1.1"
+ }
+ },
+ "node_modules/@uppy/xhr-upload": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
+ "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@uppy/companion-client": "^2.2.2",
+ "@uppy/utils": "^4.1.2",
+ "nanoid": "^3.1.25"
+ },
+ "peerDependencies": {
+ "@uppy/core": "^2.3.3"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz",
+ "integrity": "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "^1.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
+ "babel-plugin-react-compiler": "^1.0.0",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@rolldown/plugin-babel": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/coverage-v8": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz",
+ "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@bcoe/v8-coverage": "^1.0.2",
+ "@vitest/utils": "4.1.8",
+ "ast-v8-to-istanbul": "^1.0.0",
+ "istanbul-lib-coverage": "^3.2.2",
+ "istanbul-lib-report": "^3.0.1",
+ "istanbul-reports": "^3.2.0",
+ "magicast": "^0.5.2",
+ "obug": "^2.1.1",
+ "std-env": "^4.0.0-rc.1",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@vitest/browser": "4.1.8",
+ "vitest": "4.1.8"
+ },
+ "peerDependenciesMeta": {
+ "@vitest/browser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz",
+ "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.1.0",
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "4.1.8",
+ "@vitest/utils": "4.1.8",
+ "chai": "^6.2.2",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz",
+ "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "4.1.8",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/pretty-format": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz",
+ "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz",
+ "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "4.1.8",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz",
+ "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.8",
+ "@vitest/utils": "4.1.8",
+ "magic-string": "^0.30.21",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz",
+ "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz",
+ "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.8",
+ "convert-source-map": "^2.0.0",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@wangeditor/basic-modules": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
+ "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-url": "^1.2.4"
+ },
+ "peerDependencies": {
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "lodash.throttle": "^4.1.1",
+ "nanoid": "^3.2.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/code-highlight": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
+ "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
+ "license": "MIT",
+ "dependencies": {
+ "prismjs": "^1.23.0"
+ },
+ "peerDependencies": {
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/core": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmjs.org/@wangeditor/core/-/core-1.1.19.tgz",
+ "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/event-emitter": "^0.3.3",
+ "event-emitter": "^0.3.5",
+ "html-void-elements": "^2.0.0",
+ "i18next": "^20.4.0",
+ "scroll-into-view-if-needed": "^2.2.28",
+ "slate-history": "^0.66.0"
+ },
+ "peerDependencies": {
+ "@uppy/core": "^2.1.1",
+ "@uppy/xhr-upload": "^2.0.3",
+ "dom7": "^3.0.0",
+ "is-hotkey": "^0.2.0",
+ "lodash.camelcase": "^4.3.0",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.debounce": "^4.0.8",
+ "lodash.foreach": "^4.5.0",
+ "lodash.isequal": "^4.5.0",
+ "lodash.throttle": "^4.1.1",
+ "lodash.toarray": "^4.4.0",
+ "nanoid": "^3.2.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/editor": {
+ "version": "5.1.23",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor/-/editor-5.1.23.tgz",
+ "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@uppy/core": "^2.1.1",
+ "@uppy/xhr-upload": "^2.0.3",
+ "@wangeditor/basic-modules": "^1.1.7",
+ "@wangeditor/code-highlight": "^1.0.3",
+ "@wangeditor/core": "^1.1.19",
+ "@wangeditor/list-module": "^1.0.5",
+ "@wangeditor/table-module": "^1.1.4",
+ "@wangeditor/upload-image-module": "^1.0.2",
+ "@wangeditor/video-module": "^1.1.4",
+ "dom7": "^3.0.0",
+ "is-hotkey": "^0.2.0",
+ "lodash.camelcase": "^4.3.0",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.debounce": "^4.0.8",
+ "lodash.foreach": "^4.5.0",
+ "lodash.isequal": "^4.5.0",
+ "lodash.throttle": "^4.1.1",
+ "lodash.toarray": "^4.4.0",
+ "nanoid": "^3.2.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/editor-for-react": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@wangeditor/editor-for-react/-/editor-for-react-1.0.6.tgz",
+ "integrity": "sha512-KJNSfgMr5Blzae3oyaiz20flMKHZHnvsz4bCYQKDCUs/qkvC+xNTnwedlCmhGP187oPWPEypCIYI8Zg6sz0psQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@wangeditor/core": ">=1.1.0",
+ "@wangeditor/editor": ">=5.1.0",
+ "react": ">=17.0.2",
+ "react-dom": ">=17.0.2"
+ }
+ },
+ "node_modules/@wangeditor/list-module": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@wangeditor/list-module/-/list-module-1.0.5.tgz",
+ "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/table-module": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/table-module/-/table-module-1.1.4.tgz",
+ "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "lodash.isequal": "^4.5.0",
+ "lodash.throttle": "^4.1.1",
+ "nanoid": "^3.2.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/upload-image-module": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
+ "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@uppy/core": "^2.0.3",
+ "@uppy/xhr-upload": "^2.0.3",
+ "@wangeditor/basic-modules": "1.x",
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "lodash.foreach": "^4.5.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@wangeditor/video-module": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@wangeditor/video-module/-/video-module-1.1.4.tgz",
+ "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@uppy/core": "^2.1.4",
+ "@uppy/xhr-upload": "^2.0.7",
+ "@wangeditor/core": "1.x",
+ "dom7": "^3.0.0",
+ "nanoid": "^3.2.0",
+ "slate": "^0.72.0",
+ "snabbdom": "^3.1.0"
+ }
+ },
+ "node_modules/@xyflow/react": {
+ "version": "12.11.0",
+ "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.11.0.tgz",
+ "integrity": "sha512-na4IO33FSs2OS72hASgZDmTYwFAkef7Z74uBUVrong3ARmQQHfnRUVaCFn1kTt5LbS6pK03TbYjCPGLjLFfziA==",
+ "license": "MIT",
+ "dependencies": {
+ "@xyflow/system": "0.0.77",
+ "classcat": "^5.0.3",
+ "zustand": "^4.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=17",
+ "@types/react-dom": ">=17",
+ "react": ">=17",
+ "react-dom": ">=17"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@xyflow/react/node_modules/zustand": {
+ "version": "4.5.7",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz",
+ "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==",
+ "license": "MIT",
+ "dependencies": {
+ "use-sync-external-store": "^1.2.2"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16.8",
+ "immer": ">=9.0.6",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@xyflow/system": {
+ "version": "0.0.77",
+ "resolved": "https://registry.npmjs.org/@xyflow/system/-/system-0.0.77.tgz",
+ "integrity": "sha512-qCDCMCQAAgUu8yHnhloHG9F5mwPX5E+Wl8McpYIOPSSXfzFJJoZcwOcsDiAjitVKIg2de1WmJbCHfpcvxprsgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-drag": "^3.0.7",
+ "@types/d3-interpolate": "^3.0.4",
+ "@types/d3-selection": "^3.0.10",
+ "@types/d3-transition": "^3.0.8",
+ "@types/d3-zoom": "^3.0.8",
+ "d3-drag": "^3.0.0",
+ "d3-interpolate": "^3.0.1",
+ "d3-selection": "^3.0.0",
+ "d3-zoom": "^3.0.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/antd": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/antd/-/antd-6.4.3.tgz",
+ "integrity": "sha512-6H2avkxCGfxcF67r3J2mwm9Ck50el1pks/73vfM1wDsPL/tPtj5vHuauMgJFnrqmq7CH3g8aoZ0VBQbt+jpAsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@ant-design/colors": "^8.0.1",
+ "@ant-design/cssinjs": "^2.1.2",
+ "@ant-design/cssinjs-utils": "^2.1.2",
+ "@ant-design/fast-color": "^3.0.1",
+ "@ant-design/icons": "^6.2.3",
+ "@ant-design/react-slick": "~2.0.0",
+ "@babel/runtime": "^7.29.2",
+ "@rc-component/cascader": "~1.15.0",
+ "@rc-component/checkbox": "~2.0.0",
+ "@rc-component/collapse": "~1.2.0",
+ "@rc-component/color-picker": "~3.1.1",
+ "@rc-component/dialog": "~1.9.0",
+ "@rc-component/drawer": "~1.4.2",
+ "@rc-component/dropdown": "~1.0.2",
+ "@rc-component/form": "~1.8.1",
+ "@rc-component/image": "~1.9.0",
+ "@rc-component/input": "~1.3.0",
+ "@rc-component/input-number": "~1.6.2",
+ "@rc-component/mentions": "~1.9.0",
+ "@rc-component/menu": "~1.3.0",
+ "@rc-component/motion": "^1.3.2",
+ "@rc-component/mutate-observer": "^2.0.1",
+ "@rc-component/notification": "~2.0.7",
+ "@rc-component/pagination": "~1.2.0",
+ "@rc-component/picker": "~1.10.0",
+ "@rc-component/progress": "~1.0.2",
+ "@rc-component/qrcode": "~1.1.1",
+ "@rc-component/rate": "~1.0.1",
+ "@rc-component/resize-observer": "^1.1.2",
+ "@rc-component/segmented": "~1.3.0",
+ "@rc-component/select": "~1.6.15",
+ "@rc-component/slider": "~1.0.1",
+ "@rc-component/steps": "~1.2.2",
+ "@rc-component/switch": "~1.0.3",
+ "@rc-component/table": "~1.10.0",
+ "@rc-component/tabs": "~1.9.0",
+ "@rc-component/tooltip": "~1.4.0",
+ "@rc-component/tour": "~2.4.0",
+ "@rc-component/tree": "~1.3.1",
+ "@rc-component/tree-select": "~1.9.0",
+ "@rc-component/trigger": "^3.9.0",
+ "@rc-component/upload": "~1.1.0",
+ "@rc-component/util": "^1.11.0",
+ "clsx": "^2.1.1",
+ "dayjs": "^1.11.11",
+ "scroll-into-view-if-needed": "^3.1.0",
+ "throttle-debounce": "^5.0.2"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ant-design"
+ },
+ "peerDependencies": {
+ "react": ">=18.0.0",
+ "react-dom": ">=18.0.0"
+ }
+ },
+ "node_modules/antd/node_modules/compute-scroll-into-view": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz",
+ "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==",
+ "license": "MIT"
+ },
+ "node_modules/antd/node_modules/scroll-into-view-if-needed": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
+ "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "compute-scroll-into-view": "^3.0.2"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "dequal": "^2.0.3"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ast-v8-to-istanbul": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz",
+ "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.31",
+ "estree-walker": "^3.0.3",
+ "js-tokens": "^10.0.0"
+ }
+ },
+ "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
+ "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"
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz",
+ "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.16.0",
+ "form-data": "^4.0.5",
+ "https-proxy-agent": "^5.0.1",
+ "proxy-from-env": "^2.1.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.10.33",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz",
+ "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/bidi-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
+ "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "require-from-string": "^2.0.2"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
+ "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.12",
+ "caniuse-lite": "^1.0.30001782",
+ "electron-to-chromium": "^1.5.328",
+ "node-releases": "^2.0.36",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bubblesets-js": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/bubblesets-js/-/bubblesets-js-2.3.4.tgz",
+ "integrity": "sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg==",
+ "license": "MIT"
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001793",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz",
+ "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chai": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/classcat": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
+ "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
+ "license": "MIT"
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/comlink": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.2.tgz",
+ "integrity": "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/compute-scroll-into-view": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+ "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "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/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "license": "MIT",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
+ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.27.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/css.escape": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
+ "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "license": "MIT"
+ },
+ "node_modules/d": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
+ "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
+ "license": "ISC",
+ "dependencies": {
+ "es5-ext": "^0.10.64",
+ "type": "^2.7.2"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-binarytree": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/d3-binarytree/-/d3-binarytree-1.0.2.tgz",
+ "integrity": "sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==",
+ "license": "MIT"
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dispatch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-drag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+ "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-selection": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dsv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "license": "ISC",
+ "dependencies": {
+ "commander": "7",
+ "iconv-lite": "0.6",
+ "rw": "1"
+ },
+ "bin": {
+ "csv2json": "bin/dsv2json.js",
+ "csv2tsv": "bin/dsv2dsv.js",
+ "dsv2dsv": "bin/dsv2dsv.js",
+ "dsv2json": "bin/dsv2json.js",
+ "json2csv": "bin/json2dsv.js",
+ "json2dsv": "bin/json2dsv.js",
+ "json2tsv": "bin/json2dsv.js",
+ "tsv2csv": "bin/dsv2dsv.js",
+ "tsv2json": "bin/dsv2json.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-fetch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+ "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dsv": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-force": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-force-3d": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/d3-force-3d/-/d3-force-3d-3.0.6.tgz",
+ "integrity": "sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==",
+ "license": "MIT",
+ "dependencies": {
+ "d3-binarytree": "1",
+ "d3-dispatch": "1 - 3",
+ "d3-octree": "1",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
+ "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
+ "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.5.0 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo-projection": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-4.0.0.tgz",
+ "integrity": "sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==",
+ "license": "ISC",
+ "dependencies": {
+ "commander": "7",
+ "d3-array": "1 - 3",
+ "d3-geo": "1.12.0 - 3"
+ },
+ "bin": {
+ "geo2svg": "bin/geo2svg.js",
+ "geograticule": "bin/geograticule.js",
+ "geoproject": "bin/geoproject.js",
+ "geoquantize": "bin/geoquantize.js",
+ "geostitch": "bin/geostitch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-hierarchy": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-octree": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/d3-octree/-/d3-octree-1.1.0.tgz",
+ "integrity": "sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==",
+ "license": "MIT"
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-quadtree": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-random": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+ "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-regression": {
+ "version": "1.3.10",
+ "resolved": "https://registry.npmjs.org/d3-regression/-/d3-regression-1.3.10.tgz",
+ "integrity": "sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-interpolate": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-selection": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-transition": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+ "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-dispatch": "1 - 3",
+ "d3-ease": "1 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "d3-selection": "2 - 3"
+ }
+ },
+ "node_modules/d3-zoom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+ "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-drag": "2 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-selection": "2 - 3",
+ "d3-transition": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/dagre": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz",
+ "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==",
+ "license": "MIT",
+ "dependencies": {
+ "graphlib": "^2.1.8",
+ "lodash": "^4.17.15"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz",
+ "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-mimetype": "^5.0.0",
+ "whatwg-url": "^16.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.21",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz",
+ "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==",
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dom-accessibility-api": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
+ "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/dom7": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz",
+ "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
+ "license": "MIT",
+ "dependencies": {
+ "ssr-window": "^3.0.0-alpha.1"
+ }
+ },
+ "node_modules/dompurify": {
+ "version": "3.4.7",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz",
+ "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.364",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz",
+ "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.22.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz",
+ "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
+ "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
+ "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es5-ext": {
+ "version": "0.10.64",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
+ "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
+ "hasInstallScript": true,
+ "license": "ISC",
+ "dependencies": {
+ "es6-iterator": "^2.0.3",
+ "es6-symbol": "^3.1.3",
+ "esniff": "^2.0.1",
+ "next-tick": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/es6-iterator": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+ "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
+ "license": "MIT",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "^0.10.35",
+ "es6-symbol": "^3.1.1"
+ }
+ },
+ "node_modules/es6-symbol": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
+ "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.2",
+ "ext": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.4",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
+ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.2",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.5",
+ "@eslint/js": "9.39.4",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz",
+ "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz",
+ "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "eslint": "^9 || ^10"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/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/esniff": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
+ "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+ "license": "ISC",
+ "dependencies": {
+ "d": "^1.0.1",
+ "es5-ext": "^0.10.62",
+ "event-emitter": "^0.3.5",
+ "type": "^2.7.2"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "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",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/event-emitter": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+ "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
+ "license": "MIT",
+ "dependencies": {
+ "d": "1",
+ "es5-ext": "~0.10.14"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
+ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
+ "license": "MIT"
+ },
+ "node_modules/expect-type": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
+ "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/ext": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
+ "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
+ "license": "ISC",
+ "dependencies": {
+ "type": "^2.7.2"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "license": "MIT"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-string-truncated-width": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz",
+ "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-string-width": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz",
+ "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-truncated-width": "^3.0.2"
+ }
+ },
+ "node_modules/fast-wrap-ansi": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz",
+ "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^3.0.2"
+ }
+ },
+ "node_modules/fdir": {
+ "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"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "license": "MIT"
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/flru": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/flru/-/flru-1.0.2.tgz",
+ "integrity": "sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+ "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fsevents": {
+ "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,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "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"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gl-matrix": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz",
+ "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==",
+ "license": "MIT"
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "17.6.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz",
+ "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "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/graphlib": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz",
+ "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.15"
+ }
+ },
+ "node_modules/graphql": {
+ "version": "16.14.1",
+ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.14.1.tgz",
+ "integrity": "sha512-cQOsSMS/IrDz82PVyRDvf/Q1F/bRbBVjJlh+xYOkI1qw2bWRvWGiWc+m2O0d6l4Bt1fyY+8kzJ8JFWGJqNeDBg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/headers-polyfill": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-5.0.1.tgz",
+ "integrity": "sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/set-cookie-parser": "^2.4.10",
+ "set-cookie-parser": "^3.0.1"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz",
+ "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@exodus/bytes": "^1.6.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/html-void-elements": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz",
+ "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "license": "MIT",
+ "dependencies": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/i18next": {
+ "version": "20.6.1",
+ "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.6.1.tgz",
+ "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/immer": {
+ "version": "9.0.21",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+ "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/is-any-array": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-3.0.0.tgz",
+ "integrity": "sha512-o4h+tylWykC4BD1vaejp6gDxoM13bwW8FGuNs4yIKpj8xbBJcRxJx8vZpq0dCr7ZDEfeKjmsi/euolKhX6f/ww==",
+ "license": "MIT"
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
+ "license": "MIT"
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-hotkey": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz",
+ "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==",
+ "license": "MIT"
+ },
+ "node_modules/is-mobile": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-5.0.0.tgz",
+ "integrity": "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==",
+ "license": "MIT"
+ },
+ "node_modules/is-node-process": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz",
+ "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
+ "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
+ "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsdom": {
+ "version": "29.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz",
+ "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/css-color": "^5.1.11",
+ "@asamuzakjp/dom-selector": "^7.1.1",
+ "@bramus/specificity": "^2.4.2",
+ "@csstools/css-syntax-patches-for-csstree": "^1.1.3",
+ "@exodus/bytes": "^1.15.0",
+ "css-tree": "^3.2.1",
+ "data-urls": "^7.0.0",
+ "decimal.js": "^10.6.0",
+ "html-encoding-sniffer": "^6.0.0",
+ "is-potential-custom-element-name": "^1.0.1",
+ "lru-cache": "^11.3.5",
+ "parse5": "^8.0.1",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^6.0.1",
+ "undici": "^7.25.0",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^8.0.1",
+ "whatwg-mimetype": "^5.0.0",
+ "whatwg-url": "^16.0.1",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "canvas": "^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jsdom/node_modules/lru-cache": {
+ "version": "11.5.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
+ "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json2mq": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+ "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "string-convert": "^0.2.0"
+ }
+ },
+ "node_modules/json5": {
+ "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"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.foreach": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
+ "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+ "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.toarray": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
+ "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==",
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "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"
+ }
+ },
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "lz-string": "bin/bin.js"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/magicast": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz",
+ "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.3",
+ "@babel/types": "^7.29.0",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
+ "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.27.1",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
+ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz",
+ "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
+ "license": "ISC",
+ "dependencies": {
+ "wildcard": "^1.1.0"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ml-array-max": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ml-array-max/-/ml-array-max-2.0.0.tgz",
+ "integrity": "sha512-QQZ4kENwpWmyNb98UXRDFXrmtIXuXtt1+bSbda/2KA85+F+rrJP8hZk6QOkCQXM2Th9mUDYdq/PNByPdT9ID4A==",
+ "license": "MIT",
+ "dependencies": {
+ "is-any-array": "^3.0.0"
+ }
+ },
+ "node_modules/ml-array-min": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ml-array-min/-/ml-array-min-2.0.0.tgz",
+ "integrity": "sha512-GRj6Ky6sW9vGL6yIjgsHmXZ9YgrdmcQ8nCxPqEGeKc6dkfYg1XDYxGFxADUjNuZyoCd5PUscWAS4N+cFaX6hFg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-any-array": "^3.0.0"
+ }
+ },
+ "node_modules/ml-array-rescale": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ml-array-rescale/-/ml-array-rescale-2.0.0.tgz",
+ "integrity": "sha512-2GGtKfSno94/kIloWGvpp/U5Q5vLvLrza+SAaGsLeo6Xj4mEbA6Gqx+oTfZFkxnd1grT2X007HfJNs3T5BsiVg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-any-array": "^3.0.0",
+ "ml-array-max": "^2.0.0",
+ "ml-array-min": "^2.0.0"
+ }
+ },
+ "node_modules/ml-matrix": {
+ "version": "6.12.2",
+ "resolved": "https://registry.npmjs.org/ml-matrix/-/ml-matrix-6.12.2.tgz",
+ "integrity": "sha512-GC+BnW+pBh8Auap8goAxY0senAmF0IEoc3HNVSfnfbvGw0buuDIYb9kAKMS1l+GiwJ1rfK2bzJ8IHhwjzATSFA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-any-array": "^3.0.0",
+ "ml-array-rescale": "^2.0.0"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/msw": {
+ "version": "2.14.6",
+ "resolved": "https://registry.npmjs.org/msw/-/msw-2.14.6.tgz",
+ "integrity": "sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/confirm": "^6.0.11",
+ "@mswjs/interceptors": "^0.41.3",
+ "@open-draft/deferred-promise": "^3.0.0",
+ "@types/statuses": "^2.0.6",
+ "cookie": "^1.1.1",
+ "graphql": "^16.13.2",
+ "headers-polyfill": "^5.0.1",
+ "is-node-process": "^1.2.0",
+ "outvariant": "^1.4.3",
+ "path-to-regexp": "^6.3.0",
+ "picocolors": "^1.1.1",
+ "rettime": "^0.11.11",
+ "statuses": "^2.0.2",
+ "strict-event-emitter": "^0.5.1",
+ "tough-cookie": "^6.0.1",
+ "type-fest": "^5.5.0",
+ "until-async": "^3.0.2",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "msw": "cli/index.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mswjs"
+ },
+ "peerDependencies": {
+ "typescript": ">= 4.8.x"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/mute-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz",
+ "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/namespace-emitter": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
+ "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+ "license": "ISC"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz",
+ "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/obug": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
+ "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/sxzz",
+ "https://opencollective.com/debug"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/outvariant": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz",
+ "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
+ "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^8.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
+ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pdfast": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/pdfast/-/pdfast-0.2.0.tgz",
+ "integrity": "sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==",
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.60.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz",
+ "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.60.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.60.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz",
+ "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
+ "node_modules/preact": {
+ "version": "10.29.2",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz",
+ "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^17.0.1"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/pretty-format/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/prismjs": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
+ "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz",
+ "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz",
+ "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.7"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
+ "node_modules/react-router": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.16.0.tgz",
+ "integrity": "sha512-wArC8lVyJb3+jM9OpDyW6hLCizACWkvQR/sSGqSs+o5uEXEtGlqdZ4v8hENR3Jad6i+LRkK93q/+bQAcvl6V1A==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.16.0.tgz",
+ "integrity": "sha512-kMUAbimWB5FVbF4Bce4bJsiKJWLIUHq/mEG8+CFDnCSgltptBiG5nguducmsJeGKytlCvQud9Qhzpn49iduTlA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.16.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/react-router/node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "license": "MIT"
+ },
+ "node_modules/redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/rettime": {
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.11.11.tgz",
+ "integrity": "sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/rolldown": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
+ "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@oxc-project/types": "=0.133.0",
+ "@rolldown/pluginutils": "^1.0.0"
+ },
+ "bin": {
+ "rolldown": "bin/cli.mjs"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "optionalDependencies": {
+ "@rolldown/binding-android-arm64": "1.0.3",
+ "@rolldown/binding-darwin-arm64": "1.0.3",
+ "@rolldown/binding-darwin-x64": "1.0.3",
+ "@rolldown/binding-freebsd-x64": "1.0.3",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
+ "@rolldown/binding-linux-arm64-gnu": "1.0.3",
+ "@rolldown/binding-linux-arm64-musl": "1.0.3",
+ "@rolldown/binding-linux-ppc64-gnu": "1.0.3",
+ "@rolldown/binding-linux-s390x-gnu": "1.0.3",
+ "@rolldown/binding-linux-x64-gnu": "1.0.3",
+ "@rolldown/binding-linux-x64-musl": "1.0.3",
+ "@rolldown/binding-openharmony-arm64": "1.0.3",
+ "@rolldown/binding-wasm32-wasi": "1.0.3",
+ "@rolldown/binding-win32-arm64-msvc": "1.0.3",
+ "@rolldown/binding-win32-x64-msvc": "1.0.3"
+ }
+ },
+ "node_modules/rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
+ },
+ "node_modules/scroll-into-view-if-needed": {
+ "version": "2.2.31",
+ "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+ "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
+ "license": "MIT",
+ "dependencies": {
+ "compute-scroll-into-view": "^1.0.20"
+ }
+ },
+ "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/set-cookie-parser": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz",
+ "integrity": "sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/slate": {
+ "version": "0.72.8",
+ "resolved": "https://registry.npmjs.org/slate/-/slate-0.72.8.tgz",
+ "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
+ "license": "MIT",
+ "dependencies": {
+ "immer": "^9.0.6",
+ "is-plain-object": "^5.0.0",
+ "tiny-warning": "^1.0.3"
+ }
+ },
+ "node_modules/slate-history": {
+ "version": "0.66.0",
+ "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.66.0.tgz",
+ "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
+ "license": "MIT",
+ "dependencies": {
+ "is-plain-object": "^5.0.0"
+ },
+ "peerDependencies": {
+ "slate": ">=0.65.3"
+ }
+ },
+ "node_modules/snabbdom": {
+ "version": "3.6.3",
+ "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.6.3.tgz",
+ "integrity": "sha512-W2lHLLw2qR2Vv0DcMmcxXqcfdBaIcoN+y/86SmHv8fn4DazEQSH6KN3TjZcWvwujW56OHiiirsbHWZb4vx/0fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.17.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "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"
+ }
+ },
+ "node_modules/ssr-window": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz",
+ "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==",
+ "license": "MIT"
+ },
+ "node_modules/stackback": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/std-env": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
+ "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/strict-event-emitter": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz",
+ "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-convert": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+ "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==",
+ "license": "MIT"
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/styled-components": {
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.4.2.tgz",
+ "integrity": "sha512-xZBhBJsMtGqb+aKcwKgaT+BtuFums9VynX2JRvXJGTx5UfZzN12rk5r4nVdhXYvRw+hE7yiYxVrOqJZaK2+Txg==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/is-prop-valid": "1.4.0",
+ "css-to-react-native": "3.2.0",
+ "csstype": "3.2.3",
+ "stylis": "4.3.6"
+ },
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/styled-components"
+ },
+ "peerDependencies": {
+ "css-to-react-native": ">= 3.2.0",
+ "react": ">= 16.8.0",
+ "react-dom": ">= 16.8.0",
+ "react-native": ">= 0.68.0"
+ },
+ "peerDependenciesMeta": {
+ "css-to-react-native": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/styled-components/node_modules/stylis": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz",
+ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
+ "license": "MIT"
+ },
+ "node_modules/stylis": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz",
+ "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==",
+ "license": "MIT"
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/svg-path-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/svg-path-parser/-/svg-path-parser-1.1.0.tgz",
+ "integrity": "sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==",
+ "license": "MIT"
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tagged-tag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
+ "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
+ "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "license": "MIT",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/throttle-debounce": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
+ "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.22"
+ }
+ },
+ "node_modules/tiny-warning": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+ "license": "MIT"
+ },
+ "node_modules/tinybench": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+ "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz",
+ "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
+ "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tldts": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.2.tgz",
+ "integrity": "sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tldts-core": "^7.4.2"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.2.tgz",
+ "integrity": "sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tough-cookie": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz",
+ "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tldts": "^7.0.5"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz",
+ "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "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==",
+ "license": "0BSD"
+ },
+ "node_modules/type": {
+ "version": "2.7.3",
+ "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
+ "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==",
+ "license": "ISC"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.7.0.tgz",
+ "integrity": "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "dependencies": {
+ "tagged-tag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.60.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz",
+ "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.60.1",
+ "@typescript-eslint/parser": "8.60.1",
+ "@typescript-eslint/typescript-estree": "8.60.1",
+ "@typescript-eslint/utils": "8.60.1"
+ },
+ "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 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/undici": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.0.tgz",
+ "integrity": "sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/until-async": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz",
+ "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/kettanaito"
+ }
+ },
+ "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",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
+ "node_modules/vite": {
+ "version": "8.0.16",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
+ "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.15",
+ "rolldown": "1.0.3",
+ "tinyglobby": "^0.2.17"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.1.18",
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "@vitejs/devtools": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/fsevents": {
+ "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,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz",
+ "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "4.1.8",
+ "@vitest/mocker": "4.1.8",
+ "@vitest/pretty-format": "4.1.8",
+ "@vitest/runner": "4.1.8",
+ "@vitest/snapshot": "4.1.8",
+ "@vitest/spy": "4.1.8",
+ "@vitest/utils": "4.1.8",
+ "es-module-lexer": "^2.0.0",
+ "expect-type": "^1.3.0",
+ "magic-string": "^0.30.21",
+ "obug": "^2.1.1",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "std-env": "^4.0.0-rc.1",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^1.0.2",
+ "tinyglobby": "^0.2.15",
+ "tinyrainbow": "^3.1.0",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@opentelemetry/api": "^1.9.0",
+ "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
+ "@vitest/browser-playwright": "4.1.8",
+ "@vitest/browser-preview": "4.1.8",
+ "@vitest/browser-webdriverio": "4.1.8",
+ "@vitest/coverage-istanbul": "4.1.8",
+ "@vitest/coverage-v8": "4.1.8",
+ "@vitest/ui": "4.1.8",
+ "happy-dom": "*",
+ "jsdom": "*",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser-playwright": {
+ "optional": true
+ },
+ "@vitest/browser-preview": {
+ "optional": true
+ },
+ "@vitest/browser-webdriverio": {
+ "optional": true
+ },
+ "@vitest/coverage-istanbul": {
+ "optional": true
+ },
+ "@vitest/coverage-v8": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ },
+ "vite": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz",
+ "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz",
+ "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz",
+ "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@exodus/bytes": "^1.11.0",
+ "tr46": "^6.0.0",
+ "webidl-conversions": "^8.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wildcard": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz",
+ "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==",
+ "license": "MIT"
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "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/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ },
+ "node_modules/zustand": {
+ "version": "5.0.14",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz",
+ "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/apps/web/package.json b/apps/web/package.json
new file mode 100644
index 0000000..51e17b4
--- /dev/null
+++ b/apps/web/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "web",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview",
+ "test": "vitest",
+ "test:coverage": "vitest run --coverage",
+ "test:e2e": "playwright test",
+ "test:e2e:ui": "playwright test --ui"
+ },
+ "dependencies": {
+ "@ant-design/charts": "^2.6.7",
+ "@ant-design/icons": "^6.1.1",
+ "@dnd-kit/core": "^6.3.1",
+ "@dnd-kit/sortable": "^10.0.0",
+ "@wangeditor/editor": "^5.1.23",
+ "@wangeditor/editor-for-react": "^1.0.6",
+ "@xyflow/react": "^12.10.2",
+ "antd": "^6.3.5",
+ "axios": "^1.15.0",
+ "dayjs": "^1.11.20",
+ "dompurify": "^3.4.5",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "react-router-dom": "^7.14.0",
+ "snabbdom": "^3.6.3",
+ "zustand": "^5.0.12"
+ },
+ "devDependencies": {
+ "@eslint/js": "^9.39.4",
+ "@playwright/test": "^1.52.0",
+ "@tailwindcss/vite": "^4.2.2",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@types/dompurify": "^3.2.0",
+ "@types/node": "^24.12.2",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.1",
+ "@vitest/coverage-v8": "^4.1.5",
+ "eslint": "^9.39.4",
+ "eslint-plugin-react-hooks": "^7.0.1",
+ "eslint-plugin-react-refresh": "^0.5.2",
+ "globals": "^17.4.0",
+ "jsdom": "^29.0.2",
+ "msw": "^2.13.6",
+ "tailwindcss": "^4.2.2",
+ "typescript": "~6.0.2",
+ "typescript-eslint": "^8.58.0",
+ "vite": "^8.0.4",
+ "vitest": "^4.1.5"
+ },
+ "msw": {
+ "workerDirectory": [
+ "public"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts
new file mode 100644
index 0000000..4604271
--- /dev/null
+++ b/apps/web/playwright.config.ts
@@ -0,0 +1,32 @@
+import { defineConfig, devices } from '@playwright/test';
+
+export default defineConfig({
+ testDir: './e2e',
+ testMatch: ['smoke/**/*.spec.ts', 'flows/**/*.spec.ts'],
+ timeout: 60_000,
+ retries: 1,
+ fullyParallel: false,
+ workers: 1,
+ forbidOnly: !!process.env.CI,
+ reporter: [['html', { open: 'never' }], ['list']],
+ use: {
+ baseURL: process.env.E2E_BASE_URL || 'http://localhost:5174',
+ headless: true,
+ screenshot: 'only-on-failure',
+ trace: 'on-first-retry',
+ video: 'retain-on-failure',
+ },
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ ],
+ globalSetup: './e2e/check-readiness',
+ webServer: {
+ command: 'pnpm dev',
+ port: 5174,
+ reuseExistingServer: true,
+ timeout: 30_000,
+ },
+});
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml
new file mode 100644
index 0000000..b510873
--- /dev/null
+++ b/apps/web/pnpm-lock.yaml
@@ -0,0 +1,5980 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@ant-design/charts':
+ specifier: ^2.6.7
+ version: 2.6.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@ant-design/icons':
+ specifier: ^6.1.1
+ version: 6.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@dnd-kit/core':
+ specifier: ^6.3.1
+ version: 6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@dnd-kit/sortable':
+ specifier: ^10.0.0
+ version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)
+ '@wangeditor/editor':
+ specifier: ^5.1.23
+ version: 5.1.23
+ '@wangeditor/editor-for-react':
+ specifier: ^1.0.6
+ version: 1.0.6(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/editor@5.1.23)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@xyflow/react':
+ specifier: ^12.10.2
+ version: 12.10.2(@types/react@19.2.14)(immer@9.0.21)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ antd:
+ specifier: ^6.3.5
+ version: 6.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ axios:
+ specifier: ^1.15.0
+ version: 1.15.0
+ dayjs:
+ specifier: ^1.11.20
+ version: 1.11.20
+ dompurify:
+ specifier: ^3.4.5
+ version: 3.4.5
+ react:
+ specifier: ^19.2.4
+ version: 19.2.5
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.5(react@19.2.5)
+ react-router-dom:
+ specifier: ^7.14.0
+ version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ snabbdom:
+ specifier: ^3.6.3
+ version: 3.6.3
+ zustand:
+ specifier: ^5.0.12
+ version: 5.0.12(@types/react@19.2.14)(immer@9.0.21)(react@19.2.5)(use-sync-external-store@1.6.0(react@19.2.5))
+ devDependencies:
+ '@eslint/js':
+ specifier: ^9.39.4
+ version: 9.39.4
+ '@playwright/test':
+ specifier: ^1.52.0
+ version: 1.59.1
+ '@tailwindcss/vite':
+ specifier: ^4.2.2
+ version: 4.2.2(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+ '@testing-library/jest-dom':
+ specifier: ^6.9.1
+ version: 6.9.1
+ '@testing-library/react':
+ specifier: ^16.3.2
+ version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@types/dompurify':
+ specifier: ^3.2.0
+ version: 3.2.0
+ '@types/node':
+ specifier: ^24.12.2
+ version: 24.12.2
+ '@types/react':
+ specifier: ^19.2.14
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.14)
+ '@vitejs/plugin-react':
+ specifier: ^6.0.1
+ version: 6.0.1(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+ '@vitest/coverage-v8':
+ specifier: ^4.1.5
+ version: 4.1.5(vitest@4.1.5)
+ eslint:
+ specifier: ^9.39.4
+ version: 9.39.4(jiti@2.6.1)
+ eslint-plugin-react-hooks:
+ specifier: ^7.0.1
+ version: 7.0.1(eslint@9.39.4(jiti@2.6.1))
+ eslint-plugin-react-refresh:
+ specifier: ^0.5.2
+ version: 0.5.2(eslint@9.39.4(jiti@2.6.1))
+ globals:
+ specifier: ^17.4.0
+ version: 17.4.0
+ jsdom:
+ specifier: ^29.0.2
+ version: 29.0.2
+ msw:
+ specifier: ^2.13.6
+ version: 2.13.6(@types/node@24.12.2)(typescript@6.0.2)
+ tailwindcss:
+ specifier: ^4.2.2
+ version: 4.2.2
+ typescript:
+ specifier: ~6.0.2
+ version: 6.0.2
+ typescript-eslint:
+ specifier: ^8.58.0
+ version: 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ vite:
+ specifier: ^8.0.4
+ version: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ vitest:
+ specifier: ^4.1.5
+ version: 4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+
+packages:
+
+ '@adobe/css-tools@4.4.4':
+ resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
+
+ '@ant-design/charts-util@0.0.1-alpha.7':
+ resolution: {integrity: sha512-Yh0o6EdO6SvdSnStFZMbnUzjyymkVzV+TQ9ymVW9hlVgO/fUkUII3JYSdV+UVcFnYwUF0YiDKuSTLCZNAzg2bQ==}
+ peerDependencies:
+ react: '>=16.8.4'
+ react-dom: '>=16.8.4'
+
+ '@ant-design/charts-util@0.0.3':
+ resolution: {integrity: sha512-x1H7UT6t4dXAyGRoHqlOnEsEqBSTANFGTZEAMI0CWYhYUpp13n0o9grl9oPtoL6FEQMjUBTY+zGJKlHkz8smMw==}
+ peerDependencies:
+ react: '>=16.8.4'
+ react-dom: '>=16.8.4'
+
+ '@ant-design/charts@2.6.7':
+ resolution: {integrity: sha512-XfmsnspUpfrMlRFGTwmHJ2TPKcosq5a5nSxAfIOpEXAvmJBT2N16oejGTZhUFTzba8W3XtBOziwRAXmDmLUqvA==}
+ peerDependencies:
+ react: '>=16.8.4'
+ react-dom: '>=16.8.4'
+
+ '@ant-design/colors@8.0.1':
+ resolution: {integrity: sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==}
+
+ '@ant-design/cssinjs-utils@2.1.2':
+ resolution: {integrity: sha512-5fTHQ158jJJ5dC/ECeyIdZUzKxE/mpEMRZxthyG1sw/AKRHKgJBg00Yi6ACVXgycdje7KahRNvNET/uBccwCnA==}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+
+ '@ant-design/cssinjs@2.1.2':
+ resolution: {integrity: sha512-2Hy8BnCEH31xPeSLbhhB2ctCPXE2ZnASdi+KbSeS79BNbUhL9hAEe20SkUk+BR8aKTmqb6+FKFruk7w8z0VoRQ==}
+ peerDependencies:
+ react: '>=16.0.0'
+ react-dom: '>=16.0.0'
+
+ '@ant-design/fast-color@3.0.1':
+ resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==}
+ engines: {node: '>=8.x'}
+
+ '@ant-design/graphs@2.1.1':
+ resolution: {integrity: sha512-qT3Oo8BWeoAmZEy9gfR6uIk+rczbNJ3sWXKonoOD5koATWv7dY0kgvS1JnhdM1QW4FkfPPJTeQVSlRRUtvWDwA==}
+ peerDependencies:
+ react: '>=16.8.4'
+ react-dom: '>=16.8.4'
+
+ '@ant-design/icons-svg@4.4.2':
+ resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==}
+
+ '@ant-design/icons@6.1.1':
+ resolution: {integrity: sha512-AMT4N2y++TZETNHiM77fs4a0uPVCJGuL5MTonk13Pvv7UN7sID1cNEZOc1qNqx6zLKAOilTEFAdAoAFKa0U//Q==}
+ engines: {node: '>=8'}
+ peerDependencies:
+ react: '>=16.0.0'
+ react-dom: '>=16.0.0'
+
+ '@ant-design/plots@2.6.8':
+ resolution: {integrity: sha512-QsunUs2d5rbq/1BwVhga/siA5H50OaG23YopMYwPD4sPsza6NQzPQ8FM3elNIsD/BIk298tihqX1cJ/MmvVJbQ==}
+ peerDependencies:
+ react: '>=16.8.4'
+ react-dom: '>=16.8.4'
+
+ '@ant-design/react-slick@2.0.0':
+ resolution: {integrity: sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg==}
+ peerDependencies:
+ react: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ '@antv/algorithm@0.1.26':
+ resolution: {integrity: sha512-DVhcFSQ8YQnMNW34Mk8BSsfc61iC1sAnmcfYoXTAshYHuU50p/6b7x3QYaGctDNKWGvi1ub7mPcSY0bK+aN0qg==}
+
+ '@antv/component@2.1.11':
+ resolution: {integrity: sha512-dTdz8VAd3rpjOaGEZTluz82mtzrP4XCtNlNQyrxY7VNRNcjtvpTLDn57bUL2lRu1T+iklKvgbE2llMriWkq9vQ==}
+
+ '@antv/coord@0.4.7':
+ resolution: {integrity: sha512-UTbrMLhwJUkKzqJx5KFnSRpU3BqrdLORJbwUbHK2zHSCT3q3bjcFA//ZYLVfIlwqFDXp/hzfMyRtp0c77A9ZVA==}
+
+ '@antv/event-emitter@0.1.3':
+ resolution: {integrity: sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==}
+
+ '@antv/expr@1.0.2':
+ resolution: {integrity: sha512-vrfdmPHkTuiS5voVutKl2l06w1ihBh9A8SFdQPEE+2KMVpkymzGOF1eWpfkbGZ7tiFE15GodVdhhHomD/hdIwg==}
+
+ '@antv/g-canvas@2.2.0':
+ resolution: {integrity: sha512-h7zVBBo2aO64DuGKvq9sG+yTU3sCUb9DALCVm7nz8qGPs8hhLuFOkKPEzUDNfNYZGJUGzY8UDtJ3QRGRFcvEQg==}
+
+ '@antv/g-lite@2.7.0':
+ resolution: {integrity: sha512-uSzgHYa5bwR5L2Au7/5tsOhFmXKZKLPBH90+Q9bP9teVs5VT4kOAi0isPSpDI8uhdDC2/VrfTWu5K9HhWI6FWw==}
+
+ '@antv/g-math@3.1.0':
+ resolution: {integrity: sha512-DtN1Gj/yI0UiK18nSBsZX8RK0LszGwqfb+cBYWgE+ddyTm8dZnW4tPUhV7QXePsS6/A5hHC+JFpAAK7OEGo5ZQ==}
+
+ '@antv/g-plugin-dragndrop@2.1.1':
+ resolution: {integrity: sha512-+aesDUJVQDs6UJ2bOBbDlaGAPCfHmU0MbrMTlQlfpwNplWueqtgVAZ3L57oZ2ZGHRWUHiRwZGPjXMBM3O2LELw==}
+
+ '@antv/g-svg@2.1.1':
+ resolution: {integrity: sha512-gVzBkjqA8FzDTbkuIxj6L0Omz/X/hFbYLzK6alWr0sHTfywqP6czcjDUJU8DF2MRIY1Twy55uZYW4dqqLXOXXg==}
+
+ '@antv/g2-extension-plot@0.2.2':
+ resolution: {integrity: sha512-KJXCXO7as+h0hDqirGXf1omrNuYzQmY3VmBmp7lIvkepbQ7sz3pPwy895r1FWETGF3vTk5UeFcAF5yzzBHWgbw==}
+
+ '@antv/g2@5.4.8':
+ resolution: {integrity: sha512-IvgIpwmT4M5/QAd3Mn2WiHIDeBqFJ4WA2gcZhRRSZuZ2KmgCqZWZwwIT0hc+kIGxwYeDoCQqf//t6FMVu3ryBg==}
+
+ '@antv/g6-extension-react@0.2.7':
+ resolution: {integrity: sha512-X/zxGiL/kyJ+5xteX1+P2mI07oLw+zfvKcIHxfynL7IGCQCwQ6q91LkJaOlSDTuWhNRXwnwJ4Cf2Nt/9Dhq5Dg==}
+ peerDependencies:
+ '@antv/g6': ^5.1.0
+ react: '>=16.8'
+ react-dom: '>=16.8'
+
+ '@antv/g6@5.1.0':
+ resolution: {integrity: sha512-tvoBDKypL/zWEG99pgwGJLWr2CKA+6zVixYxaVzDOp0+TrPY2cxB1jevxFGPjbTOLBIMYt/vKCh1jnmDtfvtpg==}
+
+ '@antv/g@6.3.1':
+ resolution: {integrity: sha512-WYEKqy86LHB2PzTmrZXrIsIe+3Epeds2f68zceQ+BJtRoGki7Sy4IhlC8LrUMztgfT1t3d/0L745NWZwITroKA==}
+
+ '@antv/graphin@3.0.5':
+ resolution: {integrity: sha512-V/j8R8Ty44wUqxVIYLdpPuIO8WWCTIVq1eBJg5YRunL5t5o5qAFpC/qkQxslbBMWyKdIH0oWBnvHA74riGi7cw==}
+ peerDependencies:
+ react: ^18.0.0 || ^19.1.0
+ react-dom: ^18.0.0 || ^19.1.0
+
+ '@antv/graphlib@2.0.4':
+ resolution: {integrity: sha512-zc/5oQlsdk42Z0ib1mGklwzhJ5vczLFiPa1v7DgJkTbgJ2YxRh9xdarf86zI49sKVJmgbweRpJs7Nu5bIiwv4w==}
+
+ '@antv/hierarchy@0.7.1':
+ resolution: {integrity: sha512-7r22r+HxfcRZp79ZjGmsn97zgC1Iajrv0Mm9DIgx3lPfk+Kme2MG/+EKdZj1iEBsN0rJRzjWVPGL5YrBdVHchw==}
+
+ '@antv/layout@2.0.0':
+ resolution: {integrity: sha512-aCZ3UdNc40SfT7meFV7QTADY2HCnc0DShVw56CJNTI6oExUIVU736grPuL5Dhb8/JrVaU4Y83QPN/P7KafBzlw==}
+
+ '@antv/scale@0.4.16':
+ resolution: {integrity: sha512-5wg/zB5kXHxpTV5OYwJD3ja6R8yTiqIOkjOhmpEJiowkzRlbEC/BOyMvNUq5fqFIHnMCE9woO7+c3zxEQCKPjw==}
+
+ '@antv/scale@0.5.2':
+ resolution: {integrity: sha512-rTHRAwvpHWC5PGZF/mJ2ZuTDqwwvVBDRph0Uu5PV9BXwzV7K8+9lsqGJ+XHVLxe8c6bKog5nlzvV/dcYb0d5Ow==}
+
+ '@antv/util@2.0.17':
+ resolution: {integrity: sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==}
+
+ '@antv/util@3.3.11':
+ resolution: {integrity: sha512-FII08DFM4ABh2q5rPYdr0hMtKXRgeZazvXaFYCs7J7uTcWDHUhczab2qOCJLNDugoj8jFag1djb7wS9ehaRYBg==}
+
+ '@antv/vendor@1.0.11':
+ resolution: {integrity: sha512-LmhPEQ+aapk3barntaiIxJ5VHno/Tyab2JnfdcPzp5xONh/8VSfed4bo/9xKo5HcUAEydko38vYLfj6lJliLiw==}
+
+ '@asamuzakjp/css-color@5.1.11':
+ resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/dom-selector@7.1.1':
+ resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/generational-cache@1.0.1':
+ resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ '@asamuzakjp/nwsapi@2.3.9':
+ resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
+
+ '@babel/code-frame@7.29.0':
+ resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.29.2':
+ resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.29.2':
+ resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/runtime@7.29.2':
+ resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
+ '@bcoe/v8-coverage@1.0.2':
+ resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
+ engines: {node: '>=18'}
+
+ '@bramus/specificity@2.4.2':
+ resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==}
+ hasBin: true
+
+ '@csstools/color-helpers@6.0.2':
+ resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==}
+ engines: {node: '>=20.19.0'}
+
+ '@csstools/css-calc@3.2.0':
+ resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-color-parser@4.1.0':
+ resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^4.0.0
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0':
+ resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.3':
+ resolution: {integrity: sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==}
+ peerDependencies:
+ css-tree: ^3.2.1
+ peerDependenciesMeta:
+ css-tree:
+ optional: true
+
+ '@csstools/css-tokenizer@4.0.0':
+ resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
+ engines: {node: '>=20.19.0'}
+
+ '@dnd-kit/accessibility@3.1.1':
+ resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@dnd-kit/core@6.3.1':
+ resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@dnd-kit/sortable@10.0.0':
+ resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==}
+ peerDependencies:
+ '@dnd-kit/core': ^6.3.0
+ react: '>=16.8.0'
+
+ '@dnd-kit/utilities@3.2.2':
+ resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@emnapi/core@1.9.2':
+ resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==}
+
+ '@emnapi/runtime@1.9.2':
+ resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==}
+
+ '@emnapi/wasi-threads@1.2.1':
+ resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
+
+ '@emotion/hash@0.8.0':
+ resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
+
+ '@emotion/is-prop-valid@1.4.0':
+ resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
+ '@emotion/unitless@0.7.5':
+ resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
+
+ '@eslint-community/eslint-utils@4.9.1':
+ resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+ '@eslint-community/regexpp@4.12.2':
+ resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
+ engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+ '@eslint/config-array@0.21.2':
+ resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/config-helpers@0.4.2':
+ resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/core@0.17.0':
+ resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/eslintrc@3.3.5':
+ resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/js@9.39.4':
+ resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/object-schema@2.1.7':
+ resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@eslint/plugin-kit@0.4.1':
+ resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@exodus/bytes@1.15.0':
+ resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+ peerDependencies:
+ '@noble/hashes': ^1.8.0 || ^2.0.0
+ peerDependenciesMeta:
+ '@noble/hashes':
+ optional: true
+
+ '@humanfs/core@0.19.1':
+ resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanfs/node@0.16.7':
+ resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
+ engines: {node: '>=18.18.0'}
+
+ '@humanwhocodes/module-importer@1.0.1':
+ resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+ engines: {node: '>=12.22'}
+
+ '@humanwhocodes/retry@0.4.3':
+ resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
+ engines: {node: '>=18.18'}
+
+ '@inquirer/ansi@2.0.5':
+ resolution: {integrity: sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
+
+ '@inquirer/confirm@6.0.12':
+ resolution: {integrity: sha512-h9FgGun3QwVYNj5TWIZZ+slii73bMoBFjPfVIGtnFuL4t8gBiNDV9PcSfIzkuxvgquJKt9nr1QzszpBzTbH8Og==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@inquirer/core@11.1.9':
+ resolution: {integrity: sha512-BDE4fG22uYh1bGSifcj7JSx119TVYNViMhMu85usp4Fswrzh6M0DV3yld64jA98uOAa2GSQ4Bg4bZRm2d2cwSg==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@inquirer/figures@2.0.5':
+ resolution: {integrity: sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
+
+ '@inquirer/type@4.0.5':
+ resolution: {integrity: sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==}
+ engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'}
+ peerDependencies:
+ '@types/node': '>=18'
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@mswjs/interceptors@0.41.6':
+ resolution: {integrity: sha512-qmDvJIjcNsZ6tXWy2G9yuCgMPTTn35GMA3dPpSLm7QJVpbQzYdw0ALy1bKoivXnEM3U93/OrK+/M719b+fg84Q==}
+ engines: {node: '>=18'}
+
+ '@napi-rs/wasm-runtime@1.1.3':
+ resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==}
+ peerDependencies:
+ '@emnapi/core': ^1.7.1
+ '@emnapi/runtime': ^1.7.1
+
+ '@open-draft/deferred-promise@2.2.0':
+ resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==}
+
+ '@open-draft/deferred-promise@3.0.0':
+ resolution: {integrity: sha512-XW375UK8/9SqUVNVa6M0yEy8+iTi4QN5VZ7aZuRFQmy76LRwI9wy5F4YIBU6T+eTe2/DNDo8tqu8RHlwLHM6RA==}
+
+ '@open-draft/logger@0.3.0':
+ resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==}
+
+ '@open-draft/until@2.1.0':
+ resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
+
+ '@oxc-project/types@0.124.0':
+ resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==}
+
+ '@playwright/test@1.59.1':
+ resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ '@rc-component/async-validator@5.1.0':
+ resolution: {integrity: sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==}
+ engines: {node: '>=14.x'}
+
+ '@rc-component/cascader@1.14.0':
+ resolution: {integrity: sha512-Ip9356xwZUR2nbW5PRVGif4B/bDve4pLa/N+PGbvBaTnjbvmN4PFMBGQSmlDlzKP1ovxaYMvwF/dI9lXNLT4iQ==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/checkbox@2.0.0':
+ resolution: {integrity: sha512-3CXGPpAR9gsPKeO2N78HAPOzU30UdemD6HGJoWVJOpa6WleaGB5kzZj3v6bdTZab31YuWgY/RxV3VKPctn0DwQ==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/collapse@1.2.0':
+ resolution: {integrity: sha512-ZRYSKSS39qsFx93p26bde7JUZJshsUBEQRlRXPuJYlAiNX0vyYlF5TsAm8JZN3LcF8XvKikdzPbgAtXSbkLUkw==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/color-picker@3.1.1':
+ resolution: {integrity: sha512-OHaCHLHszCegdXmIq2ZRIZBN/EtpT6Wm8SG/gpzLATHbVKc/avvuKi+zlOuk05FTWvgaMmpxAko44uRJ3M+2pg==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/context@2.0.1':
+ resolution: {integrity: sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/dialog@1.8.4':
+ resolution: {integrity: sha512-Ay6PM7phkTkquplG8fWfUGFZ2GTLx9diTl4f0d8Eqxd7W1u1KjE9AQooFQHOHnhZf0Ya3z51+5EKCWHmt/dNEw==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/drawer@1.4.2':
+ resolution: {integrity: sha512-1ib+fZEp6FBu+YvcIktm+nCQ+Q+qIpwpoaJH6opGr4ofh2QMq+qdr5DLC4oCf5qf3pcWX9lUWPYX652k4ini8Q==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/dropdown@1.0.2':
+ resolution: {integrity: sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==}
+ peerDependencies:
+ react: '>=16.11.0'
+ react-dom: '>=16.11.0'
+
+ '@rc-component/form@1.8.0':
+ resolution: {integrity: sha512-eUD5KKYnIZWmJwRA0vnyO/ovYUfHGU1svydY1OrqU5fw8Oz9Tdqvxvrlh0wl6xI/EW69dT7II49xpgOWzK3T5A==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/image@1.8.1':
+ resolution: {integrity: sha512-JfPCijmMl+EaMvbftsEs/4VHmTyJKsZBh5ujFowSA45i9NTVYS1vuHtgpVV/QrGa27kXwbVOZriffCe/PNKuMw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/input-number@1.6.2':
+ resolution: {integrity: sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/input@1.1.2':
+ resolution: {integrity: sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg==}
+ peerDependencies:
+ react: '>=16.0.0'
+ react-dom: '>=16.0.0'
+
+ '@rc-component/mentions@1.6.0':
+ resolution: {integrity: sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/menu@1.2.0':
+ resolution: {integrity: sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/mini-decimal@1.1.3':
+ resolution: {integrity: sha512-bk/FJ09fLf+NLODMAFll6CfYrHPBioTedhW6lxDBuuWucJEqFUd4l/D/5JgIi3dina6sYahB8iuPAZTNz2pMxw==}
+ engines: {node: '>=8.x'}
+
+ '@rc-component/motion@1.3.2':
+ resolution: {integrity: sha512-itfd+GztzJYAb04Z4RkEub1TbJAfZc2Iuy8p44U44xD1F5+fNYFKI3897ijlbIyfvXkTmMm+KGcjkQQGMHywEQ==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/mutate-observer@2.0.1':
+ resolution: {integrity: sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/notification@1.2.0':
+ resolution: {integrity: sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/overflow@1.0.0':
+ resolution: {integrity: sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/pagination@1.2.0':
+ resolution: {integrity: sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/picker@1.9.1':
+ resolution: {integrity: sha512-9FBYYsvH3HMLICaPDA/1Th5FLaDkFa7qAtangIdlhKb3ZALaR745e9PsOhheJb6asS4QXc12ffiAcjdkZ4C5/g==}
+ engines: {node: '>=12.x'}
+ peerDependencies:
+ date-fns: '>= 2.x'
+ dayjs: '>= 1.x'
+ luxon: '>= 3.x'
+ moment: '>= 2.x'
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+ peerDependenciesMeta:
+ date-fns:
+ optional: true
+ dayjs:
+ optional: true
+ luxon:
+ optional: true
+ moment:
+ optional: true
+
+ '@rc-component/portal@2.2.0':
+ resolution: {integrity: sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ==}
+ engines: {node: '>=12.x'}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/progress@1.0.2':
+ resolution: {integrity: sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/qrcode@1.1.1':
+ resolution: {integrity: sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/rate@1.0.1':
+ resolution: {integrity: sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/resize-observer@1.1.2':
+ resolution: {integrity: sha512-t/Bb0W8uvL4PYKAB3YcChC+DlHh0Wt5kM7q/J+0qpVEUMLe7Hk5zuvc9km0hMnTFPSx5Z7Wu/fzCLN6erVLE8Q==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/segmented@1.3.0':
+ resolution: {integrity: sha512-5J/bJ01mbDnoA6P/FW8SxUvKn+OgUSTZJPzCNnTBntG50tzoP7DydGhqxp7ggZXZls7me3mc2EQDXakU3iTVFg==}
+ peerDependencies:
+ react: '>=16.0.0'
+ react-dom: '>=16.0.0'
+
+ '@rc-component/select@1.6.15':
+ resolution: {integrity: sha512-SyVCWnqxCQZZcQvQJ/CxSjx2bGma6ds/HtnpkIfZVnt6RoEgbqUmHgD6vrzNarNXwbLXerwVzWwq8F3d1sst7g==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '*'
+ react-dom: '*'
+
+ '@rc-component/slider@1.0.1':
+ resolution: {integrity: sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/steps@1.2.2':
+ resolution: {integrity: sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/switch@1.0.3':
+ resolution: {integrity: sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/table@1.9.1':
+ resolution: {integrity: sha512-FVI5ZS/GdB3BcgexfCYKi3iHhZS3Fr59EtsxORszYGrfpH1eWr33eDNSYkVfLI6tfJ7vftJDd9D5apfFWqkdJg==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/tabs@1.7.0':
+ resolution: {integrity: sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/textarea@1.1.2':
+ resolution: {integrity: sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/tooltip@1.4.0':
+ resolution: {integrity: sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/tour@2.3.0':
+ resolution: {integrity: sha512-K04K9r32kUC+auBSQfr+Fss4SpSIS9JGe56oq/ALAX0p+i2ylYOI1MgR83yBY7v96eO6ZFXcM/igCQmubps0Ow==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/tree-select@1.8.0':
+ resolution: {integrity: sha512-iYsPq3nuLYvGqdvFAW+l+I9ASRIOVbMXyA8FGZg2lGym/GwkaWeJGzI4eJ7c9IOEhRj0oyfIN4S92Fl3J05mjQ==}
+ peerDependencies:
+ react: '*'
+ react-dom: '*'
+
+ '@rc-component/tree@1.2.4':
+ resolution: {integrity: sha512-5Gli43+m4R7NhpYYz3Z61I6LOw9yI6CNChxgVtvrO6xB1qML7iE6QMLVMB3+FTjo2yF6uFdAHtqWPECz/zbX5w==}
+ engines: {node: '>=10.x'}
+ peerDependencies:
+ react: '*'
+ react-dom: '*'
+
+ '@rc-component/trigger@3.9.0':
+ resolution: {integrity: sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/upload@1.1.0':
+ resolution: {integrity: sha512-LIBV90mAnUE6VK5N4QvForoxZc4XqEYZimcp7fk+lkE4XwHHyJWxpIXQQwMU8hJM+YwBbsoZkGksL1sISWHQxw==}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rc-component/util@1.10.1':
+ resolution: {integrity: sha512-q++9S6rUa5Idb/xIBNz6jtvumw5+O5YV5V0g4iK9mn9jWs4oGJheE3ZN1kAnE723AXyaD8v95yeOASmdk8Jnng==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ '@rc-component/virtual-list@1.0.2':
+ resolution: {integrity: sha512-uvTol/mH74FYsn5loDGJxo+7kjkO4i+y4j87Re1pxJBs0FaeuMuLRzQRGaXwnMcV1CxpZLi2Z56Rerj2M00fjQ==}
+ engines: {node: '>=8.x'}
+ peerDependencies:
+ react: '>=16.9.0'
+ react-dom: '>=16.9.0'
+
+ '@rolldown/binding-android-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.0.0-rc.15':
+ resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.15':
+ resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
+ resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
+ resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
+ resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
+ resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
+ resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
+ resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
+ resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
+ resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
+ '@rolldown/pluginutils@1.0.0-rc.15':
+ resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==}
+
+ '@rolldown/pluginutils@1.0.0-rc.7':
+ resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
+
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+
+ '@tailwindcss/node@4.2.2':
+ resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==}
+
+ '@tailwindcss/oxide-android-arm64@4.2.2':
+ resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.2.2':
+ resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.2.2':
+ resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.2.2':
+ resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2':
+ resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==}
+ engines: {node: '>= 20'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.2.2':
+ resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.2.2':
+ resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.2.2':
+ resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.2.2':
+ resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.2.2':
+ resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.2.2':
+ resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==}
+ engines: {node: '>= 20'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.2.2':
+ resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==}
+ engines: {node: '>= 20'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.2.2':
+ resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==}
+ engines: {node: '>= 20'}
+
+ '@tailwindcss/vite@4.2.2':
+ resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==}
+ peerDependencies:
+ vite: ^5.2.0 || ^6 || ^7 || ^8
+
+ '@testing-library/dom@10.4.1':
+ resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
+ engines: {node: '>=18'}
+
+ '@testing-library/jest-dom@6.9.1':
+ resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==}
+ engines: {node: '>=14', npm: '>=6', yarn: '>=1'}
+
+ '@testing-library/react@16.3.2':
+ resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@testing-library/dom': ^10.0.0
+ '@types/react': ^18.0.0 || ^19.0.0
+ '@types/react-dom': ^18.0.0 || ^19.0.0
+ react: ^18.0.0 || ^19.0.0
+ react-dom: ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
+ '@transloadit/prettier-bytes@0.0.7':
+ resolution: {integrity: sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA==}
+
+ '@tybys/wasm-util@0.10.1':
+ resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
+ '@types/chai@5.2.3':
+ resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+
+ '@types/d3-array@3.2.2':
+ resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
+
+ '@types/d3-color@3.1.3':
+ resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
+
+ '@types/d3-dispatch@3.0.7':
+ resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==}
+
+ '@types/d3-drag@3.0.7':
+ resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==}
+
+ '@types/d3-dsv@3.0.7':
+ resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==}
+
+ '@types/d3-ease@3.0.2':
+ resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
+
+ '@types/d3-fetch@3.0.7':
+ resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==}
+
+ '@types/d3-force@3.0.10':
+ resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==}
+
+ '@types/d3-format@3.0.4':
+ resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==}
+
+ '@types/d3-geo@3.1.0':
+ resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==}
+
+ '@types/d3-hierarchy@3.1.7':
+ resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==}
+
+ '@types/d3-interpolate@3.0.4':
+ resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
+
+ '@types/d3-path@3.1.1':
+ resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
+
+ '@types/d3-quadtree@3.0.6':
+ resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==}
+
+ '@types/d3-random@3.0.3':
+ resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==}
+
+ '@types/d3-scale-chromatic@3.1.0':
+ resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==}
+
+ '@types/d3-scale@4.0.9':
+ resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
+
+ '@types/d3-selection@3.0.11':
+ resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==}
+
+ '@types/d3-shape@3.1.8':
+ resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==}
+
+ '@types/d3-time@3.0.4':
+ resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
+
+ '@types/d3-timer@3.0.2':
+ resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
+
+ '@types/d3-transition@3.0.9':
+ resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==}
+
+ '@types/d3-zoom@3.0.8':
+ resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==}
+
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
+ '@types/dompurify@3.2.0':
+ resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==}
+ deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/event-emitter@0.3.5':
+ resolution: {integrity: sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==}
+
+ '@types/geojson@7946.0.16':
+ resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
+
+ '@types/json-schema@7.0.15':
+ resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+ '@types/node@24.12.2':
+ resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==}
+
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
+ '@types/react@19.2.14':
+ resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
+
+ '@types/set-cookie-parser@2.4.10':
+ resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==}
+
+ '@types/statuses@2.0.6':
+ resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==}
+
+ '@types/trusted-types@2.0.7':
+ resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+
+ '@typescript-eslint/eslint-plugin@8.58.1':
+ resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ '@typescript-eslint/parser': ^8.58.1
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/parser@8.58.1':
+ resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/project-service@8.58.1':
+ resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/scope-manager@8.58.1':
+ resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/tsconfig-utils@8.58.1':
+ resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/type-utils@8.58.1':
+ resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/types@8.58.1':
+ resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@typescript-eslint/typescript-estree@8.58.1':
+ resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/utils@8.58.1':
+ resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
+ '@typescript-eslint/visitor-keys@8.58.1':
+ resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ '@uppy/companion-client@2.2.2':
+ resolution: {integrity: sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==}
+
+ '@uppy/core@2.3.4':
+ resolution: {integrity: sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==}
+
+ '@uppy/store-default@2.1.1':
+ resolution: {integrity: sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ==}
+
+ '@uppy/utils@4.1.3':
+ resolution: {integrity: sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==}
+
+ '@uppy/xhr-upload@2.1.3':
+ resolution: {integrity: sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==}
+ peerDependencies:
+ '@uppy/core': ^2.3.3
+
+ '@vitejs/plugin-react@6.0.1':
+ resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
+ babel-plugin-react-compiler: ^1.0.0
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@rolldown/plugin-babel':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+
+ '@vitest/coverage-v8@4.1.5':
+ resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==}
+ peerDependencies:
+ '@vitest/browser': 4.1.5
+ vitest: 4.1.5
+ peerDependenciesMeta:
+ '@vitest/browser':
+ optional: true
+
+ '@vitest/expect@4.1.5':
+ resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==}
+
+ '@vitest/mocker@4.1.5':
+ resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@4.1.5':
+ resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==}
+
+ '@vitest/runner@4.1.5':
+ resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==}
+
+ '@vitest/snapshot@4.1.5':
+ resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==}
+
+ '@vitest/spy@4.1.5':
+ resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==}
+
+ '@vitest/utils@4.1.5':
+ resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==}
+
+ '@wangeditor/basic-modules@1.1.7':
+ resolution: {integrity: sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==}
+ peerDependencies:
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ lodash.throttle: ^4.1.1
+ nanoid: ^3.2.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/code-highlight@1.0.3':
+ resolution: {integrity: sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==}
+ peerDependencies:
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/core@1.1.19':
+ resolution: {integrity: sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==}
+ peerDependencies:
+ '@uppy/core': ^2.1.1
+ '@uppy/xhr-upload': ^2.0.3
+ dom7: ^3.0.0
+ is-hotkey: ^0.2.0
+ lodash.camelcase: ^4.3.0
+ lodash.clonedeep: ^4.5.0
+ lodash.debounce: ^4.0.8
+ lodash.foreach: ^4.5.0
+ lodash.isequal: ^4.5.0
+ lodash.throttle: ^4.1.1
+ lodash.toarray: ^4.4.0
+ nanoid: ^3.2.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/editor-for-react@1.0.6':
+ resolution: {integrity: sha512-KJNSfgMr5Blzae3oyaiz20flMKHZHnvsz4bCYQKDCUs/qkvC+xNTnwedlCmhGP187oPWPEypCIYI8Zg6sz0psQ==}
+ peerDependencies:
+ '@wangeditor/core': '>=1.1.0'
+ '@wangeditor/editor': '>=5.1.0'
+ react: '>=17.0.2'
+ react-dom: '>=17.0.2'
+
+ '@wangeditor/editor@5.1.23':
+ resolution: {integrity: sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==}
+
+ '@wangeditor/list-module@1.0.5':
+ resolution: {integrity: sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ==}
+ peerDependencies:
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/table-module@1.1.4':
+ resolution: {integrity: sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w==}
+ peerDependencies:
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ lodash.isequal: ^4.5.0
+ lodash.throttle: ^4.1.1
+ nanoid: ^3.2.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/upload-image-module@1.0.2':
+ resolution: {integrity: sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA==}
+ peerDependencies:
+ '@uppy/core': ^2.0.3
+ '@uppy/xhr-upload': ^2.0.3
+ '@wangeditor/basic-modules': 1.x
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ lodash.foreach: ^4.5.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@wangeditor/video-module@1.1.4':
+ resolution: {integrity: sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg==}
+ peerDependencies:
+ '@uppy/core': ^2.1.4
+ '@uppy/xhr-upload': ^2.0.7
+ '@wangeditor/core': 1.x
+ dom7: ^3.0.0
+ nanoid: ^3.2.0
+ slate: ^0.72.0
+ snabbdom: ^3.1.0
+
+ '@xyflow/react@12.10.2':
+ resolution: {integrity: sha512-CgIi6HwlcHXwlkTpr0fxLv/0sRVNZ8IdwKLzzeCscaYBwpvfcH1QFOCeaTCuEn1FQEs/B8CjnTSjhs8udgmBgQ==}
+ peerDependencies:
+ react: '>=17'
+ react-dom: '>=17'
+
+ '@xyflow/system@0.0.76':
+ resolution: {integrity: sha512-hvwvnRS1B3REwVDlWexsq7YQaPZeG3/mKo1jv38UmnpWmxihp14bW6VtEOuHEwJX2FvzFw8k77LyKSk/wiZVNA==}
+
+ acorn-jsx@5.3.2:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
+ ajv@6.14.0:
+ resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
+
+ ansi-regex@5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
+ antd@6.3.5:
+ resolution: {integrity: sha512-8BPz9lpZWQm42PTx7yL4KxWAotVuqINiKcoYRcLtdd5BFmAcAZicVyFTnBJyRDlzGZFZeRW3foGu6jXYFnej6Q==}
+ peerDependencies:
+ react: '>=18.0.0'
+ react-dom: '>=18.0.0'
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
+ aria-query@5.3.2:
+ resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
+ engines: {node: '>= 0.4'}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ ast-v8-to-istanbul@1.0.0:
+ resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ axios@1.15.0:
+ resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
+
+ balanced-match@1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+ balanced-match@4.0.4:
+ resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
+ engines: {node: 18 || 20 || >=22}
+
+ base64-arraybuffer@1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+
+ baseline-browser-mapping@2.10.17:
+ resolution: {integrity: sha512-HdrkN8eVG2CXxeifv/VdJ4A4RSra1DTW8dc/hdxzhGHN8QePs6gKaWM9pHPcpCoxYZJuOZ8drHmbdpLHjCYjLA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ bidi-js@1.0.3:
+ resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
+
+ brace-expansion@1.1.13:
+ resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
+
+ brace-expansion@5.0.5:
+ resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==}
+ engines: {node: 18 || 20 || >=22}
+
+ browserslist@4.28.2:
+ resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ bubblesets-js@2.3.4:
+ resolution: {integrity: sha512-DyMjHmpkS2+xcFNtyN00apJYL3ESdp9fTrkDr5+9Qg/GPqFmcWgGsK1akZnttE1XFxJ/VMy4DNNGMGYtmFp1Sg==}
+
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001787:
+ resolution: {integrity: sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==}
+
+ chai@6.2.2:
+ resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
+ engines: {node: '>=18'}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ classcat@5.0.5:
+ resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==}
+
+ cli-width@4.1.0:
+ resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
+ engines: {node: '>= 12'}
+
+ cliui@8.0.1:
+ resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
+ engines: {node: '>=12'}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ comlink@4.4.2:
+ resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==}
+
+ commander@7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+
+ compute-scroll-into-view@1.0.20:
+ resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==}
+
+ compute-scroll-into-view@3.1.1:
+ resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
+
+ concat-map@0.0.1:
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cookie@1.1.1:
+ resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
+ engines: {node: '>=18'}
+
+ cross-spawn@7.0.6:
+ resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+ engines: {node: '>= 8'}
+
+ css-line-break@2.1.0:
+ resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
+ css.escape@1.5.1:
+ resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
+
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ d3-array@3.2.4:
+ resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
+ engines: {node: '>=12'}
+
+ d3-binarytree@1.0.2:
+ resolution: {integrity: sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==}
+
+ d3-color@3.1.0:
+ resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
+ engines: {node: '>=12'}
+
+ d3-dispatch@3.0.1:
+ resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
+ engines: {node: '>=12'}
+
+ d3-drag@3.0.0:
+ resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
+ engines: {node: '>=12'}
+
+ d3-dsv@3.0.1:
+ resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ d3-ease@3.0.1:
+ resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
+ engines: {node: '>=12'}
+
+ d3-fetch@3.0.1:
+ resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
+ engines: {node: '>=12'}
+
+ d3-force-3d@3.0.6:
+ resolution: {integrity: sha512-4tsKHUPLOVkyfEffZo1v6sFHvGFwAIIjt/W8IThbp08DYAsXZck+2pSHEG5W1+gQgEvFLdZkYvmJAbRM2EzMnA==}
+ engines: {node: '>=12'}
+
+ d3-force@3.0.0:
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
+ engines: {node: '>=12'}
+
+ d3-format@3.1.2:
+ resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
+ engines: {node: '>=12'}
+
+ d3-geo-projection@4.0.0:
+ resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ d3-geo@3.1.1:
+ resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==}
+ engines: {node: '>=12'}
+
+ d3-hierarchy@3.1.2:
+ resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==}
+ engines: {node: '>=12'}
+
+ d3-interpolate@3.0.1:
+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
+ engines: {node: '>=12'}
+
+ d3-octree@1.1.0:
+ resolution: {integrity: sha512-F8gPlqpP+HwRPMO/8uOu5wjH110+6q4cgJvgJT6vlpy3BEaDIKlTZrgHKZSp/i1InRpVfh4puY/kvL6MxK930A==}
+
+ d3-path@3.1.0:
+ resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
+ engines: {node: '>=12'}
+
+ d3-quadtree@3.0.1:
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
+ engines: {node: '>=12'}
+
+ d3-random@3.0.1:
+ resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
+ engines: {node: '>=12'}
+
+ d3-regression@1.3.10:
+ resolution: {integrity: sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==}
+
+ d3-scale-chromatic@3.1.0:
+ resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==}
+ engines: {node: '>=12'}
+
+ d3-scale@4.0.2:
+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
+ engines: {node: '>=12'}
+
+ d3-selection@3.0.0:
+ resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
+ engines: {node: '>=12'}
+
+ d3-shape@3.2.0:
+ resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
+ engines: {node: '>=12'}
+
+ d3-time-format@4.1.0:
+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
+ engines: {node: '>=12'}
+
+ d3-time@3.1.0:
+ resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
+ engines: {node: '>=12'}
+
+ d3-timer@3.0.1:
+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
+ engines: {node: '>=12'}
+
+ d3-transition@3.0.1:
+ resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ d3-selection: 2 - 3
+
+ d3-zoom@3.0.0:
+ resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
+ engines: {node: '>=12'}
+
+ d@1.0.2:
+ resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
+ engines: {node: '>=0.12'}
+
+ dagre@0.8.5:
+ resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==}
+
+ data-urls@7.0.0:
+ resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ dayjs@1.11.20:
+ resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
+ deep-is@0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
+ dom-accessibility-api@0.6.3:
+ resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+
+ dom7@3.0.0:
+ resolution: {integrity: sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==}
+
+ dompurify@3.4.5:
+ resolution: {integrity: sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==}
+
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
+ electron-to-chromium@1.5.334:
+ resolution: {integrity: sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog==}
+
+ emoji-regex@8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+ enhanced-resolve@5.20.1:
+ resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
+ engines: {node: '>=10.13.0'}
+
+ entities@8.0.0:
+ resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
+ engines: {node: '>=20.19.0'}
+
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-module-lexer@2.0.0:
+ resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
+
+ es-object-atoms@1.1.1:
+ resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+ engines: {node: '>= 0.4'}
+
+ es-set-tostringtag@2.1.0:
+ resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+ engines: {node: '>= 0.4'}
+
+ es5-ext@0.10.64:
+ resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
+ engines: {node: '>=0.10'}
+
+ es6-iterator@2.0.3:
+ resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
+
+ es6-symbol@3.1.4:
+ resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
+ engines: {node: '>=0.12'}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ eslint-plugin-react-hooks@7.0.1:
+ resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+
+ eslint-plugin-react-refresh@0.5.2:
+ resolution: {integrity: sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==}
+ peerDependencies:
+ eslint: ^9 || ^10
+
+ eslint-scope@8.4.0:
+ resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@3.4.3:
+ resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+ eslint-visitor-keys@4.2.1:
+ resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ eslint-visitor-keys@5.0.1:
+ resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24}
+
+ eslint@9.39.4:
+ resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ hasBin: true
+ peerDependencies:
+ jiti: '*'
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+
+ esniff@2.0.1:
+ resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
+ engines: {node: '>=0.10'}
+
+ espree@10.4.0:
+ resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+ esquery@1.7.0:
+ resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
+ engines: {node: '>=0.10'}
+
+ esrecurse@4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+
+ estraverse@5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+ esutils@2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+
+ event-emitter@0.3.5:
+ resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
+
+ eventemitter3@5.0.4:
+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
+
+ expect-type@1.3.0:
+ resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
+ engines: {node: '>=12.0.0'}
+
+ ext@1.7.0:
+ resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+
+ fast-deep-equal@3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ fast-json-stable-stringify@2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+ fast-levenshtein@2.0.6:
+ resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+ fast-string-truncated-width@3.0.3:
+ resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==}
+
+ fast-string-width@3.0.2:
+ resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==}
+
+ fast-wrap-ansi@0.2.0:
+ resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==}
+
+ fdir@6.5.0:
+ resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
+ engines: {node: '>=12.0.0'}
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+
+ fecha@4.2.3:
+ resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
+
+ file-entry-cache@8.0.0:
+ resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+ engines: {node: '>=16.0.0'}
+
+ find-up@5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+
+ flat-cache@4.0.1:
+ resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+ engines: {node: '>=16'}
+
+ flatted@3.4.2:
+ resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
+
+ flru@1.0.2:
+ resolution: {integrity: sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==}
+ engines: {node: '>=6'}
+
+ follow-redirects@1.15.11:
+ resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ form-data@4.0.5:
+ resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
+ engines: {node: '>= 6'}
+
+ fsevents@2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ get-caller-file@2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
+ gl-matrix@3.4.4:
+ resolution: {integrity: sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==}
+
+ glob-parent@6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+
+ globals@14.0.0:
+ resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+ engines: {node: '>=18'}
+
+ globals@17.4.0:
+ resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==}
+ engines: {node: '>=18'}
+
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ graphlib@2.1.8:
+ resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==}
+
+ graphql@16.13.2:
+ resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==}
+ engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ headers-polyfill@5.0.1:
+ resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==}
+
+ hermes-estree@0.25.1:
+ resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==}
+
+ hermes-parser@0.25.1:
+ resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
+
+ html-encoding-sniffer@6.0.0:
+ resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ html-escaper@2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+ html-void-elements@2.0.1:
+ resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==}
+
+ html2canvas@1.4.1:
+ resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+ engines: {node: '>=8.0.0'}
+
+ i18next@20.6.1:
+ resolution: {integrity: sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==}
+
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
+ ignore@5.3.2:
+ resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+ engines: {node: '>= 4'}
+
+ ignore@7.0.5:
+ resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
+ engines: {node: '>= 4'}
+
+ immer@9.0.21:
+ resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ imurmurhash@0.1.4:
+ resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+ engines: {node: '>=0.8.19'}
+
+ indent-string@4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+
+ internmap@2.0.3:
+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
+ engines: {node: '>=12'}
+
+ is-any-array@3.0.0:
+ resolution: {integrity: sha512-o4h+tylWykC4BD1vaejp6gDxoM13bwW8FGuNs4yIKpj8xbBJcRxJx8vZpq0dCr7ZDEfeKjmsi/euolKhX6f/ww==}
+
+ is-arrayish@0.3.4:
+ resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-fullwidth-code-point@3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-hotkey@0.2.0:
+ resolution: {integrity: sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==}
+
+ is-mobile@5.0.0:
+ resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==}
+
+ is-node-process@1.2.0:
+ resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==}
+
+ is-plain-object@5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
+ is-url@1.2.4:
+ resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ istanbul-lib-coverage@3.2.2:
+ resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
+ engines: {node: '>=8'}
+
+ istanbul-lib-report@3.0.1:
+ resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
+ engines: {node: '>=10'}
+
+ istanbul-reports@3.2.0:
+ resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
+ engines: {node: '>=8'}
+
+ jiti@2.6.1:
+ resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ hasBin: true
+
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.1:
+ resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
+ hasBin: true
+
+ jsdom@29.0.2:
+ resolution: {integrity: sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==}
+ engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+ json-schema-traverse@0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+ json-stable-stringify-without-jsonify@1.0.1:
+ resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+ json2mq@0.2.0:
+ resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+ levn@0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+
+ lightningcss-android-arm64@1.32.0:
+ resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.32.0:
+ resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.32.0:
+ resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.32.0:
+ resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ lightningcss-linux-x64-musl@1.32.0:
+ resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.32.0:
+ resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
+ engines: {node: '>= 12.0.0'}
+
+ locate-path@6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+
+ lodash.camelcase@4.3.0:
+ resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
+
+ lodash.clonedeep@4.5.0:
+ resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
+
+ lodash.debounce@4.0.8:
+ resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
+
+ lodash.foreach@4.5.0:
+ resolution: {integrity: sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==}
+
+ lodash.isequal@4.5.0:
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
+
+ lodash.merge@4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+ lodash.throttle@4.1.1:
+ resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
+
+ lodash.toarray@4.4.0:
+ resolution: {integrity: sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw==}
+
+ lodash@4.18.1:
+ resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
+
+ lru-cache@11.3.5:
+ resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==}
+ engines: {node: 20 || >=22}
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ lz-string@1.5.0:
+ resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
+ hasBin: true
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ magicast@0.5.2:
+ resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
+
+ make-dir@4.0.0:
+ resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
+ engines: {node: '>=10'}
+
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-match@1.0.2:
+ resolution: {integrity: sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+
+ minimatch@10.2.5:
+ resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
+ engines: {node: 18 || 20 || >=22}
+
+ minimatch@3.1.5:
+ resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
+
+ ml-array-max@2.0.0:
+ resolution: {integrity: sha512-QQZ4kENwpWmyNb98UXRDFXrmtIXuXtt1+bSbda/2KA85+F+rrJP8hZk6QOkCQXM2Th9mUDYdq/PNByPdT9ID4A==}
+
+ ml-array-min@2.0.0:
+ resolution: {integrity: sha512-GRj6Ky6sW9vGL6yIjgsHmXZ9YgrdmcQ8nCxPqEGeKc6dkfYg1XDYxGFxADUjNuZyoCd5PUscWAS4N+cFaX6hFg==}
+
+ ml-array-rescale@2.0.0:
+ resolution: {integrity: sha512-2GGtKfSno94/kIloWGvpp/U5Q5vLvLrza+SAaGsLeo6Xj4mEbA6Gqx+oTfZFkxnd1grT2X007HfJNs3T5BsiVg==}
+
+ ml-matrix@6.12.2:
+ resolution: {integrity: sha512-GC+BnW+pBh8Auap8goAxY0senAmF0IEoc3HNVSfnfbvGw0buuDIYb9kAKMS1l+GiwJ1rfK2bzJ8IHhwjzATSFA==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ msw@2.13.6:
+ resolution: {integrity: sha512-GAJbQy8Ra/Ydjt0Hb2MGT2qhzd83J3+QZMHdH85uW7r/XkKc846+Ma2PLif5hGvTm5Yqa+wkcstpim0WeLZU9g==}
+ engines: {node: '>=18'}
+ hasBin: true
+ peerDependencies:
+ typescript: '>= 4.8.x'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ mute-stream@3.0.0:
+ resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==}
+ engines: {node: ^20.17.0 || >=22.9.0}
+
+ namespace-emitter@2.0.1:
+ resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ natural-compare@1.4.0:
+ resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+ next-tick@1.1.0:
+ resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
+
+ node-releases@2.0.37:
+ resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==}
+
+ obug@2.1.1:
+ resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
+
+ optionator@0.9.4:
+ resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+ engines: {node: '>= 0.8.0'}
+
+ outvariant@1.4.3:
+ resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==}
+
+ p-limit@3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+
+ p-locate@5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse5@8.0.1:
+ resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==}
+
+ path-exists@4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-to-regexp@6.3.0:
+ resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==}
+
+ pathe@2.0.3:
+ resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+ pdfast@0.2.0:
+ resolution: {integrity: sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@4.0.4:
+ resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ engines: {node: '>=12'}
+
+ playwright-core@1.59.1:
+ resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright@1.59.1:
+ resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ postcss@8.5.9:
+ resolution: {integrity: sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ preact@10.29.1:
+ resolution: {integrity: sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==}
+
+ prelude-ls@1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
+ prismjs@1.30.0:
+ resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
+ engines: {node: '>=6'}
+
+ proxy-from-env@2.1.0:
+ resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
+ engines: {node: '>=10'}
+
+ punycode@2.3.1:
+ resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+ engines: {node: '>=6'}
+
+ react-dom@19.2.5:
+ resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==}
+ peerDependencies:
+ react: ^19.2.5
+
+ react-is@17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
+ react-is@18.3.1:
+ resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+
+ react-router-dom@7.14.0:
+ resolution: {integrity: sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+
+ react-router@7.14.0:
+ resolution: {integrity: sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==}
+ engines: {node: '>=20.0.0'}
+ peerDependencies:
+ react: '>=18'
+ react-dom: '>=18'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+
+ react@19.2.5:
+ resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==}
+ engines: {node: '>=0.10.0'}
+
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
+ require-directory@2.1.1:
+ resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
+ engines: {node: '>=0.10.0'}
+
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ rettime@0.11.8:
+ resolution: {integrity: sha512-0fERGXktJTyJ+h8fBEiPxHPEFOu0h15JY7JtwrOVqR5K+vb99ho6IyOo7ekLS3h4sJCzIDy4VWKIbZUfe9njmg==}
+
+ rolldown@1.0.0-rc.15:
+ resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
+ rw@1.3.3:
+ resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ scroll-into-view-if-needed@2.2.31:
+ resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==}
+
+ scroll-into-view-if-needed@3.1.0:
+ resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ semver@7.7.4:
+ resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ set-cookie-parser@2.7.2:
+ resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
+
+ set-cookie-parser@3.1.0:
+ resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ simple-swizzle@0.2.4:
+ resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
+
+ slate-history@0.66.0:
+ resolution: {integrity: sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==}
+ peerDependencies:
+ slate: '>=0.65.3'
+
+ slate@0.72.8:
+ resolution: {integrity: sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==}
+
+ snabbdom@3.6.3:
+ resolution: {integrity: sha512-W2lHLLw2qR2Vv0DcMmcxXqcfdBaIcoN+y/86SmHv8fn4DazEQSH6KN3TjZcWvwujW56OHiiirsbHWZb4vx/0fg==}
+ engines: {node: '>=12.17.0'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ ssr-window@3.0.0:
+ resolution: {integrity: sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==}
+
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ statuses@2.0.2:
+ resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
+ engines: {node: '>= 0.8'}
+
+ std-env@4.1.0:
+ resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==}
+
+ strict-event-emitter@0.5.1:
+ resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
+
+ string-convert@0.2.1:
+ resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
+
+ string-width@4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+
+ strip-ansi@6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
+ strip-json-comments@3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+
+ styled-components@6.4.0:
+ resolution: {integrity: sha512-BL1EDFpt+q10eAeZB0q9ps6pSlPejaBQWBkiuM16pyoVTG4NhZrPrZK0cqNbrozxSsYwUsJ9SQYN6NyeKJYX9A==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ css-to-react-native: '>= 3.2.0'
+ react: '>= 16.8.0'
+ react-dom: '>= 16.8.0'
+ react-native: '>= 0.68.0'
+ peerDependenciesMeta:
+ css-to-react-native:
+ optional: true
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+
+ stylis@4.3.6:
+ resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ svg-path-parser@1.1.0:
+ resolution: {integrity: sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==}
+
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
+ tagged-tag@1.0.0:
+ resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==}
+ engines: {node: '>=20'}
+
+ tailwindcss@4.2.2:
+ resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==}
+
+ tapable@2.3.2:
+ resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==}
+ engines: {node: '>=6'}
+
+ text-segmentation@1.0.3:
+ resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+
+ throttle-debounce@5.0.2:
+ resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==}
+ engines: {node: '>=12.22'}
+
+ tiny-warning@1.0.3:
+ resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@1.1.1:
+ resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==}
+ engines: {node: '>=18'}
+
+ tinyglobby@0.2.16:
+ resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
+ engines: {node: '>=12.0.0'}
+
+ tinyrainbow@3.1.0:
+ resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
+ engines: {node: '>=14.0.0'}
+
+ tldts-core@7.0.28:
+ resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==}
+
+ tldts@7.0.28:
+ resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==}
+ hasBin: true
+
+ tough-cookie@6.0.1:
+ resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
+ engines: {node: '>=16'}
+
+ tr46@6.0.0:
+ resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==}
+ engines: {node: '>=20'}
+
+ ts-api-utils@2.5.0:
+ resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==}
+ engines: {node: '>=18.12'}
+ peerDependencies:
+ typescript: '>=4.8.4'
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-check@0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+
+ type-fest@5.6.0:
+ resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==}
+ engines: {node: '>=20'}
+
+ type@2.7.3:
+ resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
+
+ typescript-eslint@8.58.1:
+ resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: '>=4.8.4 <6.1.0'
+
+ typescript@6.0.2:
+ resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
+ undici@7.25.0:
+ resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==}
+ engines: {node: '>=20.18.1'}
+
+ until-async@3.0.2:
+ resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==}
+
+ update-browserslist-db@1.2.3:
+ resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ uri-js@4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+ use-sync-external-store@1.6.0:
+ resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
+ utrie@1.0.2:
+ resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+
+ vite@8.0.8:
+ resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ '@vitejs/devtools': ^0.1.0
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ vitest@4.1.5:
+ resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==}
+ engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@opentelemetry/api': ^1.9.0
+ '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0
+ '@vitest/browser-playwright': 4.1.5
+ '@vitest/browser-preview': 4.1.5
+ '@vitest/browser-webdriverio': 4.1.5
+ '@vitest/coverage-istanbul': 4.1.5
+ '@vitest/coverage-v8': 4.1.5
+ '@vitest/ui': 4.1.5
+ happy-dom: '*'
+ jsdom: '*'
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@opentelemetry/api':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser-playwright':
+ optional: true
+ '@vitest/browser-preview':
+ optional: true
+ '@vitest/browser-webdriverio':
+ optional: true
+ '@vitest/coverage-istanbul':
+ optional: true
+ '@vitest/coverage-v8':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
+ webidl-conversions@8.0.1:
+ resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
+ engines: {node: '>=20'}
+
+ whatwg-mimetype@5.0.0:
+ resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
+ engines: {node: '>=20'}
+
+ whatwg-url@16.0.1:
+ resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==}
+ engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
+ wildcard@1.1.2:
+ resolution: {integrity: sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==}
+
+ word-wrap@1.2.5:
+ resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+ engines: {node: '>=0.10.0'}
+
+ wrap-ansi@7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
+ y18n@5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yargs-parser@21.1.1:
+ resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
+ engines: {node: '>=12'}
+
+ yargs@17.7.2:
+ resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+ engines: {node: '>=12'}
+
+ yocto-queue@0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+
+ zod-validation-error@4.0.2:
+ resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ zod: ^3.25.0 || ^4.0.0
+
+ zod@4.3.6:
+ resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
+
+ zustand@4.5.7:
+ resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==}
+ engines: {node: '>=12.7.0'}
+ peerDependencies:
+ '@types/react': '>=16.8'
+ immer: '>=9.0.6'
+ react: '>=16.8'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+
+ zustand@5.0.12:
+ resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=18.0.0'
+ immer: '>=9.0.6'
+ react: '>=18.0.0'
+ use-sync-external-store: '>=1.2.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+
+snapshots:
+
+ '@adobe/css-tools@4.4.4': {}
+
+ '@ant-design/charts-util@0.0.1-alpha.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ lodash: 4.18.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@ant-design/charts-util@0.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ lodash: 4.18.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@ant-design/charts@2.6.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/graphs': 2.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@ant-design/plots': 2.6.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ lodash: 4.18.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ transitivePeerDependencies:
+ - css-to-react-native
+ - react-native
+
+ '@ant-design/colors@8.0.1':
+ dependencies:
+ '@ant-design/fast-color': 3.0.1
+
+ '@ant-design/cssinjs-utils@2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/cssinjs': 2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@babel/runtime': 7.29.2
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@ant-design/cssinjs@2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@emotion/hash': 0.8.0
+ '@emotion/unitless': 0.7.5
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ csstype: 3.2.3
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ stylis: 4.3.6
+
+ '@ant-design/fast-color@3.0.1': {}
+
+ '@ant-design/graphs@2.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/charts-util': 0.0.1-alpha.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@antv/g6': 5.1.0
+ '@antv/g6-extension-react': 0.2.7(@antv/g6@5.1.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@antv/graphin': 3.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ lodash: 4.18.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ styled-components: 6.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ transitivePeerDependencies:
+ - css-to-react-native
+ - react-native
+
+ '@ant-design/icons-svg@4.4.2': {}
+
+ '@ant-design/icons@6.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/colors': 8.0.1
+ '@ant-design/icons-svg': 4.4.2
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@ant-design/plots@2.6.8(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/charts-util': 0.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@antv/event-emitter': 0.1.3
+ '@antv/g': 6.3.1
+ '@antv/g2': 5.4.8
+ '@antv/g2-extension-plot': 0.2.2
+ lodash: 4.18.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@ant-design/react-slick@2.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ clsx: 2.1.1
+ json2mq: 0.2.0
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ throttle-debounce: 5.0.2
+
+ '@antv/algorithm@0.1.26':
+ dependencies:
+ '@antv/util': 2.0.17
+ tslib: 2.8.1
+
+ '@antv/component@2.1.11':
+ dependencies:
+ '@antv/g': 6.3.1
+ '@antv/scale': 0.4.16
+ '@antv/util': 3.3.11
+ svg-path-parser: 1.1.0
+
+ '@antv/coord@0.4.7':
+ dependencies:
+ '@antv/scale': 0.4.16
+ '@antv/util': 2.0.17
+ gl-matrix: 3.4.4
+
+ '@antv/event-emitter@0.1.3': {}
+
+ '@antv/expr@1.0.2': {}
+
+ '@antv/g-canvas@2.2.0':
+ dependencies:
+ '@antv/g-lite': 2.7.0
+ '@antv/g-math': 3.1.0
+ '@antv/util': 3.3.11
+ '@babel/runtime': 7.29.2
+ gl-matrix: 3.4.4
+ tslib: 2.8.1
+
+ '@antv/g-lite@2.7.0':
+ dependencies:
+ '@antv/g-math': 3.1.0
+ '@antv/util': 3.3.11
+ '@antv/vendor': 1.0.11
+ '@babel/runtime': 7.29.2
+ eventemitter3: 5.0.4
+ gl-matrix: 3.4.4
+ tslib: 2.8.1
+
+ '@antv/g-math@3.1.0':
+ dependencies:
+ '@antv/util': 3.3.11
+ '@babel/runtime': 7.29.2
+ gl-matrix: 3.4.4
+ tslib: 2.8.1
+
+ '@antv/g-plugin-dragndrop@2.1.1':
+ dependencies:
+ '@antv/g-lite': 2.7.0
+ '@antv/util': 3.3.11
+ '@babel/runtime': 7.29.2
+ tslib: 2.8.1
+
+ '@antv/g-svg@2.1.1':
+ dependencies:
+ '@antv/g-lite': 2.7.0
+ '@antv/util': 3.3.11
+ '@babel/runtime': 7.29.2
+ gl-matrix: 3.4.4
+ tslib: 2.8.1
+
+ '@antv/g2-extension-plot@0.2.2':
+ dependencies:
+ '@antv/g2': 5.4.8
+ '@antv/util': 3.3.11
+ '@antv/vendor': 1.0.11
+
+ '@antv/g2@5.4.8':
+ dependencies:
+ '@antv/component': 2.1.11
+ '@antv/coord': 0.4.7
+ '@antv/event-emitter': 0.1.3
+ '@antv/expr': 1.0.2
+ '@antv/g': 6.3.1
+ '@antv/g-canvas': 2.2.0
+ '@antv/g-plugin-dragndrop': 2.1.1
+ '@antv/scale': 0.5.2
+ '@antv/util': 3.3.11
+ '@antv/vendor': 1.0.11
+ flru: 1.0.2
+ pdfast: 0.2.0
+
+ '@antv/g6-extension-react@0.2.7(@antv/g6@5.1.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@antv/g': 6.3.1
+ '@antv/g-svg': 2.1.1
+ '@antv/g6': 5.1.0
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@antv/g6@5.1.0':
+ dependencies:
+ '@antv/algorithm': 0.1.26
+ '@antv/component': 2.1.11
+ '@antv/event-emitter': 0.1.3
+ '@antv/g': 6.3.1
+ '@antv/g-canvas': 2.2.0
+ '@antv/g-plugin-dragndrop': 2.1.1
+ '@antv/graphlib': 2.0.4
+ '@antv/hierarchy': 0.7.1
+ '@antv/layout': 2.0.0
+ '@antv/util': 3.3.11
+ bubblesets-js: 2.3.4
+
+ '@antv/g@6.3.1':
+ dependencies:
+ '@antv/g-lite': 2.7.0
+ '@antv/util': 3.3.11
+ '@babel/runtime': 7.29.2
+ gl-matrix: 3.4.4
+ html2canvas: 1.4.1
+
+ '@antv/graphin@3.0.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@antv/g6': 5.1.0
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@antv/graphlib@2.0.4':
+ dependencies:
+ '@antv/event-emitter': 0.1.3
+
+ '@antv/hierarchy@0.7.1': {}
+
+ '@antv/layout@2.0.0':
+ dependencies:
+ '@antv/event-emitter': 0.1.3
+ '@antv/expr': 1.0.2
+ '@antv/graphlib': 2.0.4
+ '@antv/util': 3.3.11
+ comlink: 4.4.2
+ d3-force: 3.0.0
+ d3-force-3d: 3.0.6
+ d3-octree: 1.1.0
+ d3-quadtree: 3.0.1
+ dagre: 0.8.5
+ ml-matrix: 6.12.2
+ tslib: 2.8.1
+
+ '@antv/scale@0.4.16':
+ dependencies:
+ '@antv/util': 3.3.11
+ color-string: 1.9.1
+ fecha: 4.2.3
+
+ '@antv/scale@0.5.2':
+ dependencies:
+ '@antv/util': 3.3.11
+ color-string: 1.9.1
+ fecha: 4.2.3
+
+ '@antv/util@2.0.17':
+ dependencies:
+ csstype: 3.2.3
+ tslib: 2.8.1
+
+ '@antv/util@3.3.11':
+ dependencies:
+ fast-deep-equal: 3.1.3
+ gl-matrix: 3.4.4
+ tslib: 2.8.1
+
+ '@antv/vendor@1.0.11':
+ dependencies:
+ '@types/d3-array': 3.2.2
+ '@types/d3-color': 3.1.3
+ '@types/d3-dispatch': 3.0.7
+ '@types/d3-dsv': 3.0.7
+ '@types/d3-ease': 3.0.2
+ '@types/d3-fetch': 3.0.7
+ '@types/d3-force': 3.0.10
+ '@types/d3-format': 3.0.4
+ '@types/d3-geo': 3.1.0
+ '@types/d3-hierarchy': 3.1.7
+ '@types/d3-interpolate': 3.0.4
+ '@types/d3-path': 3.1.1
+ '@types/d3-quadtree': 3.0.6
+ '@types/d3-random': 3.0.3
+ '@types/d3-scale': 4.0.9
+ '@types/d3-scale-chromatic': 3.1.0
+ '@types/d3-shape': 3.1.8
+ '@types/d3-time': 3.0.4
+ '@types/d3-timer': 3.0.2
+ d3-array: 3.2.4
+ d3-color: 3.1.0
+ d3-dispatch: 3.0.1
+ d3-dsv: 3.0.1
+ d3-ease: 3.0.1
+ d3-fetch: 3.0.1
+ d3-force: 3.0.0
+ d3-force-3d: 3.0.6
+ d3-format: 3.1.2
+ d3-geo: 3.1.1
+ d3-geo-projection: 4.0.0
+ d3-hierarchy: 3.1.2
+ d3-interpolate: 3.0.1
+ d3-path: 3.1.0
+ d3-quadtree: 3.0.1
+ d3-random: 3.0.1
+ d3-regression: 1.3.10
+ d3-scale: 4.0.2
+ d3-scale-chromatic: 3.1.0
+ d3-shape: 3.2.0
+ d3-time: 3.1.0
+ d3-timer: 3.0.1
+
+ '@asamuzakjp/css-color@5.1.11':
+ dependencies:
+ '@asamuzakjp/generational-cache': 1.0.1
+ '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@asamuzakjp/dom-selector@7.1.1':
+ dependencies:
+ '@asamuzakjp/generational-cache': 1.0.1
+ '@asamuzakjp/nwsapi': 2.3.9
+ bidi-js: 1.0.3
+ css-tree: 3.2.1
+ is-potential-custom-element-name: 1.0.1
+
+ '@asamuzakjp/generational-cache@1.0.1': {}
+
+ '@asamuzakjp/nwsapi@2.3.9': {}
+
+ '@babel/code-frame@7.29.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.29.0': {}
+
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.29.2
+ '@babel/parser': 7.29.2
+ '@babel/template': 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.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.2
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.28.5': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.29.2':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
+ '@babel/parser@7.29.2':
+ dependencies:
+ '@babel/types': 7.29.0
+
+ '@babel/runtime@7.29.2': {}
+
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.2
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
+ '@bcoe/v8-coverage@1.0.2': {}
+
+ '@bramus/specificity@2.4.2':
+ dependencies:
+ css-tree: 3.2.1
+
+ '@csstools/color-helpers@6.0.2': {}
+
+ '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/color-helpers': 6.0.2
+ '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)':
+ dependencies:
+ '@csstools/css-tokenizer': 4.0.0
+
+ '@csstools/css-syntax-patches-for-csstree@1.1.3(css-tree@3.2.1)':
+ optionalDependencies:
+ css-tree: 3.2.1
+
+ '@csstools/css-tokenizer@4.0.0': {}
+
+ '@dnd-kit/accessibility@3.1.1(react@19.2.5)':
+ dependencies:
+ react: 19.2.5
+ tslib: 2.8.1
+
+ '@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@dnd-kit/accessibility': 3.1.1(react@19.2.5)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.5)
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ tslib: 2.8.1
+
+ '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@dnd-kit/core': 6.3.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@dnd-kit/utilities': 3.2.2(react@19.2.5)
+ react: 19.2.5
+ tslib: 2.8.1
+
+ '@dnd-kit/utilities@3.2.2(react@19.2.5)':
+ dependencies:
+ react: 19.2.5
+ tslib: 2.8.1
+
+ '@emnapi/core@1.9.2':
+ dependencies:
+ '@emnapi/wasi-threads': 1.2.1
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.9.2':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.2.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emotion/hash@0.8.0': {}
+
+ '@emotion/is-prop-valid@1.4.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
+ '@emotion/unitless@0.7.5': {}
+
+ '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))':
+ dependencies:
+ eslint: 9.39.4(jiti@2.6.1)
+ eslint-visitor-keys: 3.4.3
+
+ '@eslint-community/regexpp@4.12.2': {}
+
+ '@eslint/config-array@0.21.2':
+ dependencies:
+ '@eslint/object-schema': 2.1.7
+ debug: 4.4.3
+ minimatch: 3.1.5
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/config-helpers@0.4.2':
+ dependencies:
+ '@eslint/core': 0.17.0
+
+ '@eslint/core@0.17.0':
+ dependencies:
+ '@types/json-schema': 7.0.15
+
+ '@eslint/eslintrc@3.3.5':
+ dependencies:
+ ajv: 6.14.0
+ debug: 4.4.3
+ espree: 10.4.0
+ globals: 14.0.0
+ ignore: 5.3.2
+ import-fresh: 3.3.1
+ js-yaml: 4.1.1
+ minimatch: 3.1.5
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@eslint/js@9.39.4': {}
+
+ '@eslint/object-schema@2.1.7': {}
+
+ '@eslint/plugin-kit@0.4.1':
+ dependencies:
+ '@eslint/core': 0.17.0
+ levn: 0.4.1
+
+ '@exodus/bytes@1.15.0': {}
+
+ '@humanfs/core@0.19.1': {}
+
+ '@humanfs/node@0.16.7':
+ dependencies:
+ '@humanfs/core': 0.19.1
+ '@humanwhocodes/retry': 0.4.3
+
+ '@humanwhocodes/module-importer@1.0.1': {}
+
+ '@humanwhocodes/retry@0.4.3': {}
+
+ '@inquirer/ansi@2.0.5': {}
+
+ '@inquirer/confirm@6.0.12(@types/node@24.12.2)':
+ dependencies:
+ '@inquirer/core': 11.1.9(@types/node@24.12.2)
+ '@inquirer/type': 4.0.5(@types/node@24.12.2)
+ optionalDependencies:
+ '@types/node': 24.12.2
+
+ '@inquirer/core@11.1.9(@types/node@24.12.2)':
+ dependencies:
+ '@inquirer/ansi': 2.0.5
+ '@inquirer/figures': 2.0.5
+ '@inquirer/type': 4.0.5(@types/node@24.12.2)
+ cli-width: 4.1.0
+ fast-wrap-ansi: 0.2.0
+ mute-stream: 3.0.0
+ signal-exit: 4.1.0
+ optionalDependencies:
+ '@types/node': 24.12.2
+
+ '@inquirer/figures@2.0.5': {}
+
+ '@inquirer/type@4.0.5(@types/node@24.12.2)':
+ optionalDependencies:
+ '@types/node': 24.12.2
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@mswjs/interceptors@0.41.6':
+ dependencies:
+ '@open-draft/deferred-promise': 2.2.0
+ '@open-draft/logger': 0.3.0
+ '@open-draft/until': 2.1.0
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+ strict-event-emitter: 0.5.1
+
+ '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)':
+ dependencies:
+ '@emnapi/core': 1.9.2
+ '@emnapi/runtime': 1.9.2
+ '@tybys/wasm-util': 0.10.1
+ optional: true
+
+ '@open-draft/deferred-promise@2.2.0': {}
+
+ '@open-draft/deferred-promise@3.0.0': {}
+
+ '@open-draft/logger@0.3.0':
+ dependencies:
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+
+ '@open-draft/until@2.1.0': {}
+
+ '@oxc-project/types@0.124.0': {}
+
+ '@playwright/test@1.59.1':
+ dependencies:
+ playwright: 1.59.1
+
+ '@rc-component/async-validator@5.1.0':
+ dependencies:
+ '@babel/runtime': 7.29.2
+
+ '@rc-component/cascader@1.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/select': 1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tree': 1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/checkbox@2.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/collapse@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/color-picker@3.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@ant-design/fast-color': 3.0.1
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/context@2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/dialog@1.8.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/drawer@1.4.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/dropdown@1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/form@1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/async-validator': 5.1.0
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/image@1.8.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/input-number@1.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/mini-decimal': 1.1.3
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/input@1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/mentions@1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/input': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/menu': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/textarea': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/menu@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/mini-decimal@1.1.3':
+ dependencies:
+ '@babel/runtime': 7.29.2
+
+ '@rc-component/motion@1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/mutate-observer@2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/notification@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/overflow@1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/pagination@1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/picker@1.9.1(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ optionalDependencies:
+ dayjs: 1.11.20
+
+ '@rc-component/portal@2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/progress@1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/qrcode@1.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/rate@1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/resize-observer@1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/segmented@1.3.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/select@1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/overflow': 1.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/slider@1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/steps@1.2.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/switch@1.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/table@1.9.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/context': 2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/tabs@1.7.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/dropdown': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/menu': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/textarea@1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/input': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/tooltip@1.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/tour@2.3.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/tree-select@1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/select': 1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tree': 1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/tree@1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/virtual-list': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/trigger@3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/portal': 2.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/upload@1.1.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rc-component/util@1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ is-mobile: 5.0.0
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ react-is: 18.3.1
+
+ '@rc-component/virtual-list@1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@rolldown/binding-android-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-wasm32-wasi@1.0.0-rc.15':
+ dependencies:
+ '@emnapi/core': 1.9.2
+ '@emnapi/runtime': 1.9.2
+ '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15':
+ optional: true
+
+ '@rolldown/pluginutils@1.0.0-rc.15': {}
+
+ '@rolldown/pluginutils@1.0.0-rc.7': {}
+
+ '@standard-schema/spec@1.1.0': {}
+
+ '@tailwindcss/node@4.2.2':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.20.1
+ jiti: 2.6.1
+ lightningcss: 1.32.0
+ magic-string: 0.30.21
+ source-map-js: 1.2.1
+ tailwindcss: 4.2.2
+
+ '@tailwindcss/oxide-android-arm64@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.2.2':
+ optional: true
+
+ '@tailwindcss/oxide@4.2.2':
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.2.2
+ '@tailwindcss/oxide-darwin-arm64': 4.2.2
+ '@tailwindcss/oxide-darwin-x64': 4.2.2
+ '@tailwindcss/oxide-freebsd-x64': 4.2.2
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2
+ '@tailwindcss/oxide-linux-arm64-musl': 4.2.2
+ '@tailwindcss/oxide-linux-x64-gnu': 4.2.2
+ '@tailwindcss/oxide-linux-x64-musl': 4.2.2
+ '@tailwindcss/oxide-wasm32-wasi': 4.2.2
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2
+ '@tailwindcss/oxide-win32-x64-msvc': 4.2.2
+
+ '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))':
+ dependencies:
+ '@tailwindcss/node': 4.2.2
+ '@tailwindcss/oxide': 4.2.2
+ tailwindcss: 4.2.2
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+
+ '@testing-library/dom@10.4.1':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/runtime': 7.29.2
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ picocolors: 1.1.1
+ pretty-format: 27.5.1
+
+ '@testing-library/jest-dom@6.9.1':
+ dependencies:
+ '@adobe/css-tools': 4.4.4
+ aria-query: 5.3.2
+ css.escape: 1.5.1
+ dom-accessibility-api: 0.6.3
+ picocolors: 1.1.1
+ redent: 3.0.0
+
+ '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@babel/runtime': 7.29.2
+ '@testing-library/dom': 10.4.1
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ optionalDependencies:
+ '@types/react': 19.2.14
+ '@types/react-dom': 19.2.3(@types/react@19.2.14)
+
+ '@transloadit/prettier-bytes@0.0.7': {}
+
+ '@tybys/wasm-util@0.10.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@types/aria-query@5.0.4': {}
+
+ '@types/chai@5.2.3':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
+
+ '@types/d3-array@3.2.2': {}
+
+ '@types/d3-color@3.1.3': {}
+
+ '@types/d3-dispatch@3.0.7': {}
+
+ '@types/d3-drag@3.0.7':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-dsv@3.0.7': {}
+
+ '@types/d3-ease@3.0.2': {}
+
+ '@types/d3-fetch@3.0.7':
+ dependencies:
+ '@types/d3-dsv': 3.0.7
+
+ '@types/d3-force@3.0.10': {}
+
+ '@types/d3-format@3.0.4': {}
+
+ '@types/d3-geo@3.1.0':
+ dependencies:
+ '@types/geojson': 7946.0.16
+
+ '@types/d3-hierarchy@3.1.7': {}
+
+ '@types/d3-interpolate@3.0.4':
+ dependencies:
+ '@types/d3-color': 3.1.3
+
+ '@types/d3-path@3.1.1': {}
+
+ '@types/d3-quadtree@3.0.6': {}
+
+ '@types/d3-random@3.0.3': {}
+
+ '@types/d3-scale-chromatic@3.1.0': {}
+
+ '@types/d3-scale@4.0.9':
+ dependencies:
+ '@types/d3-time': 3.0.4
+
+ '@types/d3-selection@3.0.11': {}
+
+ '@types/d3-shape@3.1.8':
+ dependencies:
+ '@types/d3-path': 3.1.1
+
+ '@types/d3-time@3.0.4': {}
+
+ '@types/d3-timer@3.0.2': {}
+
+ '@types/d3-transition@3.0.9':
+ dependencies:
+ '@types/d3-selection': 3.0.11
+
+ '@types/d3-zoom@3.0.8':
+ dependencies:
+ '@types/d3-interpolate': 3.0.4
+ '@types/d3-selection': 3.0.11
+
+ '@types/deep-eql@4.0.2': {}
+
+ '@types/dompurify@3.2.0':
+ dependencies:
+ dompurify: 3.4.5
+
+ '@types/estree@1.0.8': {}
+
+ '@types/event-emitter@0.3.5': {}
+
+ '@types/geojson@7946.0.16': {}
+
+ '@types/json-schema@7.0.15': {}
+
+ '@types/node@24.12.2':
+ dependencies:
+ undici-types: 7.16.0
+
+ '@types/react-dom@19.2.3(@types/react@19.2.14)':
+ dependencies:
+ '@types/react': 19.2.14
+
+ '@types/react@19.2.14':
+ dependencies:
+ csstype: 3.2.3
+
+ '@types/set-cookie-parser@2.4.10':
+ dependencies:
+ '@types/node': 24.12.2
+
+ '@types/statuses@2.0.6': {}
+
+ '@types/trusted-types@2.0.7':
+ optional: true
+
+ '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)':
+ dependencies:
+ '@eslint-community/regexpp': 4.12.2
+ '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ '@typescript-eslint/scope-manager': 8.58.1
+ '@typescript-eslint/type-utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ '@typescript-eslint/visitor-keys': 8.58.1
+ eslint: 9.39.4(jiti@2.6.1)
+ ignore: 7.0.5
+ natural-compare: 1.4.0
+ ts-api-utils: 2.5.0(typescript@6.0.2)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)':
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.58.1
+ '@typescript-eslint/types': 8.58.1
+ '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/visitor-keys': 8.58.1
+ debug: 4.4.3
+ eslint: 9.39.4(jiti@2.6.1)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/project-service@8.58.1(typescript@6.0.2)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/types': 8.58.1
+ debug: 4.4.3
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/scope-manager@8.58.1':
+ dependencies:
+ '@typescript-eslint/types': 8.58.1
+ '@typescript-eslint/visitor-keys': 8.58.1
+
+ '@typescript-eslint/tsconfig-utils@8.58.1(typescript@6.0.2)':
+ dependencies:
+ typescript: 6.0.2
+
+ '@typescript-eslint/type-utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)':
+ dependencies:
+ '@typescript-eslint/types': 8.58.1
+ '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ debug: 4.4.3
+ eslint: 9.39.4(jiti@2.6.1)
+ ts-api-utils: 2.5.0(typescript@6.0.2)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/types@8.58.1': {}
+
+ '@typescript-eslint/typescript-estree@8.58.1(typescript@6.0.2)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/types': 8.58.1
+ '@typescript-eslint/visitor-keys': 8.58.1
+ debug: 4.4.3
+ minimatch: 10.2.5
+ semver: 7.7.4
+ tinyglobby: 0.2.16
+ ts-api-utils: 2.5.0(typescript@6.0.2)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/utils@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)':
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1))
+ '@typescript-eslint/scope-manager': 8.58.1
+ '@typescript-eslint/types': 8.58.1
+ '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2)
+ eslint: 9.39.4(jiti@2.6.1)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@typescript-eslint/visitor-keys@8.58.1':
+ dependencies:
+ '@typescript-eslint/types': 8.58.1
+ eslint-visitor-keys: 5.0.1
+
+ '@uppy/companion-client@2.2.2':
+ dependencies:
+ '@uppy/utils': 4.1.3
+ namespace-emitter: 2.0.1
+
+ '@uppy/core@2.3.4':
+ dependencies:
+ '@transloadit/prettier-bytes': 0.0.7
+ '@uppy/store-default': 2.1.1
+ '@uppy/utils': 4.1.3
+ lodash.throttle: 4.1.1
+ mime-match: 1.0.2
+ namespace-emitter: 2.0.1
+ nanoid: 3.3.11
+ preact: 10.29.1
+
+ '@uppy/store-default@2.1.1': {}
+
+ '@uppy/utils@4.1.3':
+ dependencies:
+ lodash.throttle: 4.1.1
+
+ '@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4)':
+ dependencies:
+ '@uppy/companion-client': 2.2.2
+ '@uppy/core': 2.3.4
+ '@uppy/utils': 4.1.3
+ nanoid: 3.3.11
+
+ '@vitejs/plugin-react@6.0.1(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))':
+ dependencies:
+ '@rolldown/pluginutils': 1.0.0-rc.7
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+
+ '@vitest/coverage-v8@4.1.5(vitest@4.1.5)':
+ dependencies:
+ '@bcoe/v8-coverage': 1.0.2
+ '@vitest/utils': 4.1.5
+ ast-v8-to-istanbul: 1.0.0
+ istanbul-lib-coverage: 3.2.2
+ istanbul-lib-report: 3.0.1
+ istanbul-reports: 3.2.0
+ magicast: 0.5.2
+ obug: 2.1.1
+ std-env: 4.1.0
+ tinyrainbow: 3.1.0
+ vitest: 4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+
+ '@vitest/expect@4.1.5':
+ dependencies:
+ '@standard-schema/spec': 1.1.0
+ '@types/chai': 5.2.3
+ '@vitest/spy': 4.1.5
+ '@vitest/utils': 4.1.5
+ chai: 6.2.2
+ tinyrainbow: 3.1.0
+
+ '@vitest/mocker@4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))':
+ dependencies:
+ '@vitest/spy': 4.1.5
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ optionalDependencies:
+ msw: 2.13.6(@types/node@24.12.2)(typescript@6.0.2)
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+
+ '@vitest/pretty-format@4.1.5':
+ dependencies:
+ tinyrainbow: 3.1.0
+
+ '@vitest/runner@4.1.5':
+ dependencies:
+ '@vitest/utils': 4.1.5
+ pathe: 2.0.3
+
+ '@vitest/snapshot@4.1.5':
+ dependencies:
+ '@vitest/pretty-format': 4.1.5
+ '@vitest/utils': 4.1.5
+ magic-string: 0.30.21
+ pathe: 2.0.3
+
+ '@vitest/spy@4.1.5': {}
+
+ '@vitest/utils@4.1.5':
+ dependencies:
+ '@vitest/pretty-format': 4.1.5
+ convert-source-map: 2.0.0
+ tinyrainbow: 3.1.0
+
+ '@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ is-url: 1.2.4
+ lodash.throttle: 4.1.1
+ nanoid: 3.3.11
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/code-highlight@1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ prismjs: 1.30.0
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@types/event-emitter': 0.3.5
+ '@uppy/core': 2.3.4
+ '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
+ dom7: 3.0.0
+ event-emitter: 0.3.5
+ html-void-elements: 2.0.1
+ i18next: 20.6.1
+ is-hotkey: 0.2.0
+ lodash.camelcase: 4.3.0
+ lodash.clonedeep: 4.5.0
+ lodash.debounce: 4.0.8
+ lodash.foreach: 4.5.0
+ lodash.isequal: 4.5.0
+ lodash.throttle: 4.1.1
+ lodash.toarray: 4.4.0
+ nanoid: 3.3.11
+ scroll-into-view-if-needed: 2.2.31
+ slate: 0.72.8
+ slate-history: 0.66.0(slate@0.72.8)
+ snabbdom: 3.6.3
+
+ '@wangeditor/editor-for-react@1.0.6(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/editor@5.1.23)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/editor': 5.1.23
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+
+ '@wangeditor/editor@5.1.23':
+ dependencies:
+ '@uppy/core': 2.3.4
+ '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
+ '@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/code-highlight': 1.0.3(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/list-module': 1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/table-module': 1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/upload-image-module': 1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/video-module': 1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ is-hotkey: 0.2.0
+ lodash.camelcase: 4.3.0
+ lodash.clonedeep: 4.5.0
+ lodash.debounce: 4.0.8
+ lodash.foreach: 4.5.0
+ lodash.isequal: 4.5.0
+ lodash.throttle: 4.1.1
+ lodash.toarray: 4.4.0
+ nanoid: 3.3.11
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/list-module@1.0.5(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/table-module@1.1.4(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ lodash.isequal: 4.5.0
+ lodash.throttle: 4.1.1
+ nanoid: 3.3.11
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/upload-image-module@1.0.2(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/basic-modules@1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.foreach@4.5.0)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@uppy/core': 2.3.4
+ '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
+ '@wangeditor/basic-modules': 1.1.7(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ lodash.foreach: 4.5.0
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@wangeditor/video-module@1.1.4(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor/core@1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@3.0.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
+ dependencies:
+ '@uppy/core': 2.3.4
+ '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
+ '@wangeditor/core': 1.1.19(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.isequal@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
+ dom7: 3.0.0
+ nanoid: 3.3.11
+ slate: 0.72.8
+ snabbdom: 3.6.3
+
+ '@xyflow/react@12.10.2(@types/react@19.2.14)(immer@9.0.21)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)':
+ dependencies:
+ '@xyflow/system': 0.0.76
+ classcat: 5.0.5
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ zustand: 4.5.7(@types/react@19.2.14)(immer@9.0.21)(react@19.2.5)
+ transitivePeerDependencies:
+ - '@types/react'
+ - immer
+
+ '@xyflow/system@0.0.76':
+ dependencies:
+ '@types/d3-drag': 3.0.7
+ '@types/d3-interpolate': 3.0.4
+ '@types/d3-selection': 3.0.11
+ '@types/d3-transition': 3.0.9
+ '@types/d3-zoom': 3.0.8
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-zoom: 3.0.0
+
+ acorn-jsx@5.3.2(acorn@8.16.0):
+ dependencies:
+ acorn: 8.16.0
+
+ acorn@8.16.0: {}
+
+ ajv@6.14.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+
+ ansi-regex@5.0.1: {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ ansi-styles@5.2.0: {}
+
+ antd@6.3.5(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
+ dependencies:
+ '@ant-design/colors': 8.0.1
+ '@ant-design/cssinjs': 2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@ant-design/cssinjs-utils': 2.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@ant-design/fast-color': 3.0.1
+ '@ant-design/icons': 6.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@ant-design/react-slick': 2.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@babel/runtime': 7.29.2
+ '@rc-component/cascader': 1.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/checkbox': 2.0.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/collapse': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/color-picker': 3.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/dialog': 1.8.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/drawer': 1.4.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/dropdown': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/form': 1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/image': 1.8.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/input': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/input-number': 1.6.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/mentions': 1.6.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/menu': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/motion': 1.3.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/notification': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/pagination': 1.2.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/picker': 1.9.1(dayjs@1.11.20)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/progress': 1.0.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/qrcode': 1.1.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/rate': 1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/resize-observer': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/segmented': 1.3.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/select': 1.6.15(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/slider': 1.0.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/steps': 1.2.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/switch': 1.0.3(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/table': 1.9.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tabs': 1.7.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/textarea': 1.1.2(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tooltip': 1.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tour': 2.3.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tree': 1.2.4(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/tree-select': 1.8.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/trigger': 3.9.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/upload': 1.1.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ '@rc-component/util': 1.10.1(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+ clsx: 2.1.1
+ dayjs: 1.11.20
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ scroll-into-view-if-needed: 3.1.0
+ throttle-debounce: 5.0.2
+ transitivePeerDependencies:
+ - date-fns
+ - luxon
+ - moment
+
+ argparse@2.0.1: {}
+
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
+ aria-query@5.3.2: {}
+
+ assertion-error@2.0.1: {}
+
+ ast-v8-to-istanbul@1.0.0:
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.31
+ estree-walker: 3.0.3
+ js-tokens: 10.0.0
+
+ asynckit@0.4.0: {}
+
+ axios@1.15.0:
+ dependencies:
+ follow-redirects: 1.15.11
+ form-data: 4.0.5
+ proxy-from-env: 2.1.0
+ transitivePeerDependencies:
+ - debug
+
+ balanced-match@1.0.2: {}
+
+ balanced-match@4.0.4: {}
+
+ base64-arraybuffer@1.0.2: {}
+
+ baseline-browser-mapping@2.10.17: {}
+
+ bidi-js@1.0.3:
+ dependencies:
+ require-from-string: 2.0.2
+
+ brace-expansion@1.1.13:
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+
+ brace-expansion@5.0.5:
+ dependencies:
+ balanced-match: 4.0.4
+
+ browserslist@4.28.2:
+ dependencies:
+ baseline-browser-mapping: 2.10.17
+ caniuse-lite: 1.0.30001787
+ electron-to-chromium: 1.5.334
+ node-releases: 2.0.37
+ update-browserslist-db: 1.2.3(browserslist@4.28.2)
+
+ bubblesets-js@2.3.4: {}
+
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001787: {}
+
+ chai@6.2.2: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ classcat@5.0.5: {}
+
+ cli-width@4.1.0: {}
+
+ cliui@8.0.1:
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+
+ clsx@2.1.1: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.4
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ comlink@4.4.2: {}
+
+ commander@7.2.0: {}
+
+ compute-scroll-into-view@1.0.20: {}
+
+ compute-scroll-into-view@3.1.1: {}
+
+ concat-map@0.0.1: {}
+
+ convert-source-map@2.0.0: {}
+
+ cookie@1.1.1: {}
+
+ cross-spawn@7.0.6:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ css-line-break@2.1.0:
+ dependencies:
+ utrie: 1.0.2
+
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
+ css.escape@1.5.1: {}
+
+ csstype@3.2.3: {}
+
+ d3-array@3.2.4:
+ dependencies:
+ internmap: 2.0.3
+
+ d3-binarytree@1.0.2: {}
+
+ d3-color@3.1.0: {}
+
+ d3-dispatch@3.0.1: {}
+
+ d3-drag@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-selection: 3.0.0
+
+ d3-dsv@3.0.1:
+ dependencies:
+ commander: 7.2.0
+ iconv-lite: 0.6.3
+ rw: 1.3.3
+
+ d3-ease@3.0.1: {}
+
+ d3-fetch@3.0.1:
+ dependencies:
+ d3-dsv: 3.0.1
+
+ d3-force-3d@3.0.6:
+ dependencies:
+ d3-binarytree: 1.0.2
+ d3-dispatch: 3.0.1
+ d3-octree: 1.1.0
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+
+ d3-force@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+
+ d3-format@3.1.2: {}
+
+ d3-geo-projection@4.0.0:
+ dependencies:
+ commander: 7.2.0
+ d3-array: 3.2.4
+ d3-geo: 3.1.1
+
+ d3-geo@3.1.1:
+ dependencies:
+ d3-array: 3.2.4
+
+ d3-hierarchy@3.1.2: {}
+
+ d3-interpolate@3.0.1:
+ dependencies:
+ d3-color: 3.1.0
+
+ d3-octree@1.1.0: {}
+
+ d3-path@3.1.0: {}
+
+ d3-quadtree@3.0.1: {}
+
+ d3-random@3.0.1: {}
+
+ d3-regression@1.3.10: {}
+
+ d3-scale-chromatic@3.1.0:
+ dependencies:
+ d3-color: 3.1.0
+ d3-interpolate: 3.0.1
+
+ d3-scale@4.0.2:
+ dependencies:
+ d3-array: 3.2.4
+ d3-format: 3.1.2
+ d3-interpolate: 3.0.1
+ d3-time: 3.1.0
+ d3-time-format: 4.1.0
+
+ d3-selection@3.0.0: {}
+
+ d3-shape@3.2.0:
+ dependencies:
+ d3-path: 3.1.0
+
+ d3-time-format@4.1.0:
+ dependencies:
+ d3-time: 3.1.0
+
+ d3-time@3.1.0:
+ dependencies:
+ d3-array: 3.2.4
+
+ d3-timer@3.0.1: {}
+
+ d3-transition@3.0.1(d3-selection@3.0.0):
+ dependencies:
+ d3-color: 3.1.0
+ d3-dispatch: 3.0.1
+ d3-ease: 3.0.1
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-timer: 3.0.1
+
+ d3-zoom@3.0.0:
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1(d3-selection@3.0.0)
+
+ d@1.0.2:
+ dependencies:
+ es5-ext: 0.10.64
+ type: 2.7.3
+
+ dagre@0.8.5:
+ dependencies:
+ graphlib: 2.1.8
+ lodash: 4.18.1
+
+ data-urls@7.0.0:
+ dependencies:
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ dayjs@1.11.20: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
+ decimal.js@10.6.0: {}
+
+ deep-is@0.1.4: {}
+
+ delayed-stream@1.0.0: {}
+
+ dequal@2.0.3: {}
+
+ detect-libc@2.1.2: {}
+
+ dom-accessibility-api@0.5.16: {}
+
+ dom-accessibility-api@0.6.3: {}
+
+ dom7@3.0.0:
+ dependencies:
+ ssr-window: 3.0.0
+
+ dompurify@3.4.5:
+ optionalDependencies:
+ '@types/trusted-types': 2.0.7
+
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
+ electron-to-chromium@1.5.334: {}
+
+ emoji-regex@8.0.0: {}
+
+ enhanced-resolve@5.20.1:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.3.2
+
+ entities@8.0.0: {}
+
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-module-lexer@2.0.0: {}
+
+ es-object-atoms@1.1.1:
+ dependencies:
+ es-errors: 1.3.0
+
+ es-set-tostringtag@2.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+
+ es5-ext@0.10.64:
+ dependencies:
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.4
+ esniff: 2.0.1
+ next-tick: 1.1.0
+
+ es6-iterator@2.0.3:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-symbol: 3.1.4
+
+ es6-symbol@3.1.4:
+ dependencies:
+ d: 1.0.2
+ ext: 1.7.0
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ eslint-plugin-react-hooks@7.0.1(eslint@9.39.4(jiti@2.6.1)):
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/parser': 7.29.2
+ eslint: 9.39.4(jiti@2.6.1)
+ hermes-parser: 0.25.1
+ zod: 4.3.6
+ zod-validation-error: 4.0.2(zod@4.3.6)
+ transitivePeerDependencies:
+ - supports-color
+
+ eslint-plugin-react-refresh@0.5.2(eslint@9.39.4(jiti@2.6.1)):
+ dependencies:
+ eslint: 9.39.4(jiti@2.6.1)
+
+ eslint-scope@8.4.0:
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+
+ eslint-visitor-keys@3.4.3: {}
+
+ eslint-visitor-keys@4.2.1: {}
+
+ eslint-visitor-keys@5.0.1: {}
+
+ eslint@9.39.4(jiti@2.6.1):
+ dependencies:
+ '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1))
+ '@eslint-community/regexpp': 4.12.2
+ '@eslint/config-array': 0.21.2
+ '@eslint/config-helpers': 0.4.2
+ '@eslint/core': 0.17.0
+ '@eslint/eslintrc': 3.3.5
+ '@eslint/js': 9.39.4
+ '@eslint/plugin-kit': 0.4.1
+ '@humanfs/node': 0.16.7
+ '@humanwhocodes/module-importer': 1.0.1
+ '@humanwhocodes/retry': 0.4.3
+ '@types/estree': 1.0.8
+ ajv: 6.14.0
+ chalk: 4.1.2
+ cross-spawn: 7.0.6
+ debug: 4.4.3
+ escape-string-regexp: 4.0.0
+ eslint-scope: 8.4.0
+ eslint-visitor-keys: 4.2.1
+ espree: 10.4.0
+ esquery: 1.7.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 8.0.0
+ find-up: 5.0.0
+ glob-parent: 6.0.2
+ ignore: 5.3.2
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ json-stable-stringify-without-jsonify: 1.0.1
+ lodash.merge: 4.6.2
+ minimatch: 3.1.5
+ natural-compare: 1.4.0
+ optionator: 0.9.4
+ optionalDependencies:
+ jiti: 2.6.1
+ transitivePeerDependencies:
+ - supports-color
+
+ esniff@2.0.1:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ event-emitter: 0.3.5
+ type: 2.7.3
+
+ espree@10.4.0:
+ dependencies:
+ acorn: 8.16.0
+ acorn-jsx: 5.3.2(acorn@8.16.0)
+ eslint-visitor-keys: 4.2.1
+
+ esquery@1.7.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ esrecurse@4.3.0:
+ dependencies:
+ estraverse: 5.3.0
+
+ estraverse@5.3.0: {}
+
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.8
+
+ esutils@2.0.3: {}
+
+ event-emitter@0.3.5:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+
+ eventemitter3@5.0.4: {}
+
+ expect-type@1.3.0: {}
+
+ ext@1.7.0:
+ dependencies:
+ type: 2.7.3
+
+ fast-deep-equal@3.1.3: {}
+
+ fast-json-stable-stringify@2.1.0: {}
+
+ fast-levenshtein@2.0.6: {}
+
+ fast-string-truncated-width@3.0.3: {}
+
+ fast-string-width@3.0.2:
+ dependencies:
+ fast-string-truncated-width: 3.0.3
+
+ fast-wrap-ansi@0.2.0:
+ dependencies:
+ fast-string-width: 3.0.2
+
+ fdir@6.5.0(picomatch@4.0.4):
+ optionalDependencies:
+ picomatch: 4.0.4
+
+ fecha@4.2.3: {}
+
+ file-entry-cache@8.0.0:
+ dependencies:
+ flat-cache: 4.0.1
+
+ find-up@5.0.0:
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+
+ flat-cache@4.0.1:
+ dependencies:
+ flatted: 3.4.2
+ keyv: 4.5.4
+
+ flatted@3.4.2: {}
+
+ flru@1.0.2: {}
+
+ follow-redirects@1.15.11: {}
+
+ form-data@4.0.5:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
+ mime-types: 2.1.35
+
+ fsevents@2.3.2:
+ optional: true
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ gensync@1.0.0-beta.2: {}
+
+ get-caller-file@2.0.5: {}
+
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.1
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.2
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.1
+
+ gl-matrix@3.4.4: {}
+
+ glob-parent@6.0.2:
+ dependencies:
+ is-glob: 4.0.3
+
+ globals@14.0.0: {}
+
+ globals@17.4.0: {}
+
+ gopd@1.2.0: {}
+
+ graceful-fs@4.2.11: {}
+
+ graphlib@2.1.8:
+ dependencies:
+ lodash: 4.18.1
+
+ graphql@16.13.2: {}
+
+ has-flag@4.0.0: {}
+
+ has-symbols@1.1.0: {}
+
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.1.0
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ headers-polyfill@5.0.1:
+ dependencies:
+ '@types/set-cookie-parser': 2.4.10
+ set-cookie-parser: 3.1.0
+
+ hermes-estree@0.25.1: {}
+
+ hermes-parser@0.25.1:
+ dependencies:
+ hermes-estree: 0.25.1
+
+ html-encoding-sniffer@6.0.0:
+ dependencies:
+ '@exodus/bytes': 1.15.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ html-escaper@2.0.2: {}
+
+ html-void-elements@2.0.1: {}
+
+ html2canvas@1.4.1:
+ dependencies:
+ css-line-break: 2.1.0
+ text-segmentation: 1.0.3
+
+ i18next@20.6.1:
+ dependencies:
+ '@babel/runtime': 7.29.2
+
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
+ ignore@5.3.2: {}
+
+ ignore@7.0.5: {}
+
+ immer@9.0.21: {}
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ imurmurhash@0.1.4: {}
+
+ indent-string@4.0.0: {}
+
+ internmap@2.0.3: {}
+
+ is-any-array@3.0.0: {}
+
+ is-arrayish@0.3.4: {}
+
+ is-extglob@2.1.1: {}
+
+ is-fullwidth-code-point@3.0.0: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-hotkey@0.2.0: {}
+
+ is-mobile@5.0.0: {}
+
+ is-node-process@1.2.0: {}
+
+ is-plain-object@5.0.0: {}
+
+ is-potential-custom-element-name@1.0.1: {}
+
+ is-url@1.2.4: {}
+
+ isexe@2.0.0: {}
+
+ istanbul-lib-coverage@3.2.2: {}
+
+ istanbul-lib-report@3.0.1:
+ dependencies:
+ istanbul-lib-coverage: 3.2.2
+ make-dir: 4.0.0
+ supports-color: 7.2.0
+
+ istanbul-reports@3.2.0:
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.1
+
+ jiti@2.6.1: {}
+
+ js-tokens@10.0.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.1:
+ dependencies:
+ argparse: 2.0.1
+
+ jsdom@29.0.2:
+ dependencies:
+ '@asamuzakjp/css-color': 5.1.11
+ '@asamuzakjp/dom-selector': 7.1.1
+ '@bramus/specificity': 2.4.2
+ '@csstools/css-syntax-patches-for-csstree': 1.1.3(css-tree@3.2.1)
+ '@exodus/bytes': 1.15.0
+ css-tree: 3.2.1
+ data-urls: 7.0.0
+ decimal.js: 10.6.0
+ html-encoding-sniffer: 6.0.0
+ is-potential-custom-element-name: 1.0.1
+ lru-cache: 11.3.5
+ parse5: 8.0.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 6.0.1
+ undici: 7.25.0
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 8.0.1
+ whatwg-mimetype: 5.0.0
+ whatwg-url: 16.0.1
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ jsesc@3.1.0: {}
+
+ json-buffer@3.0.1: {}
+
+ json-schema-traverse@0.4.1: {}
+
+ json-stable-stringify-without-jsonify@1.0.1: {}
+
+ json2mq@0.2.0:
+ dependencies:
+ string-convert: 0.2.1
+
+ json5@2.2.3: {}
+
+ keyv@4.5.4:
+ dependencies:
+ json-buffer: 3.0.1
+
+ levn@0.4.1:
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+
+ lightningcss-android-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-arm64@1.32.0:
+ optional: true
+
+ lightningcss-darwin-x64@1.32.0:
+ optional: true
+
+ lightningcss-freebsd-x64@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.32.0:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.32.0:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.32.0:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.32.0:
+ optional: true
+
+ lightningcss@1.32.0:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.32.0
+ lightningcss-darwin-arm64: 1.32.0
+ lightningcss-darwin-x64: 1.32.0
+ lightningcss-freebsd-x64: 1.32.0
+ lightningcss-linux-arm-gnueabihf: 1.32.0
+ lightningcss-linux-arm64-gnu: 1.32.0
+ lightningcss-linux-arm64-musl: 1.32.0
+ lightningcss-linux-x64-gnu: 1.32.0
+ lightningcss-linux-x64-musl: 1.32.0
+ lightningcss-win32-arm64-msvc: 1.32.0
+ lightningcss-win32-x64-msvc: 1.32.0
+
+ locate-path@6.0.0:
+ dependencies:
+ p-locate: 5.0.0
+
+ lodash.camelcase@4.3.0: {}
+
+ lodash.clonedeep@4.5.0: {}
+
+ lodash.debounce@4.0.8: {}
+
+ lodash.foreach@4.5.0: {}
+
+ lodash.isequal@4.5.0: {}
+
+ lodash.merge@4.6.2: {}
+
+ lodash.throttle@4.1.1: {}
+
+ lodash.toarray@4.4.0: {}
+
+ lodash@4.18.1: {}
+
+ lru-cache@11.3.5: {}
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ lz-string@1.5.0: {}
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ magicast@0.5.2:
+ dependencies:
+ '@babel/parser': 7.29.2
+ '@babel/types': 7.29.0
+ source-map-js: 1.2.1
+
+ make-dir@4.0.0:
+ dependencies:
+ semver: 7.7.4
+
+ math-intrinsics@1.1.0: {}
+
+ mdn-data@2.27.1: {}
+
+ mime-db@1.52.0: {}
+
+ mime-match@1.0.2:
+ dependencies:
+ wildcard: 1.1.2
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ min-indent@1.0.1: {}
+
+ minimatch@10.2.5:
+ dependencies:
+ brace-expansion: 5.0.5
+
+ minimatch@3.1.5:
+ dependencies:
+ brace-expansion: 1.1.13
+
+ ml-array-max@2.0.0:
+ dependencies:
+ is-any-array: 3.0.0
+
+ ml-array-min@2.0.0:
+ dependencies:
+ is-any-array: 3.0.0
+
+ ml-array-rescale@2.0.0:
+ dependencies:
+ is-any-array: 3.0.0
+ ml-array-max: 2.0.0
+ ml-array-min: 2.0.0
+
+ ml-matrix@6.12.2:
+ dependencies:
+ is-any-array: 3.0.0
+ ml-array-rescale: 2.0.0
+
+ ms@2.1.3: {}
+
+ msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2):
+ dependencies:
+ '@inquirer/confirm': 6.0.12(@types/node@24.12.2)
+ '@mswjs/interceptors': 0.41.6
+ '@open-draft/deferred-promise': 3.0.0
+ '@types/statuses': 2.0.6
+ cookie: 1.1.1
+ graphql: 16.13.2
+ headers-polyfill: 5.0.1
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+ path-to-regexp: 6.3.0
+ picocolors: 1.1.1
+ rettime: 0.11.8
+ statuses: 2.0.2
+ strict-event-emitter: 0.5.1
+ tough-cookie: 6.0.1
+ type-fest: 5.6.0
+ until-async: 3.0.2
+ yargs: 17.7.2
+ optionalDependencies:
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - '@types/node'
+
+ mute-stream@3.0.0: {}
+
+ namespace-emitter@2.0.1: {}
+
+ nanoid@3.3.11: {}
+
+ natural-compare@1.4.0: {}
+
+ next-tick@1.1.0: {}
+
+ node-releases@2.0.37: {}
+
+ obug@2.1.1: {}
+
+ optionator@0.9.4:
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.5
+
+ outvariant@1.4.3: {}
+
+ p-limit@3.1.0:
+ dependencies:
+ yocto-queue: 0.1.0
+
+ p-locate@5.0.0:
+ dependencies:
+ p-limit: 3.1.0
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse5@8.0.1:
+ dependencies:
+ entities: 8.0.0
+
+ path-exists@4.0.0: {}
+
+ path-key@3.1.1: {}
+
+ path-to-regexp@6.3.0: {}
+
+ pathe@2.0.3: {}
+
+ pdfast@0.2.0: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@4.0.4: {}
+
+ playwright-core@1.59.1: {}
+
+ playwright@1.59.1:
+ dependencies:
+ playwright-core: 1.59.1
+ optionalDependencies:
+ fsevents: 2.3.2
+
+ postcss@8.5.9:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ preact@10.29.1: {}
+
+ prelude-ls@1.2.1: {}
+
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+
+ prismjs@1.30.0: {}
+
+ proxy-from-env@2.1.0: {}
+
+ punycode@2.3.1: {}
+
+ react-dom@19.2.5(react@19.2.5):
+ dependencies:
+ react: 19.2.5
+ scheduler: 0.27.0
+
+ react-is@17.0.2: {}
+
+ react-is@18.3.1: {}
+
+ react-router-dom@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
+ dependencies:
+ react: 19.2.5
+ react-dom: 19.2.5(react@19.2.5)
+ react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5)
+
+ react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
+ dependencies:
+ cookie: 1.1.1
+ react: 19.2.5
+ set-cookie-parser: 2.7.2
+ optionalDependencies:
+ react-dom: 19.2.5(react@19.2.5)
+
+ react@19.2.5: {}
+
+ redent@3.0.0:
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+
+ require-directory@2.1.1: {}
+
+ require-from-string@2.0.2: {}
+
+ resolve-from@4.0.0: {}
+
+ rettime@0.11.8: {}
+
+ rolldown@1.0.0-rc.15:
+ dependencies:
+ '@oxc-project/types': 0.124.0
+ '@rolldown/pluginutils': 1.0.0-rc.15
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.0-rc.15
+ '@rolldown/binding-darwin-arm64': 1.0.0-rc.15
+ '@rolldown/binding-darwin-x64': 1.0.0-rc.15
+ '@rolldown/binding-freebsd-x64': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15
+ '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15
+ '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15
+ '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15
+ '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15
+
+ rw@1.3.3: {}
+
+ safer-buffer@2.1.2: {}
+
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
+ scheduler@0.27.0: {}
+
+ scroll-into-view-if-needed@2.2.31:
+ dependencies:
+ compute-scroll-into-view: 1.0.20
+
+ scroll-into-view-if-needed@3.1.0:
+ dependencies:
+ compute-scroll-into-view: 3.1.1
+
+ semver@6.3.1: {}
+
+ semver@7.7.4: {}
+
+ set-cookie-parser@2.7.2: {}
+
+ set-cookie-parser@3.1.0: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ siginfo@2.0.0: {}
+
+ signal-exit@4.1.0: {}
+
+ simple-swizzle@0.2.4:
+ dependencies:
+ is-arrayish: 0.3.4
+
+ slate-history@0.66.0(slate@0.72.8):
+ dependencies:
+ is-plain-object: 5.0.0
+ slate: 0.72.8
+
+ slate@0.72.8:
+ dependencies:
+ immer: 9.0.21
+ is-plain-object: 5.0.0
+ tiny-warning: 1.0.3
+
+ snabbdom@3.6.3: {}
+
+ source-map-js@1.2.1: {}
+
+ ssr-window@3.0.0: {}
+
+ stackback@0.0.2: {}
+
+ statuses@2.0.2: {}
+
+ std-env@4.1.0: {}
+
+ strict-event-emitter@0.5.1: {}
+
+ string-convert@0.2.1: {}
+
+ string-width@4.2.3:
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+
+ strip-ansi@6.0.1:
+ dependencies:
+ ansi-regex: 5.0.1
+
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
+ strip-json-comments@3.1.1: {}
+
+ styled-components@6.4.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5):
+ dependencies:
+ '@emotion/is-prop-valid': 1.4.0
+ csstype: 3.2.3
+ react: 19.2.5
+ stylis: 4.3.6
+ optionalDependencies:
+ react-dom: 19.2.5(react@19.2.5)
+
+ stylis@4.3.6: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ svg-path-parser@1.1.0: {}
+
+ symbol-tree@3.2.4: {}
+
+ tagged-tag@1.0.0: {}
+
+ tailwindcss@4.2.2: {}
+
+ tapable@2.3.2: {}
+
+ text-segmentation@1.0.3:
+ dependencies:
+ utrie: 1.0.2
+
+ throttle-debounce@5.0.2: {}
+
+ tiny-warning@1.0.3: {}
+
+ tinybench@2.9.0: {}
+
+ tinyexec@1.1.1: {}
+
+ tinyglobby@0.2.16:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.4)
+ picomatch: 4.0.4
+
+ tinyrainbow@3.1.0: {}
+
+ tldts-core@7.0.28: {}
+
+ tldts@7.0.28:
+ dependencies:
+ tldts-core: 7.0.28
+
+ tough-cookie@6.0.1:
+ dependencies:
+ tldts: 7.0.28
+
+ tr46@6.0.0:
+ dependencies:
+ punycode: 2.3.1
+
+ ts-api-utils@2.5.0(typescript@6.0.2):
+ dependencies:
+ typescript: 6.0.2
+
+ tslib@2.8.1: {}
+
+ type-check@0.4.0:
+ dependencies:
+ prelude-ls: 1.2.1
+
+ type-fest@5.6.0:
+ dependencies:
+ tagged-tag: 1.0.0
+
+ type@2.7.3: {}
+
+ typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2):
+ dependencies:
+ '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ '@typescript-eslint/parser': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2)
+ '@typescript-eslint/utils': 8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)
+ eslint: 9.39.4(jiti@2.6.1)
+ typescript: 6.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ typescript@6.0.2: {}
+
+ undici-types@7.16.0: {}
+
+ undici@7.25.0: {}
+
+ until-async@3.0.2: {}
+
+ update-browserslist-db@1.2.3(browserslist@4.28.2):
+ dependencies:
+ browserslist: 4.28.2
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
+
+ use-sync-external-store@1.6.0(react@19.2.5):
+ dependencies:
+ react: 19.2.5
+
+ utrie@1.0.2:
+ dependencies:
+ base64-arraybuffer: 1.0.2
+
+ vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1):
+ dependencies:
+ lightningcss: 1.32.0
+ picomatch: 4.0.4
+ postcss: 8.5.9
+ rolldown: 1.0.0-rc.15
+ tinyglobby: 0.2.16
+ optionalDependencies:
+ '@types/node': 24.12.2
+ fsevents: 2.3.3
+ jiti: 2.6.1
+
+ vitest@4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)):
+ dependencies:
+ '@vitest/expect': 4.1.5
+ '@vitest/mocker': 4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))
+ '@vitest/pretty-format': 4.1.5
+ '@vitest/runner': 4.1.5
+ '@vitest/snapshot': 4.1.5
+ '@vitest/spy': 4.1.5
+ '@vitest/utils': 4.1.5
+ es-module-lexer: 2.0.0
+ expect-type: 1.3.0
+ magic-string: 0.30.21
+ obug: 2.1.1
+ pathe: 2.0.3
+ picomatch: 4.0.4
+ std-env: 4.1.0
+ tinybench: 2.9.0
+ tinyexec: 1.1.1
+ tinyglobby: 0.2.16
+ tinyrainbow: 3.1.0
+ vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 24.12.2
+ '@vitest/coverage-v8': 4.1.5(vitest@4.1.5)
+ jsdom: 29.0.2
+ transitivePeerDependencies:
+ - msw
+
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
+ webidl-conversions@8.0.1: {}
+
+ whatwg-mimetype@5.0.0: {}
+
+ whatwg-url@16.0.1:
+ dependencies:
+ '@exodus/bytes': 1.15.0
+ tr46: 6.0.0
+ webidl-conversions: 8.0.1
+ transitivePeerDependencies:
+ - '@noble/hashes'
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
+
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
+ wildcard@1.1.2: {}
+
+ word-wrap@1.2.5: {}
+
+ wrap-ansi@7.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
+ y18n@5.0.8: {}
+
+ yallist@3.1.1: {}
+
+ yargs-parser@21.1.1: {}
+
+ yargs@17.7.2:
+ dependencies:
+ cliui: 8.0.1
+ escalade: 3.2.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 21.1.1
+
+ yocto-queue@0.1.0: {}
+
+ zod-validation-error@4.0.2(zod@4.3.6):
+ dependencies:
+ zod: 4.3.6
+
+ zod@4.3.6: {}
+
+ zustand@4.5.7(@types/react@19.2.14)(immer@9.0.21)(react@19.2.5):
+ dependencies:
+ use-sync-external-store: 1.6.0(react@19.2.5)
+ optionalDependencies:
+ '@types/react': 19.2.14
+ immer: 9.0.21
+ react: 19.2.5
+
+ zustand@5.0.12(@types/react@19.2.14)(immer@9.0.21)(react@19.2.5)(use-sync-external-store@1.6.0(react@19.2.5)):
+ optionalDependencies:
+ '@types/react': 19.2.14
+ immer: 9.0.21
+ react: 19.2.5
+ use-sync-external-store: 1.6.0(react@19.2.5)
diff --git a/apps/web/public/crm.wasm b/apps/web/public/crm.wasm
new file mode 100644
index 0000000..94339aa
Binary files /dev/null and b/apps/web/public/crm.wasm differ
diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg
new file mode 100644
index 0000000..6893eb1
--- /dev/null
+++ b/apps/web/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/web/public/icons.svg b/apps/web/public/icons.svg
new file mode 100644
index 0000000..e952219
--- /dev/null
+++ b/apps/web/public/icons.svg
@@ -0,0 +1,24 @@
+
diff --git a/apps/web/public/inventory.wasm b/apps/web/public/inventory.wasm
new file mode 100644
index 0000000..f402120
Binary files /dev/null and b/apps/web/public/inventory.wasm differ
diff --git a/apps/web/public/mockServiceWorker.js b/apps/web/public/mockServiceWorker.js
new file mode 100644
index 0000000..80f1930
--- /dev/null
+++ b/apps/web/public/mockServiceWorker.js
@@ -0,0 +1,349 @@
+/* eslint-disable */
+/* tslint:disable */
+
+/**
+ * Mock Service Worker.
+ * @see https://github.com/mswjs/msw
+ * - Please do NOT modify this file.
+ */
+
+const PACKAGE_VERSION = '2.13.6'
+const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
+const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
+const activeClientIds = new Set()
+
+addEventListener('install', function () {
+ self.skipWaiting()
+})
+
+addEventListener('activate', function (event) {
+ event.waitUntil(self.clients.claim())
+})
+
+addEventListener('message', async function (event) {
+ const clientId = Reflect.get(event.source || {}, 'id')
+
+ if (!clientId || !self.clients) {
+ return
+ }
+
+ const client = await self.clients.get(clientId)
+
+ if (!client) {
+ return
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ switch (event.data) {
+ case 'KEEPALIVE_REQUEST': {
+ sendToClient(client, {
+ type: 'KEEPALIVE_RESPONSE',
+ })
+ break
+ }
+
+ case 'INTEGRITY_CHECK_REQUEST': {
+ sendToClient(client, {
+ type: 'INTEGRITY_CHECK_RESPONSE',
+ payload: {
+ packageVersion: PACKAGE_VERSION,
+ checksum: INTEGRITY_CHECKSUM,
+ },
+ })
+ break
+ }
+
+ case 'MOCK_ACTIVATE': {
+ activeClientIds.add(clientId)
+
+ sendToClient(client, {
+ type: 'MOCKING_ENABLED',
+ payload: {
+ client: {
+ id: client.id,
+ frameType: client.frameType,
+ },
+ },
+ })
+ break
+ }
+
+ case 'CLIENT_CLOSED': {
+ activeClientIds.delete(clientId)
+
+ const remainingClients = allClients.filter((client) => {
+ return client.id !== clientId
+ })
+
+ // Unregister itself when there are no more clients
+ if (remainingClients.length === 0) {
+ self.registration.unregister()
+ }
+
+ break
+ }
+ }
+})
+
+addEventListener('fetch', function (event) {
+ const requestInterceptedAt = Date.now()
+
+ // Bypass navigation requests.
+ if (event.request.mode === 'navigate') {
+ return
+ }
+
+ // Opening the DevTools triggers the "only-if-cached" request
+ // that cannot be handled by the worker. Bypass such requests.
+ if (
+ event.request.cache === 'only-if-cached' &&
+ event.request.mode !== 'same-origin'
+ ) {
+ return
+ }
+
+ // Bypass all requests when there are no active clients.
+ // Prevents the self-unregistered worked from handling requests
+ // after it's been terminated (still remains active until the next reload).
+ if (activeClientIds.size === 0) {
+ return
+ }
+
+ const requestId = crypto.randomUUID()
+ event.respondWith(handleRequest(event, requestId, requestInterceptedAt))
+})
+
+/**
+ * @param {FetchEvent} event
+ * @param {string} requestId
+ * @param {number} requestInterceptedAt
+ */
+async function handleRequest(event, requestId, requestInterceptedAt) {
+ const client = await resolveMainClient(event)
+ const requestCloneForEvents = event.request.clone()
+ const response = await getResponse(
+ event,
+ client,
+ requestId,
+ requestInterceptedAt,
+ )
+
+ // Send back the response clone for the "response:*" life-cycle events.
+ // Ensure MSW is active and ready to handle the message, otherwise
+ // this message will pend indefinitely.
+ if (client && activeClientIds.has(client.id)) {
+ const serializedRequest = await serializeRequest(requestCloneForEvents)
+
+ // Clone the response so both the client and the library could consume it.
+ const responseClone = response.clone()
+
+ sendToClient(
+ client,
+ {
+ type: 'RESPONSE',
+ payload: {
+ isMockedResponse: IS_MOCKED_RESPONSE in response,
+ request: {
+ id: requestId,
+ ...serializedRequest,
+ },
+ response: {
+ type: responseClone.type,
+ status: responseClone.status,
+ statusText: responseClone.statusText,
+ headers: Object.fromEntries(responseClone.headers.entries()),
+ body: responseClone.body,
+ },
+ },
+ },
+ responseClone.body ? [serializedRequest.body, responseClone.body] : [],
+ )
+ }
+
+ return response
+}
+
+/**
+ * Resolve the main client for the given event.
+ * Client that issues a request doesn't necessarily equal the client
+ * that registered the worker. It's with the latter the worker should
+ * communicate with during the response resolving phase.
+ * @param {FetchEvent} event
+ * @returns {Promise}
+ */
+async function resolveMainClient(event) {
+ const client = await self.clients.get(event.clientId)
+
+ if (activeClientIds.has(event.clientId)) {
+ return client
+ }
+
+ if (client?.frameType === 'top-level') {
+ return client
+ }
+
+ const allClients = await self.clients.matchAll({
+ type: 'window',
+ })
+
+ return allClients
+ .filter((client) => {
+ // Get only those clients that are currently visible.
+ return client.visibilityState === 'visible'
+ })
+ .find((client) => {
+ // Find the client ID that's recorded in the
+ // set of clients that have registered the worker.
+ return activeClientIds.has(client.id)
+ })
+}
+
+/**
+ * @param {FetchEvent} event
+ * @param {Client | undefined} client
+ * @param {string} requestId
+ * @param {number} requestInterceptedAt
+ * @returns {Promise}
+ */
+async function getResponse(event, client, requestId, requestInterceptedAt) {
+ // Clone the request because it might've been already used
+ // (i.e. its body has been read and sent to the client).
+ const requestClone = event.request.clone()
+
+ function passthrough() {
+ // Cast the request headers to a new Headers instance
+ // so the headers can be manipulated with.
+ const headers = new Headers(requestClone.headers)
+
+ // Remove the "accept" header value that marked this request as passthrough.
+ // This prevents request alteration and also keeps it compliant with the
+ // user-defined CORS policies.
+ const acceptHeader = headers.get('accept')
+ if (acceptHeader) {
+ const values = acceptHeader.split(',').map((value) => value.trim())
+ const filteredValues = values.filter(
+ (value) => value !== 'msw/passthrough',
+ )
+
+ if (filteredValues.length > 0) {
+ headers.set('accept', filteredValues.join(', '))
+ } else {
+ headers.delete('accept')
+ }
+ }
+
+ return fetch(requestClone, { headers })
+ }
+
+ // Bypass mocking when the client is not active.
+ if (!client) {
+ return passthrough()
+ }
+
+ // Bypass initial page load requests (i.e. static assets).
+ // The absence of the immediate/parent client in the map of the active clients
+ // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet
+ // and is not ready to handle requests.
+ if (!activeClientIds.has(client.id)) {
+ return passthrough()
+ }
+
+ // Notify the client that a request has been intercepted.
+ const serializedRequest = await serializeRequest(event.request)
+ const clientMessage = await sendToClient(
+ client,
+ {
+ type: 'REQUEST',
+ payload: {
+ id: requestId,
+ interceptedAt: requestInterceptedAt,
+ ...serializedRequest,
+ },
+ },
+ [serializedRequest.body],
+ )
+
+ switch (clientMessage.type) {
+ case 'MOCK_RESPONSE': {
+ return respondWithMock(clientMessage.data)
+ }
+
+ case 'PASSTHROUGH': {
+ return passthrough()
+ }
+ }
+
+ return passthrough()
+}
+
+/**
+ * @param {Client} client
+ * @param {any} message
+ * @param {Array} transferrables
+ * @returns {Promise}
+ */
+function sendToClient(client, message, transferrables = []) {
+ return new Promise((resolve, reject) => {
+ const channel = new MessageChannel()
+
+ channel.port1.onmessage = (event) => {
+ if (event.data && event.data.error) {
+ return reject(event.data.error)
+ }
+
+ resolve(event.data)
+ }
+
+ client.postMessage(message, [
+ channel.port2,
+ ...transferrables.filter(Boolean),
+ ])
+ })
+}
+
+/**
+ * @param {Response} response
+ * @returns {Response}
+ */
+function respondWithMock(response) {
+ // Setting response status code to 0 is a no-op.
+ // However, when responding with a "Response.error()", the produced Response
+ // instance will have status code set to 0. Since it's not possible to create
+ // a Response instance with status code 0, handle that use-case separately.
+ if (response.status === 0) {
+ return Response.error()
+ }
+
+ const mockedResponse = new Response(response.body, response)
+
+ Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, {
+ value: true,
+ enumerable: true,
+ })
+
+ return mockedResponse
+}
+
+/**
+ * @param {Request} request
+ */
+async function serializeRequest(request) {
+ return {
+ url: request.url,
+ mode: request.mode,
+ method: request.method,
+ headers: Object.fromEntries(request.headers.entries()),
+ cache: request.cache,
+ credentials: request.credentials,
+ destination: request.destination,
+ integrity: request.integrity,
+ redirect: request.redirect,
+ referrer: request.referrer,
+ referrerPolicy: request.referrerPolicy,
+ body: await request.arrayBuffer(),
+ keepalive: request.keepalive,
+ }
+}
diff --git a/apps/web/public/robots.txt b/apps/web/public/robots.txt
new file mode 100644
index 0000000..c2a49f4
--- /dev/null
+++ b/apps/web/public/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Allow: /
diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx
new file mode 100644
index 0000000..051f1fd
--- /dev/null
+++ b/apps/web/src/App.tsx
@@ -0,0 +1,371 @@
+import { useEffect, lazy, Suspense, useMemo } from 'react';
+import { HashRouter, Routes, Route, Navigate, useLocation, useNavigate } from 'react-router-dom';
+import { ConfigProvider, theme as antdTheme, Spin, Result } from 'antd';
+import zhCN from 'antd/locale/zh_CN';
+import MainLayout from './layouts/MainLayout';
+import Login from './pages/Login';
+import { ErrorBoundary } from './components/ErrorBoundary';
+import { useAuthStore } from './stores/auth';
+import { useAppStore } from './stores/app';
+import type { ThemeName } from './stores/app';
+import { ROUTE_PERMISSIONS, FROZEN_ROUTES, validateRouteCoverage } from './routeConfig';
+
+const Home = lazy(() => import('./pages/Home'));
+const Users = lazy(() => import('./pages/Users'));
+const Roles = lazy(() => import('./pages/Roles'));
+const Organizations = lazy(() => import('./pages/Organizations'));
+const Workflow = lazy(() => import('./pages/Workflow'));
+const Messages = lazy(() => import('./pages/Messages'));
+const Settings = lazy(() => import('./pages/Settings'));
+const PluginAdmin = lazy(() => import('./pages/PluginAdmin'));
+const PluginMarket = lazy(() => import('./pages/PluginMarket'));
+const PluginCRUDPage = lazy(() => import('./pages/PluginCRUDPage'));
+const PluginTabsPage = lazy(() => import('./pages/PluginTabsPage').then((m) => ({ default: m.PluginTabsPage })));
+const PluginTreePage = lazy(() => import('./pages/PluginTreePage').then((m) => ({ default: m.PluginTreePage })));
+const PluginGraphPage = lazy(() => import('./pages/PluginGraphPage').then((m) => ({ default: m.PluginGraphPage })));
+const PluginDashboardPage = lazy(() => import('./pages/PluginDashboardPage').then((m) => ({ default: m.PluginDashboardPage })));
+const PluginKanbanPage = lazy(() => import('./pages/PluginKanbanPage'));
+
+// 健康管理模块
+const PatientList = lazy(() => import('./pages/health/PatientList'));
+const PatientDetail = lazy(() => import('./pages/health/PatientDetail'));
+const PatientTagManage = lazy(() => import('./pages/health/PatientTagManage'));
+const DoctorList = lazy(() => import('./pages/health/DoctorList'));
+const AppointmentList = lazy(() => import('./pages/health/AppointmentList'));
+const DoctorSchedule = lazy(() => import('./pages/health/DoctorSchedule'));
+const FollowUpTaskList = lazy(() => import('./pages/health/FollowUpTaskList'));
+const FollowUpRecordList = lazy(() => import('./pages/health/FollowUpRecordList'));
+const ConsultationList = lazy(() => import('./pages/health/ConsultationList'));
+const ConsultationDetail = lazy(() => import('./pages/health/ConsultationDetail'));
+const PointsRuleList = lazy(() => import('./pages/health/PointsRuleList'));
+const PointsProductList = lazy(() => import('./pages/health/PointsProductList'));
+const PointsOrderList = lazy(() => import('./pages/health/PointsOrderList'));
+const OfflineEventList = lazy(() => import('./pages/health/OfflineEventList'));
+const StatisticsDashboard = lazy(() => import('./pages/health/StatisticsDashboard'));
+const AiPromptList = lazy(() => import('./pages/health/AiPromptList'));
+const AiAnalysisList = lazy(() => import('./pages/health/AiAnalysisList'));
+const AiUsageDashboard = lazy(() => import('./pages/health/AiUsageDashboard'));
+const AiConfigPage = lazy(() => import('./pages/health/AiConfigPage'));
+const KnowledgeV2Page = lazy(() => import('./pages/ai/KnowledgeV2Page'));
+const AiChatPage = lazy(() => import('./pages/ai/ChatPage'));
+const AlertList = lazy(() => import('./pages/health/AlertList'));
+const AlertDashboard = lazy(() => import('./pages/health/AlertDashboard'));
+const AlertRuleList = lazy(() => import('./pages/health/AlertRuleList'));
+const DeviceManage = lazy(() => import('./pages/health/DeviceManage'));
+const RealtimeMonitor = lazy(() => import('./pages/health/RealtimeMonitor'));
+const OAuthClientList = lazy(() => import('./pages/health/OAuthClientList'));
+const DialysisManageList = lazy(() => import('./pages/health/DialysisManageList'));
+const ActionInbox = lazy(() => import('./pages/health/ActionInbox'));
+const FollowUpTemplateList = lazy(() => import('./pages/health/FollowUpTemplateList'));
+const CarePlanList = lazy(() => import('./pages/health/CarePlanList'));
+const CarePlanDetail = lazy(() => import('./pages/health/CarePlanDetail'));
+const ShiftList = lazy(() => import('./pages/health/ShiftList'));
+const ShiftDetail = lazy(() => import('./pages/health/ShiftDetail'));
+const MedicationRecordList = lazy(() => import('./pages/health/MedicationRecordList'));
+const BleGatewayList = lazy(() => import('./pages/health/BleGatewayList'));
+const BleGatewayDetail = lazy(() => import('./pages/health/BleGatewayDetail'));
+const CriticalValueThresholdList = lazy(() => import('./pages/health/CriticalValueThresholdList'));
+const FamilyProxyPage = lazy(() => import('./pages/health/FamilyProxyPage'));
+
+// 内容管理
+const ArticleManageList = lazy(() => import('./pages/health/ArticleManageList'));
+const ArticleEditor = lazy(() => import('./pages/health/articleEditor/ArticleEditor'));
+const ArticleCategoryManage = lazy(() => import('./pages/health/ArticleCategoryManage'));
+const ArticleTagManage = lazy(() => import('./pages/health/ArticleTagManage'));
+const BannerManage = lazy(() => import('./pages/health/BannerManage'));
+const MediaLibrary = lazy(() => import('./pages/health/MediaLibrary'));
+
+function FrozenRoute() {
+ return ;
+}
+
+function ForbiddenPage() {
+ const navigate = useNavigate();
+ return (
+
+ navigate('/')} style={{ cursor: 'pointer', color: 'var(--ant-color-primary)', background: 'none', border: 'none', fontSize: 14 }}>返回首页}
+ />
+
+ );
+}
+
+function PrivateRoute({ children }: { children: React.ReactNode }) {
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
+ const permissions = useAuthStore((s) => s.permissions);
+ const location = useLocation();
+
+ if (!isAuthenticated) return ;
+
+ const path = location.pathname;
+
+ // 冻结路由检查
+ if (FROZEN_ROUTES.some((frozen) => path.startsWith(frozen))) {
+ return ;
+ }
+
+ // 首页/工作台始终放行
+ if (path === '/' || path === '') return <>{children}>;
+
+ const matchedPrefix = Object.keys(ROUTE_PERMISSIONS).find(
+ (prefix) => path === prefix || path.startsWith(prefix + '/'),
+ );
+ if (matchedPrefix) {
+ const required = ROUTE_PERMISSIONS[matchedPrefix];
+ const hasAccess = required.some((r) => permissions.includes(r));
+ if (!hasAccess) return ;
+ } else {
+ return ;
+ }
+
+ return <>{children}>;
+}
+
+const baseToken = {
+ borderRadius: 10,
+ borderRadiusLG: 12,
+ borderRadiusSM: 6,
+ fontFamily: "'Noto Sans SC', -apple-system, system-ui, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif",
+ fontSize: 14,
+ fontSizeHeading4: 20,
+ controlHeight: 40,
+ controlHeightLG: 44,
+ controlHeightSM: 32,
+ boxShadow: 'none',
+ boxShadowSecondary: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)',
+};
+
+const baseComponents = {
+ Button: { primaryShadow: 'none', fontWeight: 500 },
+ Card: { paddingLG: 20 },
+ Menu: { itemBorderRadius: 10, itemMarginInline: 8, itemHeight: 40 },
+ Modal: { borderRadiusLG: 16 },
+ Tag: { borderRadiusSM: 6 },
+};
+
+const themeConfigs: Record; components: Record> }> = {
+ blue: {
+ token: {
+ ...baseToken,
+ colorPrimary: '#2563eb',
+ colorSuccess: '#059669',
+ colorWarning: '#d97706',
+ colorError: '#dc2626',
+ colorInfo: '#0284c7',
+ colorBgLayout: '#f8fafc',
+ colorBgContainer: '#ffffff',
+ colorBgElevated: '#ffffff',
+ colorBorder: '#e2e8f0',
+ colorBorderSecondary: '#f1f5f9',
+ },
+ components: {
+ ...baseComponents,
+ Table: { headerBg: '#f1f5f9', headerColor: '#475569', rowHoverBg: '#f1f5f9', fontSize: 14 },
+ },
+ },
+ warm: {
+ token: {
+ ...baseToken,
+ borderRadius: 12,
+ borderRadiusLG: 14,
+ borderRadiusSM: 8,
+ colorPrimary: '#C4623A',
+ colorSuccess: '#5B7A5E',
+ colorWarning: '#C4873A',
+ colorError: '#B54A4A',
+ colorInfo: '#8B7A5E',
+ colorBgLayout: '#F5F0EB',
+ colorBgContainer: '#ffffff',
+ colorBgElevated: '#ffffff',
+ colorBorder: '#E8E2DC',
+ colorBorderSecondary: '#F0EBE5',
+ },
+ components: {
+ ...baseComponents,
+ Table: { headerBg: '#EDE8E2', headerColor: '#7A756E', rowHoverBg: '#F5F0EB', fontSize: 14 },
+ },
+ },
+ dark: {
+ token: {
+ ...baseToken,
+ colorPrimary: '#60A5FA',
+ colorSuccess: '#34D399',
+ colorWarning: '#FBBF24',
+ colorError: '#F87171',
+ colorInfo: '#38BDF8',
+ colorBgLayout: '#0F172A',
+ colorBgContainer: '#1E293B',
+ colorBgElevated: '#334155',
+ colorBorder: '#334155',
+ colorBorderSecondary: 'rgba(255,255,255,0.06)',
+ boxShadow: 'none',
+ boxShadowSecondary: '0 2px 8px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.2)',
+ },
+ components: {
+ ...baseComponents,
+ Table: { headerBg: '#1E293B', headerColor: '#94A3B8', rowHoverBg: '#1E293B', fontSize: 14 },
+ },
+ },
+ emerald: {
+ token: {
+ ...baseToken,
+ borderRadius: 10,
+ borderRadiusLG: 14,
+ borderRadiusSM: 8,
+ colorPrimary: '#5B7A5E',
+ colorSuccess: '#3D7A42',
+ colorWarning: '#B8863A',
+ colorError: '#A54A4A',
+ colorInfo: '#4A7A8B',
+ colorBgLayout: '#F4F7F4',
+ colorBgContainer: '#ffffff',
+ colorBgElevated: '#ffffff',
+ colorBorder: '#D5DED5',
+ colorBorderSecondary: '#E5ECE5',
+ },
+ components: {
+ ...baseComponents,
+ Table: { headerBg: '#EDF2ED', headerColor: '#5A6E5A', rowHoverBg: '#F4F7F4', fontSize: 14 },
+ },
+ },
+};
+
+export default function App() {
+ const loadFromStorage = useAuthStore((s) => s.loadFromStorage);
+ const themeName = useAppStore((s) => s.theme);
+
+ useEffect(() => {
+ loadFromStorage();
+ }, [loadFromStorage]);
+
+ useEffect(() => {
+ document.documentElement.setAttribute('data-theme', themeName);
+ }, [themeName]);
+
+ // DEV mode: validate all routes have permission declarations
+ useEffect(() => {
+ validateRouteCoverage([
+ "/users", "/roles", "/organizations", "/workflow", "/messages", "/settings",
+ "/plugins/admin", "/plugins/market",
+ "/health/statistics", "/health/patients", "/health/tags", "/health/doctors",
+ "/health/appointments", "/health/schedules", "/health/follow-up-tasks",
+ "/health/follow-up-records", "/health/consultations",
+ "/health/points-rules", "/health/points-products", "/health/points-orders",
+ "/health/offline-events", "/health/ai-prompts", "/health/ai-analysis",
+ "/health/ai-usage", "/health/ai-config", "/health/ai-knowledge", "/health/alerts", "/health/alert-dashboard",
+ "/ai/chat",
+ "/health/alert-rules", "/health/devices", "/health/realtime-monitor",
+ "/health/oauth-clients", "/health/dialysis", "/health/action-inbox",
+ "/health/follow-up-templates", "/health/care-plans", "/health/shifts",
+ "/health/medications", "/health/ble-gateways",
+ "/health/critical-value-thresholds", "/health/diagnoses",
+ "/health/family-proxy", "/health/consents",
+ "/health/articles", "/health/article-categories", "/health/article-tags",
+ "/health/banners", "/health/media-library",
+ "/health/medication-records",
+ ]);
+ }, []);
+
+ const isDark = themeName === 'dark';
+ const antTheme = useMemo(() => themeConfigs[themeName] ?? themeConfigs.blue, [themeName]);
+
+ return (
+ <>
+ 跳转到主要内容
+
+
+
+ } />
+
+
+
+ }>
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ {/* 健康管理 */}
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ {/* 内容管理 */}
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+
+
+ }
+ />
+
+
+
+ >
+ );
+}
diff --git a/apps/web/src/api/ai/analysis.test.ts b/apps/web/src/api/ai/analysis.test.ts
new file mode 100644
index 0000000..f2ec95c
--- /dev/null
+++ b/apps/web/src/api/ai/analysis.test.ts
@@ -0,0 +1,127 @@
+/**
+ * AI 模块 API 契约测试(analysis + prompts + suggestions + usage)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { analysisApi } from './analysis'
+import { promptApi } from './prompts'
+import { suggestionApi } from './suggestions'
+import { usageApi } from './usage'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('analysisApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('list 应调用 GET /ai/analysis/history 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await analysisApi.list({ patient_id: 'p-001', analysis_type: 'lab-report', page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/analysis/history', {
+ params: { patient_id: 'p-001', analysis_type: 'lab-report', page: 1, page_size: 10 },
+ })
+ })
+
+ it('get 应调用 GET /ai/analysis/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await analysisApi.get('ana-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/analysis/ana-001')
+ })
+})
+
+describe('promptApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('list 应调用 GET /ai/prompts 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await promptApi.list({ category: 'analysis', page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/prompts', {
+ params: { category: 'analysis', page: 1, page_size: 10 },
+ })
+ })
+
+ it('create 应调用 POST /ai/prompts 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '化验解读', system_prompt: '你是专业医生', user_prompt_template: '解读: {report}', model_config: {}, category: 'analysis' }
+ await promptApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/ai/prompts', req)
+ })
+
+ it('activate 应调用 POST /ai/prompts/:id/activate', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await promptApi.activate('prompt-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/ai/prompts/prompt-001/activate')
+ })
+
+ it('rollback 应调用 POST /ai/prompts/:id/rollback', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await promptApi.rollback('prompt-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/ai/prompts/prompt-001/rollback')
+ })
+})
+
+describe('suggestionApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('list 应调用 GET /ai/suggestions 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await suggestionApi.list({ analysis_id: 'ana-001', status: 'pending' })
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/suggestions', {
+ params: { analysis_id: 'ana-001', status: 'pending' },
+ })
+ })
+
+ it('approve 应调用 POST /ai/suggestions/:id/approve 并传递 action', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await suggestionApi.approve('sug-001', 'approve')
+
+ expect(mockPost).toHaveBeenCalledWith('/ai/suggestions/sug-001/approve', { action: 'approve' })
+ })
+
+ it('getComparison 应调用 GET /ai/suggestions/:id/comparison', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await suggestionApi.getComparison('sug-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/suggestions/sug-001/comparison')
+ })
+})
+
+describe('usageApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('overview 应调用 GET /ai/usage/overview', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await usageApi.overview()
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/usage/overview')
+ })
+
+ it('byType 应调用 GET /ai/usage/by-type', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await usageApi.byType()
+
+ expect(mockGet).toHaveBeenCalledWith('/ai/usage/by-type')
+ })
+})
diff --git a/apps/web/src/api/ai/analysis.ts b/apps/web/src/api/ai/analysis.ts
new file mode 100644
index 0000000..cdfbff9
--- /dev/null
+++ b/apps/web/src/api/ai/analysis.ts
@@ -0,0 +1,47 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+export interface AnalysisItem {
+ id: string;
+ patient_id: string;
+ patient_name?: string;
+ analysis_type: string;
+ source_ref: string;
+ model_used: string;
+ status: string;
+ result_content: string | null;
+ result_metadata: Record | null;
+ error_message: string | null;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface HealthSummaryResponse {
+ patient_id: string;
+ risk_level: 'low' | 'medium' | 'high' | 'critical';
+ active_insights_count: number;
+ recent_analyses_count: number;
+ latest_insight_title: string | null;
+ latest_analysis_type: string | null;
+ summary_items: Array<{
+ category: string;
+ title: string;
+ severity: string | null;
+ created_at: string;
+ }>;
+}
+
+export const analysisApi = {
+ list: async (params?: { patient_id?: string; analysis_type?: string; page?: number; page_size?: number }) => {
+ const resp = await client.get('/ai/analysis/history', { params });
+ return resp.data.data as PaginatedResponse;
+ },
+ get: async (id: string) => {
+ const resp = await client.get(`/ai/analysis/${id}`);
+ return resp.data.data as AnalysisItem;
+ },
+ getHealthSummary: async (patientId: string) => {
+ const resp = await client.get('/ai/health-summary', { params: { patient_id: patientId } });
+ return resp.data.data as HealthSummaryResponse;
+ },
+};
diff --git a/apps/web/src/api/ai/analysisSse.ts b/apps/web/src/api/ai/analysisSse.ts
new file mode 100644
index 0000000..4dee7af
--- /dev/null
+++ b/apps/web/src/api/ai/analysisSse.ts
@@ -0,0 +1,98 @@
+export type AnalysisType = 'lab-report' | 'trends' | 'checkup-plan' | 'report-summary' | 'follow-up-summary';
+
+interface AnalyzeBody {
+ report_id?: string;
+ patient_id?: string;
+ metrics?: string[];
+ source_id?: string;
+}
+
+const ENDPOINT_MAP: Record = {
+ 'lab-report': '/ai/analyze/lab-report',
+ 'trends': '/ai/analyze/trends',
+ 'checkup-plan': '/ai/analyze/checkup-plan',
+ 'report-summary': '/ai/analyze/report-summary',
+ 'follow-up-summary': '/ai/analyze/follow-up-summary',
+};
+
+export interface SseCallbacks {
+ onChunk: (content: string, index: number) => void;
+ onError: (message: string) => void;
+ onDone: (analysisId: string) => void;
+}
+
+export async function startAnalysis(
+ type: AnalysisType,
+ body: AnalyzeBody,
+ callbacks: SseCallbacks,
+): Promise {
+ const controller = new AbortController();
+ const endpoint = ENDPOINT_MAP[type];
+
+ const token = localStorage.getItem('hms-token');
+ const resp = await fetch(`/api/v1${endpoint}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify(body),
+ signal: controller.signal,
+ });
+
+ if (!resp.ok) {
+ const err = await resp.json().catch(() => ({ message: '分析请求失败' }));
+ callbacks.onError(err?.message || `HTTP ${resp.status}`);
+ return controller;
+ }
+
+ const reader = resp.body?.getReader();
+ if (!reader) {
+ callbacks.onError('无法读取响应流');
+ return controller;
+ }
+
+ const decoder = new TextDecoder();
+ let chunkIndex = 0;
+ let buffer = '';
+
+ (async () => {
+ try {
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split('\n');
+ buffer = lines.pop() || '';
+
+ for (const line of lines) {
+ if (line.startsWith('data: ')) {
+ const data = line.slice(6);
+ if (data === '[DONE]') {
+ continue;
+ }
+ try {
+ const event = JSON.parse(data);
+ if (event.type === 'chunk' && event.content) {
+ callbacks.onChunk(event.content, chunkIndex++);
+ } else if (event.type === 'done' && event.analysis_id) {
+ callbacks.onDone(event.analysis_id);
+ } else if (event.type === 'error') {
+ callbacks.onError(event.message || '分析出错');
+ }
+ } catch {
+ // 非 JSON 行,跳过
+ }
+ }
+ }
+ }
+ } catch (err) {
+ if (!controller.signal.aborted) {
+ callbacks.onError(err instanceof Error ? err.message : '连接中断');
+ }
+ }
+ })();
+
+ return controller;
+}
diff --git a/apps/web/src/api/ai/chat.ts b/apps/web/src/api/ai/chat.ts
new file mode 100644
index 0000000..b303e82
--- /dev/null
+++ b/apps/web/src/api/ai/chat.ts
@@ -0,0 +1,118 @@
+import client from '../client';
+
+export interface ChatHistoryItem {
+ role: 'user' | 'assistant';
+ content: string;
+}
+
+export type DisplayHint =
+ | {
+ type: 'vital_card';
+ indicator_type: string;
+ values: [string, number][];
+ unit: string;
+ }
+ | {
+ type: 'lab_report_card';
+ report_date: string;
+ abnormal_count: number;
+ }
+ | {
+ type: 'action_confirm';
+ action_type: string;
+ summary: string;
+ confirm_payload: unknown;
+ }
+ | {
+ type: 'risk_alert';
+ level: string;
+ message: string;
+ }
+ | {
+ type: 'trend_chart';
+ metrics: string[];
+ period: string;
+ summary: string;
+ }
+ | {
+ type: 'insight_card';
+ title: string;
+ severity: string;
+ items: string[];
+ }
+ | {
+ type: 'patient_profile';
+ chronic_conditions: string[];
+ medication_count: number;
+ }
+ | { type: 'text' };
+
+export interface ChatResponse {
+ reply: string;
+ message_id: string;
+ iterations: number;
+ display_hints?: DisplayHint[];
+}
+
+export interface ChatSession {
+ id: string;
+ title: string | null;
+ patient_id: string | null;
+ status: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export const aiChatApi = {
+ sendMessage: async (
+ message: string,
+ history: ChatHistoryItem[],
+ patientId?: string,
+ sessionId?: string
+ ): Promise => {
+ const resp = await client.post('/ai/chat', {
+ message,
+ history,
+ ...(patientId ? { patient_id: patientId } : {}),
+ ...(sessionId ? { session_id: sessionId } : {}),
+ });
+ return resp.data.data as ChatResponse;
+ },
+
+ createSession: async (
+ patientId?: string,
+ title?: string
+ ): Promise => {
+ const resp = await client.post('/ai/chat/sessions', {
+ ...(patientId ? { patient_id: patientId } : {}),
+ ...(title ? { title } : {}),
+ });
+ return resp.data.data as ChatSession;
+ },
+
+ listSessions: async (): Promise => {
+ const resp = await client.get('/ai/chat/sessions');
+ return resp.data.data as ChatSession[];
+ },
+
+ renameSession: async (
+ sessionId: string,
+ title: string
+ ): Promise => {
+ await client.put(`/ai/chat/sessions/${sessionId}/rename`, { title });
+ },
+
+ closeSession: async (sessionId: string): Promise => {
+ await client.post(`/ai/chat/sessions/${sessionId}/close`);
+ },
+
+ getSessionMessages: async (sessionId: string): Promise> => {
+ const resp = await client.get(`/ai/chat/sessions/${sessionId}/messages`);
+ return resp.data.data;
+ },
+};
diff --git a/apps/web/src/api/ai/config.ts b/apps/web/src/api/ai/config.ts
new file mode 100644
index 0000000..e371755
--- /dev/null
+++ b/apps/web/src/api/ai/config.ts
@@ -0,0 +1,45 @@
+import client from '../client';
+
+export interface AiAgentConfig {
+ model: string;
+ temperature: number;
+ max_tokens: number;
+ max_iterations: number;
+ system_prompt: string;
+}
+
+export interface AiAnalysisDefaults {
+ model: string;
+ temperature: number;
+ max_tokens: number;
+}
+
+export interface AiProviderConfig {
+ provider_type: string;
+ enabled: boolean;
+ base_url: string;
+ api_key: string;
+ model: string;
+}
+
+export interface AiConfig {
+ agent: AiAgentConfig;
+ analysis_defaults: AiAnalysisDefaults;
+ default_provider: string;
+ providers: Record;
+}
+
+export const aiConfigApi = {
+ get: async () => {
+ const resp = await client.get('/ai/config');
+ return resp.data.data as AiConfig;
+ },
+ getDefaults: async () => {
+ const resp = await client.get('/ai/config/defaults');
+ return resp.data.data as AiConfig;
+ },
+ update: async (config: AiConfig) => {
+ const resp = await client.put('/ai/config', { config });
+ return resp.data.data as AiConfig;
+ },
+};
diff --git a/apps/web/src/api/ai/dialysis.ts b/apps/web/src/api/ai/dialysis.ts
new file mode 100644
index 0000000..70268ab
--- /dev/null
+++ b/apps/web/src/api/ai/dialysis.ts
@@ -0,0 +1,23 @@
+import client from '../client';
+
+export interface DialysisRiskRequest {
+ patient_id: string;
+ dialysis_session_id?: string;
+}
+
+export interface DialysisRiskAssessment {
+ id: string;
+ patient_id: string;
+ risk_level: string;
+ risk_factors: string[];
+ recommendations: string[];
+ kdigo_stage?: string;
+ created_at: string;
+}
+
+export const dialysisRiskApi = {
+ assess: async (data: DialysisRiskRequest) => {
+ const resp = await client.post('/ai/dialysis/risk-assessment', data);
+ return resp.data.data as DialysisRiskAssessment;
+ },
+};
diff --git a/apps/web/src/api/ai/knowledgeV2.ts b/apps/web/src/api/ai/knowledgeV2.ts
new file mode 100644
index 0000000..3a1ba31
--- /dev/null
+++ b/apps/web/src/api/ai/knowledgeV2.ts
@@ -0,0 +1,188 @@
+import client from '../client';
+
+// === Types ===
+
+export interface KnowledgeBase {
+ id: string;
+ tenant_id: string;
+ name: string;
+ kb_type: string;
+ description: string | null;
+ icon: string | null;
+ chunk_strategy: Record;
+ intent_keywords: Record;
+ embedding_model: string | null;
+ is_enabled: boolean;
+ document_count: number;
+ chunk_count: number;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface KnowledgeDocument {
+ id: string;
+ tenant_id: string;
+ knowledge_base_id: string;
+ title: string;
+ doc_type: string;
+ source_type: string;
+ source_url: string | null;
+ file_name: string | null;
+ file_size: number | null;
+ file_mime_type: string | null;
+ content: string | null;
+ status: string;
+ chunk_count: number;
+ embedded_count: number;
+ error_message: string | null;
+ processing_started_at: string | null;
+ processing_completed_at: string | null;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface SearchHit {
+ chunk_id: string;
+ document_id: string;
+ chunk_index: number;
+ content: string;
+ doc_title: string;
+ similarity: number;
+ metadata: Record;
+}
+
+export interface CreateKnowledgeBaseReq {
+ name: string;
+ kb_type: string;
+ description?: string;
+ icon?: string;
+ chunk_strategy?: Record;
+ intent_keywords?: Record;
+ embedding_model?: string;
+ is_enabled?: boolean;
+}
+
+export interface UpdateKnowledgeBaseReq {
+ name?: string;
+ kb_type?: string;
+ description?: string;
+ icon?: string;
+ chunk_strategy?: Record;
+ intent_keywords?: Record;
+ embedding_model?: string;
+ is_enabled?: boolean;
+}
+
+export interface CreateDocumentReq {
+ kb_id: string;
+ title: string;
+ doc_type?: string;
+ source_type?: string;
+ source_url?: string;
+ content?: string;
+}
+
+// === API ===
+
+export const knowledgeV2Api = {
+ // Knowledge Bases
+ listKnowledgeBases: async (params?: {
+ kb_type?: string;
+ is_enabled?: boolean;
+ page?: number;
+ page_size?: number;
+ }) => {
+ const resp = await client.get('/ai/knowledge-bases', { params });
+ return resp.data.data as {
+ data: KnowledgeBase[];
+ total: number;
+ page: number;
+ page_size: number;
+ };
+ },
+
+ getKnowledgeBase: async (id: string) => {
+ const resp = await client.get(`/ai/knowledge-bases/${id}`);
+ return resp.data.data as KnowledgeBase;
+ },
+
+ createKnowledgeBase: async (data: CreateKnowledgeBaseReq) => {
+ const resp = await client.post('/ai/knowledge-bases', data);
+ return resp.data.data as { id: string };
+ },
+
+ updateKnowledgeBase: async (id: string, data: UpdateKnowledgeBaseReq) => {
+ const resp = await client.put(`/ai/knowledge-bases/${id}`, data);
+ return resp.data.data as { id: string };
+ },
+
+ deleteKnowledgeBase: async (id: string) => {
+ const resp = await client.delete(`/ai/knowledge-bases/${id}`);
+ return resp.data.data as { id: string };
+ },
+
+ // Documents
+ listDocuments: async (
+ kbId: string,
+ params?: { status?: string; page?: number; page_size?: number },
+ ) => {
+ const resp = await client.get(
+ `/ai/knowledge-bases/${kbId}/documents`,
+ { params },
+ );
+ return resp.data.data as {
+ data: KnowledgeDocument[];
+ total: number;
+ page: number;
+ page_size: number;
+ };
+ },
+
+ getDocument: async (id: string) => {
+ const resp = await client.get(`/ai/documents/${id}`);
+ return resp.data.data as KnowledgeDocument;
+ },
+
+ createManualDocument: async (data: CreateDocumentReq) => {
+ const resp = await client.post('/ai/documents/manual', data);
+ return resp.data.data as { id: string };
+ },
+
+ uploadDocument: async (
+ kbId: string,
+ file: File,
+ title?: string,
+ ) => {
+ const formData = new FormData();
+ formData.append('kb_id', kbId);
+ formData.append('file', file);
+ if (title) {
+ formData.append('title', title);
+ }
+ const resp = await client.post('/ai/documents/upload', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ return resp.data.data as { id: string };
+ },
+
+ deleteDocument: async (kbId: string, id: string) => {
+ const resp = await client.delete(
+ `/ai/knowledge-bases/${kbId}/documents/${id}`,
+ );
+ return resp.data.data as { id: string };
+ },
+
+ // Hit Test
+ hitTest: async (kbId: string, query: string, topK?: number) => {
+ const resp = await client.post('/ai/documents/hit-test', {
+ kb_id: kbId,
+ query,
+ top_k: topK,
+ });
+ return resp.data.data as {
+ query: string;
+ total: number;
+ hits: SearchHit[];
+ };
+ },
+};
diff --git a/apps/web/src/api/ai/prompts.ts b/apps/web/src/api/ai/prompts.ts
new file mode 100644
index 0000000..a8fcc24
--- /dev/null
+++ b/apps/web/src/api/ai/prompts.ts
@@ -0,0 +1,54 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+export interface PromptItem {
+ id: string;
+ name: string;
+ description: string;
+ system_prompt: string;
+ user_prompt_template: string;
+ model_config: Record;
+ version: number;
+ is_active: boolean;
+ category: string;
+ analysis_type: string;
+ tags: Record | null;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface CreatePromptReq {
+ name: string;
+ description?: string;
+ system_prompt: string;
+ user_prompt_template: string;
+ model_config: Record;
+ category: string;
+ analysis_type: string;
+}
+
+export const promptApi = {
+ list: async (params?: { category?: string; analysis_type?: string; page?: number; page_size?: number }) => {
+ const resp = await client.get('/ai/prompts', { params });
+ return resp.data.data as PaginatedResponse;
+ },
+ create: async (data: CreatePromptReq) => {
+ const resp = await client.post('/ai/prompts', data);
+ return resp.data.data as PromptItem;
+ },
+ activate: async (id: string) => {
+ const resp = await client.post(`/ai/prompts/${id}/activate`);
+ return resp.data.data as PromptItem;
+ },
+ deactivate: async (id: string) => {
+ const resp = await client.post(`/ai/prompts/${id}/deactivate`);
+ return resp.data.data as PromptItem;
+ },
+ rollback: async (id: string) => {
+ const resp = await client.post(`/ai/prompts/${id}/rollback`);
+ return resp.data.data as PromptItem;
+ },
+ delete: async (id: string) => {
+ await client.delete(`/ai/prompts/${id}`);
+ },
+};
diff --git a/apps/web/src/api/ai/suggestions.ts b/apps/web/src/api/ai/suggestions.ts
new file mode 100644
index 0000000..5e351fc
--- /dev/null
+++ b/apps/web/src/api/ai/suggestions.ts
@@ -0,0 +1,38 @@
+import client from '../client';
+
+export interface SuggestionItem {
+ id: string;
+ analysis_id: string;
+ suggestion_type: string;
+ risk_level: string;
+ params: Record | null;
+ status: string;
+ created_at: string;
+}
+
+export interface ComparisonReport {
+ suggestion_id: string;
+ baseline: Record | null;
+ current: Record | null;
+ comparison_available: boolean;
+ message?: string;
+}
+
+export const suggestionApi = {
+ list: async (params?: { analysis_id?: string; status?: string }) => {
+ const resp = await client.get('/ai/suggestions', { params });
+ return resp.data.data as { data: SuggestionItem[]; total: number };
+ },
+ approve: async (id: string, action: 'approve' | 'reject') => {
+ const resp = await client.post(`/ai/suggestions/${id}/approve`, { action });
+ return resp.data.data as { id: string; status: string };
+ },
+ execute: async (id: string) => {
+ const resp = await client.post(`/ai/suggestions/${id}/execute`);
+ return resp.data.data as { id: string; status: string };
+ },
+ getComparison: async (id: string) => {
+ const resp = await client.get(`/ai/suggestions/${id}/comparison`);
+ return resp.data.data as ComparisonReport;
+ },
+};
diff --git a/apps/web/src/api/ai/usage.ts b/apps/web/src/api/ai/usage.ts
new file mode 100644
index 0000000..5b91f63
--- /dev/null
+++ b/apps/web/src/api/ai/usage.ts
@@ -0,0 +1,107 @@
+import client from '../client';
+
+export interface UsageOverview {
+ total_count: number;
+}
+
+export interface TypeDistribution {
+ analysis_type: string;
+ count: number;
+}
+
+export interface ProviderInfo {
+ id: string;
+ name: string;
+ provider_type: string;
+ is_active: boolean;
+ model_name?: string;
+}
+
+export interface ProviderHealth {
+ provider_id: string;
+ status: string;
+ latency_ms?: number;
+ last_checked_at?: string;
+}
+
+export interface QuotaSummary {
+ provider_id: string;
+ quota_limit: number;
+ quota_used: number;
+ quota_remaining: number;
+ period: string;
+}
+
+export interface BudgetStatus {
+ total_budget: number;
+ spent: number;
+ remaining: number;
+ period: string;
+}
+
+export interface CostEstimate {
+ analysis_type: string;
+ estimated_cost: number;
+ currency: string;
+}
+
+export interface DailyUsageRow {
+ date: string;
+ feature: string;
+ provider: string;
+ model: string;
+ total_calls: number;
+ total_input_tokens: number;
+ total_output_tokens: number;
+ total_cost_cents: number;
+}
+
+export interface FeatureFlag {
+ feature: string;
+ is_enabled: boolean;
+}
+
+export const usageApi = {
+ overview: async () => {
+ const resp = await client.get('/ai/usage/overview');
+ return resp.data.data as UsageOverview;
+ },
+ byType: async () => {
+ const resp = await client.get('/ai/usage/by-type');
+ return resp.data.data as TypeDistribution[];
+ },
+ listProviders: async () => {
+ const resp = await client.get('/ai/providers');
+ return resp.data.data as ProviderInfo[];
+ },
+ getProvidersHealth: async () => {
+ const resp = await client.get('/ai/providers/health');
+ return resp.data.data as ProviderHealth[];
+ },
+ getQuotaSummary: async () => {
+ const resp = await client.get('/ai/quota/summary');
+ return resp.data.data as QuotaSummary[];
+ },
+ getBudgetStatus: async () => {
+ const resp = await client.get('/ai/budget/status');
+ return resp.data.data as BudgetStatus;
+ },
+ getCostEstimate: async (params: { analysis_type: string }) => {
+ const resp = await client.get('/ai/cost/estimate', { params });
+ return resp.data.data as CostEstimate;
+ },
+ getDailyUsage: async (startDate: string, endDate: string) => {
+ const resp = await client.get('/ai/admin/daily-usage', {
+ params: { start_date: startDate, end_date: endDate },
+ });
+ return resp.data.data as DailyUsageRow[];
+ },
+ getFeatureFlags: async () => {
+ const resp = await client.get('/ai/admin/flags');
+ return resp.data.data as FeatureFlag[];
+ },
+ updateFeatureFlag: async (feature: string, enabled: boolean) => {
+ const resp = await client.post('/ai/admin/flags', { feature, enabled });
+ return resp.data.data as { feature: string; enabled: boolean };
+ },
+};
diff --git a/apps/web/src/api/auditLogs.test.ts b/apps/web/src/api/auditLogs.test.ts
new file mode 100644
index 0000000..1a71084
--- /dev/null
+++ b/apps/web/src/api/auditLogs.test.ts
@@ -0,0 +1,51 @@
+/**
+ * auditLogs API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as auditLogsApi from './auditLogs'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('auditLogs API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listAuditLogs 应调用 GET /audit-logs 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await auditLogsApi.listAuditLogs({ resource_type: 'user', user_id: 'u-001', page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/audit-logs', {
+ params: expect.objectContaining({
+ resource_type: 'user',
+ user_id: 'u-001',
+ page: 1,
+ page_size: 10,
+ }),
+ })
+ })
+
+ it('listAuditLogs 默认应传 page=1 page_size=20', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await auditLogsApi.listAuditLogs()
+
+ expect(mockGet).toHaveBeenCalledWith('/audit-logs', {
+ params: expect.objectContaining({ page: 1, page_size: 20 }),
+ })
+ })
+})
diff --git a/apps/web/src/api/auditLogs.ts b/apps/web/src/api/auditLogs.ts
new file mode 100644
index 0000000..92be6cc
--- /dev/null
+++ b/apps/web/src/api/auditLogs.ts
@@ -0,0 +1,31 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface AuditLogItem {
+ id: string;
+ tenant_id: string;
+ action: string;
+ resource_type: string;
+ resource_id: string;
+ user_id: string;
+ old_value?: string;
+ new_value?: string;
+ ip_address?: string;
+ user_agent?: string;
+ created_at: string;
+}
+
+export interface AuditLogQuery {
+ resource_type?: string;
+ user_id?: string;
+ page?: number;
+ page_size?: number;
+}
+
+export async function listAuditLogs(query: AuditLogQuery = {}) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/audit-logs',
+ { params: { page: query.page ?? 1, page_size: query.page_size ?? 20, ...query } },
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/auth.test.ts b/apps/web/src/api/auth.test.ts
new file mode 100644
index 0000000..5a68920
--- /dev/null
+++ b/apps/web/src/api/auth.test.ts
@@ -0,0 +1,55 @@
+/**
+ * auth API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as authApi from './auth'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('auth API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('login 应调用 POST /auth/login 并传递用户名密码', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await authApi.login({ username: 'admin', password: '123456' })
+
+ expect(mockPost).toHaveBeenCalledWith('/auth/login', {
+ username: 'admin',
+ password: '123456',
+ })
+ })
+
+ it('logout 应调用 POST /auth/logout', async () => {
+ mockPost.mockResolvedValue(undefined)
+ await authApi.logout()
+
+ expect(mockPost).toHaveBeenCalledWith('/auth/logout')
+ })
+
+ it('changePassword 应调用 POST /auth/change-password', async () => {
+ mockPost.mockResolvedValue(undefined)
+ await authApi.changePassword('oldPass', 'newPass')
+
+ expect(mockPost).toHaveBeenCalledWith('/auth/change-password', {
+ current_password: 'oldPass',
+ new_password: 'newPass',
+ })
+ })
+})
diff --git a/apps/web/src/api/auth.ts b/apps/web/src/api/auth.ts
new file mode 100644
index 0000000..98cb7f7
--- /dev/null
+++ b/apps/web/src/api/auth.ts
@@ -0,0 +1,55 @@
+import client from './client';
+
+export interface LoginRequest {
+ username: string;
+ password: string;
+}
+
+export interface UserInfo {
+ id: string;
+ username: string;
+ email?: string;
+ phone?: string;
+ display_name?: string;
+ avatar_url?: string;
+ status: string;
+ roles: RoleInfo[];
+ version: number;
+}
+
+export interface RoleInfo {
+ id: string;
+ name: string;
+ code: string;
+ description?: string;
+ is_system: boolean;
+}
+
+export interface LoginResponse {
+ access_token: string;
+ refresh_token: string;
+ expires_in: number;
+ user: UserInfo;
+}
+
+export async function login(req: LoginRequest): Promise {
+ const { data } = await client.post<{ success: boolean; data: LoginResponse }>(
+ '/auth/login',
+ req
+ );
+ return data.data;
+}
+
+export async function logout(): Promise {
+ await client.post('/auth/logout');
+}
+
+export async function changePassword(
+ currentPassword: string,
+ newPassword: string
+): Promise {
+ await client.post('/auth/change-password', {
+ current_password: currentPassword,
+ new_password: newPassword,
+ });
+}
diff --git a/apps/web/src/api/client.ts b/apps/web/src/api/client.ts
new file mode 100644
index 0000000..c568930
--- /dev/null
+++ b/apps/web/src/api/client.ts
@@ -0,0 +1,261 @@
+import axios from "axios";
+import { message as antMessage } from "antd";
+
+// 请求缓存:短时间内相同请求复用结果
+interface CacheEntry {
+ data: unknown;
+ timestamp: number;
+}
+
+const requestCache = new Map();
+const CACHE_TTL = 5000; // 5 秒缓存
+
+function getCacheKey(config: {
+ url?: string;
+ params?: unknown;
+ method?: string;
+}): string {
+ return `${config.method || "get"}:${config.url || ""}:${JSON.stringify(config.params || {})}`;
+}
+
+const defaultAdapter = axios.getAdapter(axios.defaults.adapter);
+
+const client = axios.create({
+ baseURL: "/api/v1",
+ timeout: 10000,
+ headers: { "Content-Type": "application/json" },
+ adapter: (config) => {
+ // GET 请求检查缓存
+ if (config.method === "get" && config.url) {
+ const key = getCacheKey(config);
+ const entry = requestCache.get(key);
+ if (entry && Date.now() - entry.timestamp < CACHE_TTL) {
+ return Promise.resolve({
+ data: entry.data,
+ status: 200,
+ statusText: "OK (cached)",
+ headers: new axios.AxiosHeaders(),
+ config,
+ });
+ }
+ }
+ return defaultAdapter(config);
+ },
+});
+
+// Decode JWT payload without external library
+function decodeJwtPayload(
+ token: string,
+): { exp?: number; sub?: string } | null {
+ try {
+ const parts = token.split(".");
+ if (parts.length !== 3) return null;
+ const payload = JSON.parse(
+ atob(parts[1].replace(/-/g, "+").replace(/_/g, "/")),
+ );
+ return payload;
+ } catch {
+ return null;
+ }
+}
+
+// Check if token is expired or about to expire (within 30s buffer)
+function isTokenExpiringSoon(token: string): boolean {
+ const payload = decodeJwtPayload(token);
+ if (!payload?.exp) return true;
+ return Date.now() / 1000 > payload.exp - 30;
+}
+
+// Request interceptor: attach access token + proactive refresh
+client.interceptors.request.use(async (config) => {
+ const token = localStorage.getItem("access_token");
+ if (token) {
+ // If token is about to expire, proactively refresh before sending the request
+ if (isTokenExpiringSoon(token)) {
+ const refreshToken = localStorage.getItem("refresh_token");
+ if (refreshToken && !isRefreshing) {
+ isRefreshing = true;
+ try {
+ const { data } = await axios.post("/api/v1/auth/refresh", {
+ refresh_token: refreshToken,
+ });
+ const newAccess = data.data.access_token;
+ const newRefresh = data.data.refresh_token;
+
+ // 验证新 token 的用户身份一致
+ const currentUserSub = decodeJwtPayload(token)?.sub;
+ const newTokenSub = decodeJwtPayload(newAccess)?.sub;
+ if (currentUserSub && newTokenSub && currentUserSub !== newTokenSub) {
+ localStorage.removeItem("access_token");
+ localStorage.removeItem("refresh_token");
+ localStorage.removeItem("user");
+ window.location.hash = "/login";
+ return Promise.reject(new Error("身份验证失败,请重新登录"));
+ }
+
+ localStorage.setItem("access_token", newAccess);
+ localStorage.setItem("refresh_token", newRefresh);
+ processQueue(null, newAccess);
+ config.headers.Authorization = `Bearer ${newAccess}`;
+ return config;
+ } catch {
+ processQueue(new Error("refresh failed"), null);
+ // Continue with old token, let 401 handler deal with it
+ } finally {
+ isRefreshing = false;
+ }
+ }
+ }
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+
+ return config;
+});
+
+// 响应拦截器:缓存 GET 响应 + 自动刷新 token
+client.interceptors.response.use(
+ (response) => {
+ // 缓存 GET 响应
+ if (response.config.method === "get" && response.config.url) {
+ const key = getCacheKey(response.config);
+ requestCache.set(key, { data: response.data, timestamp: Date.now() });
+ }
+ return response;
+ },
+ async (error) => {
+ const originalRequest = error.config;
+ if (
+ error.response?.status === 401 &&
+ !originalRequest._retry &&
+ !originalRequest.url?.includes("/auth/login")
+ ) {
+ if (isRefreshing) {
+ return new Promise((resolve, reject) => {
+ failedQueue.push({ resolve, reject });
+ }).then((token) => {
+ originalRequest.headers.Authorization = `Bearer ${token}`;
+ return client(originalRequest);
+ });
+ }
+
+ originalRequest._retry = true;
+ isRefreshing = true;
+
+ try {
+ const refreshToken = localStorage.getItem("refresh_token");
+ if (!refreshToken) throw new Error("No refresh token");
+
+ const { data } = await axios.post("/api/v1/auth/refresh", {
+ refresh_token: refreshToken,
+ });
+
+ const newAccessToken = data.data.access_token;
+ const newRefreshToken = data.data.refresh_token;
+
+ // 验证新 token 的用户身份与当前用户一致,防止并发场景下身份切换
+ const currentToken = localStorage.getItem("access_token");
+ const currentUserSub = currentToken
+ ? decodeJwtPayload(currentToken)?.sub
+ : null;
+ const newTokenSub = decodeJwtPayload(newAccessToken)?.sub;
+ if (currentUserSub && newTokenSub && currentUserSub !== newTokenSub) {
+ // 身份不一致,强制登出
+ localStorage.removeItem("access_token");
+ localStorage.removeItem("refresh_token");
+ localStorage.removeItem("user");
+ window.location.hash = "/login";
+ return Promise.reject(new Error("身份验证失败,请重新登录"));
+ }
+
+ localStorage.setItem("access_token", newAccessToken);
+ localStorage.setItem("refresh_token", newRefreshToken);
+
+ processQueue(null, newAccessToken);
+
+ originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
+ return client(originalRequest);
+ } catch (refreshError) {
+ processQueue(refreshError, null);
+ localStorage.removeItem("access_token");
+ localStorage.removeItem("refresh_token");
+ window.location.hash = "/login";
+ return Promise.reject(refreshError);
+ } finally {
+ isRefreshing = false;
+ }
+ }
+
+ return Promise.reject(error);
+ },
+);
+
+// 全局错误提示(仅对未被组件处理的错误显示)
+let globalErrorTimer: ReturnType | null = null;
+function showGlobalError(msg: string) {
+ // 防止短时间内弹出大量相同提示
+ if (globalErrorTimer) return;
+ antMessage.error(msg, 3);
+ globalErrorTimer = setTimeout(() => {
+ globalErrorTimer = null;
+ }, 3000);
+}
+
+// 全局错误拦截 — 在响应拦截器之后、组件 catch 之前执行
+// 组件可通过 axios config 中设置 skipGlobalError: true 来抑制全局提示
+declare module "axios" {
+ interface AxiosRequestConfig {
+ skipGlobalError?: boolean;
+ }
+ interface InternalAxiosRequestConfig {
+ skipGlobalError?: boolean;
+ }
+}
+
+client.interceptors.response.use(
+ (response) => response,
+ (error) => {
+ if (error.config?.skipGlobalError) {
+ return Promise.reject(error);
+ }
+ if (!error.response) {
+ showGlobalError("网络连接异常,请检查网络");
+ } else if (error.response.status === 403) {
+ // 403 通常是权限不足,不全局提示 — 组件层通过 AuthButton 已隐藏操作入口
+ } else if (error.response.status === 404) {
+ // 404 通常由组件自行处理(如跳转),不全局提示
+ } else if (error.response.status >= 500) {
+ showGlobalError("服务器异常,请稍后重试");
+ }
+ return Promise.reject(error);
+ },
+);
+
+let isRefreshing = false;
+let failedQueue: Array<{
+ resolve: (token: string) => void;
+ reject: (error: unknown) => void;
+}> = [];
+
+function processQueue(error: unknown, token: string | null) {
+ failedQueue.forEach(({ resolve, reject }) => {
+ if (token) resolve(token);
+ else reject(error);
+ });
+ failedQueue = [];
+}
+
+// 清除缓存(登录/登出时调用)
+export function clearApiCache() {
+ requestCache.clear();
+}
+
+// 通用错误处理:提取后端错误消息并展示
+export function handleApiError(err: unknown, fallback = "操作失败"): string {
+ const msg =
+ (err as { response?: { data?: { message?: string } } })?.response?.data
+ ?.message || fallback;
+ antMessage.error(msg);
+ return msg;
+}
+
+export default client;
diff --git a/apps/web/src/api/config-modules.test.ts b/apps/web/src/api/config-modules.test.ts
new file mode 100644
index 0000000..f051af7
--- /dev/null
+++ b/apps/web/src/api/config-modules.test.ts
@@ -0,0 +1,197 @@
+/**
+ * config-modules API 契约测试(menus + settings + languages + numberingRules + themes)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as menusApi from './menus'
+import * as settingsApi from './settings'
+import * as languagesApi from './languages'
+import * as numberingApi from './numberingRules'
+import * as themesApi from './themes'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+// ============================================================
+// menus
+// ============================================================
+describe('menus API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('getMenus 应调用 GET /config/menus', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await menusApi.getMenus()
+
+ expect(mockGet).toHaveBeenCalledWith('/config/menus')
+ })
+
+ it('getMenusForUser 应调用 GET /menus/user', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await menusApi.getMenusForUser()
+
+ expect(mockGet).toHaveBeenCalledWith('/menus/user')
+ })
+
+ it('batchSaveMenus 应调用 PUT /config/menus 并传递 menus 数组', async () => {
+ mockPut.mockResolvedValue(undefined)
+ const menus = [{ title: '仪表盘', path: '/dashboard' }]
+ await menusApi.batchSaveMenus(menus)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/menus', { menus })
+ })
+
+ it('createMenu 应调用 POST /config/menus', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { title: '新菜单', path: '/new', sort_order: 10 }
+ await menusApi.createMenu(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/config/menus', req)
+ })
+
+ it('deleteMenu 应调用 DELETE /config/menus/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await menusApi.deleteMenu('menu-001', 3)
+
+ expect(mockDelete).toHaveBeenCalledWith('/config/menus/menu-001', { data: { version: 3 } })
+ })
+})
+
+// ============================================================
+// settings
+// ============================================================
+describe('settings API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('getSetting 应调用 GET /config/settings/:key 并传递 scope 参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await settingsApi.getSetting('site.name', 'global', 'org-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/config/settings/site.name', {
+ params: { scope: 'global', scope_id: 'org-001' },
+ })
+ })
+
+ it('updateSetting 应调用 PUT /config/settings/:key', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await settingsApi.updateSetting('site.name', '新名称', 1)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/settings/site.name', {
+ setting_value: '新名称',
+ version: 1,
+ })
+ })
+
+ it('deleteSetting 应调用 DELETE /config/settings/:key', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await settingsApi.deleteSetting('site.name', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/config/settings/site.name', { data: { version: 2 } })
+ })
+})
+
+// ============================================================
+// languages
+// ============================================================
+describe('languages API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listLanguages 应调用 GET /config/languages', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await languagesApi.listLanguages()
+
+ expect(mockGet).toHaveBeenCalledWith('/config/languages')
+ })
+
+ it('updateLanguage 应调用 PUT /config/languages/:code', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await languagesApi.updateLanguage('zh-CN', { is_active: true, name: '简体中文' })
+
+ expect(mockPut).toHaveBeenCalledWith('/config/languages/zh-CN', {
+ is_active: true,
+ name: '简体中文',
+ })
+ })
+})
+
+// ============================================================
+// numberingRules
+// ============================================================
+describe('numberingRules API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listNumberingRules 应调用 GET /config/numbering-rules', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await numberingApi.listNumberingRules(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/config/numbering-rules', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createNumberingRule 应调用 POST /config/numbering-rules', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '患者编号', code: 'patient', prefix: 'P', seq_length: 6 }
+ await numberingApi.createNumberingRule(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/config/numbering-rules', req)
+ })
+
+ it('updateNumberingRule 应调用 PUT /config/numbering-rules/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { prefix: 'HMS', version: 1 }
+ await numberingApi.updateNumberingRule('nr-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/numbering-rules/nr-001', req)
+ })
+
+ it('generateNumber 应调用 POST /config/numbering-rules/:id/generate', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await numberingApi.generateNumber('nr-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/config/numbering-rules/nr-001/generate')
+ })
+
+ it('deleteNumberingRule 应调用 DELETE /config/numbering-rules/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await numberingApi.deleteNumberingRule('nr-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/config/numbering-rules/nr-001', { data: { version: 1 } })
+ })
+})
+
+// ============================================================
+// themes
+// ============================================================
+describe('themes API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('getTheme 应调用 GET /config/themes', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await themesApi.getTheme()
+
+ expect(mockGet).toHaveBeenCalledWith('/config/themes')
+ })
+
+ it('updateTheme 应调用 PUT /config/themes', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const theme = { primary_color: '#1890ff', brand_name: 'HMS' }
+ await themesApi.updateTheme(theme)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/themes', theme)
+ })
+})
diff --git a/apps/web/src/api/copilot.ts b/apps/web/src/api/copilot.ts
new file mode 100644
index 0000000..535e48e
--- /dev/null
+++ b/apps/web/src/api/copilot.ts
@@ -0,0 +1,66 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+// --- Types ---
+
+export type InsightType = 'risk_score' | 'anomaly' | 'follow_up_hint' | 'consult_hint';
+export type InsightSource = 'rule' | 'llm' | 'hybrid';
+export type RiskLevel = 'low' | 'medium' | 'high' | 'critical';
+
+export interface MatchedRule {
+ rule_id: string;
+ name: string;
+ score: number;
+ severity: string;
+ suggestion?: string;
+}
+
+export interface RiskScore {
+ score: number;
+ level: RiskLevel;
+ matched_rules: MatchedRule[];
+}
+
+export interface CopilotInsight {
+ id: string;
+ patient_id: string;
+ insight_type: InsightType;
+ source: InsightSource;
+ severity: 'info' | 'warning' | 'critical';
+ title: string;
+ content: Record;
+ rule_matches?: MatchedRule[];
+ llm_supplement?: string;
+ created_at: string;
+}
+
+// --- API Functions ---
+
+export async function getPatientRisk(patientId: string) {
+ const { data } = await client.get<{ success: boolean; data: RiskScore }>(`/copilot/patients/${patientId}/risk`);
+ return data.data;
+}
+
+export async function listInsights(params: {
+ patient_id?: string;
+ insight_type?: string;
+ severity?: string;
+ page?: number;
+ page_size?: number;
+}) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>('/copilot/insights', { params });
+ return data.data;
+}
+
+export function dismissInsight(id: string) {
+ return client.post(`/copilot/insights/${id}/dismiss`);
+}
+
+export function listAlerts(params?: { severity?: string; page?: number; page_size?: number }) {
+ return listInsights({ insight_type: 'anomaly', ...params });
+}
+
+export async function listRules(params?: { page?: number; page_size?: number }) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse> }>('/copilot/rules', { params });
+ return data.data;
+}
diff --git a/apps/web/src/api/dictionaries.test.ts b/apps/web/src/api/dictionaries.test.ts
new file mode 100644
index 0000000..a0000a6
--- /dev/null
+++ b/apps/web/src/api/dictionaries.test.ts
@@ -0,0 +1,96 @@
+/**
+ * dictionaries API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as dictApi from './dictionaries'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('dictionaries API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listDictionaries 应调用 GET /config/dictionaries 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dictApi.listDictionaries(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/config/dictionaries', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createDictionary 应调用 POST /config/dictionaries', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '性别', code: 'gender', description: '性别字典' }
+ await dictApi.createDictionary(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/config/dictionaries', req)
+ })
+
+ it('updateDictionary 应调用 PUT /config/dictionaries/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '性别(更新)', version: 1 }
+ await dictApi.updateDictionary('dict-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/dictionaries/dict-001', req)
+ })
+
+ it('deleteDictionary 应调用 DELETE /config/dictionaries/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await dictApi.deleteDictionary('dict-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/config/dictionaries/dict-001', {
+ data: { version: 2 },
+ })
+ })
+
+ it('listItemsByCode 应调用 GET /config/dictionaries/items 并传递 code 参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dictApi.listItemsByCode('gender')
+
+ expect(mockGet).toHaveBeenCalledWith('/config/dictionaries/items', {
+ params: { code: 'gender' },
+ })
+ })
+
+ it('createDictionaryItem 应调用 POST /config/dictionaries/:id/items', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { label: '男', value: 'male', sort_order: 1 }
+ await dictApi.createDictionaryItem('dict-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/config/dictionaries/dict-001/items', req)
+ })
+
+ it('updateDictionaryItem 应调用 PUT /config/dictionaries/:dictId/items/:itemId', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { label: '女', version: 1 }
+ await dictApi.updateDictionaryItem('dict-001', 'item-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/config/dictionaries/dict-001/items/item-001', req)
+ })
+
+ it('deleteDictionaryItem 应调用 DELETE /config/dictionaries/:dictId/items/:itemId', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await dictApi.deleteDictionaryItem('dict-001', 'item-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/config/dictionaries/dict-001/items/item-001', {
+ data: { version: 1 },
+ })
+ })
+})
diff --git a/apps/web/src/api/dictionaries.ts b/apps/web/src/api/dictionaries.ts
new file mode 100644
index 0000000..b44d443
--- /dev/null
+++ b/apps/web/src/api/dictionaries.ts
@@ -0,0 +1,111 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface DictionaryItemInfo {
+ id: string;
+ dictionary_id: string;
+ label: string;
+ value: string;
+ sort_order: number;
+ color?: string;
+ version: number;
+}
+
+export interface DictionaryInfo {
+ id: string;
+ name: string;
+ code: string;
+ description?: string;
+ items: DictionaryItemInfo[];
+ version: number;
+}
+
+export interface CreateDictionaryRequest {
+ name: string;
+ code: string;
+ description?: string;
+}
+
+export interface UpdateDictionaryRequest {
+ name?: string;
+ description?: string;
+ version: number;
+}
+
+export async function listDictionaries(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/config/dictionaries',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function createDictionary(req: CreateDictionaryRequest) {
+ const { data } = await client.post<{ success: boolean; data: DictionaryInfo }>(
+ '/config/dictionaries',
+ req,
+ );
+ return data.data;
+}
+
+export async function updateDictionary(id: string, req: UpdateDictionaryRequest) {
+ const { data } = await client.put<{ success: boolean; data: DictionaryInfo }>(
+ `/config/dictionaries/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deleteDictionary(id: string, version: number) {
+ await client.delete(`/config/dictionaries/${id}`, { data: { version } });
+}
+
+export async function listItemsByCode(code: string) {
+ const { data } = await client.get<{ success: boolean; data: DictionaryItemInfo[] }>(
+ '/config/dictionaries/items',
+ { params: { code } },
+ );
+ return data.data;
+}
+
+export interface CreateDictionaryItemRequest {
+ label: string;
+ value: string;
+ sort_order?: number;
+ color?: string;
+}
+
+export interface UpdateDictionaryItemRequest {
+ label?: string;
+ value?: string;
+ sort_order?: number;
+ color?: string;
+ version: number;
+}
+
+export async function createDictionaryItem(
+ dictionaryId: string,
+ req: CreateDictionaryItemRequest,
+) {
+ const { data } = await client.post<{ success: boolean; data: DictionaryItemInfo }>(
+ `/config/dictionaries/${dictionaryId}/items`,
+ req,
+ );
+ return data.data;
+}
+
+export async function updateDictionaryItem(
+ dictionaryId: string,
+ itemId: string,
+ req: UpdateDictionaryItemRequest,
+) {
+ const { data } = await client.put<{ success: boolean; data: DictionaryItemInfo }>(
+ `/config/dictionaries/${dictionaryId}/items/${itemId}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deleteDictionaryItem(dictionaryId: string, itemId: string, version: number) {
+ await client.delete(`/config/dictionaries/${dictionaryId}/items/${itemId}`, { data: { version } });
+}
diff --git a/apps/web/src/api/health/actionInbox.ts b/apps/web/src/api/health/actionInbox.ts
new file mode 100644
index 0000000..951ba63
--- /dev/null
+++ b/apps/web/src/api/health/actionInbox.ts
@@ -0,0 +1,128 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+export type ActionType = 'ai_suggestion' | 'alert' | 'followup' | 'data_anomaly';
+export type ActionPriority = 'urgent' | 'high' | 'medium' | 'low';
+export type ActionStatus = 'pending' | 'in_progress' | 'completed' | 'dismissed';
+
+export interface ActionItem {
+ id: string;
+ action_type: ActionType;
+ priority: ActionPriority;
+ status: ActionStatus;
+ title: string;
+ summary: string;
+ patient_id: string;
+ patient_name: string;
+ source_ref: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface ThreadEvent {
+ step: string;
+ label: string;
+ status: ActionStatus;
+ detail?: string;
+ timestamp?: string;
+ operator?: string;
+ link_to?: string;
+}
+
+export interface ActionDefinition {
+ key: string;
+ label: string;
+ variant: 'primary' | 'danger' | 'default';
+ api_endpoint?: string;
+}
+
+export interface ThreadResponse {
+ action_item: ActionItem;
+ thread: ThreadEvent[];
+ available_actions: ActionDefinition[];
+}
+
+export interface WorkbenchStats {
+ total_pending: number;
+ ai_suggestion_pending: number;
+ urgent_alerts: number;
+ followup_due: number;
+ completion_rate: number | null;
+}
+
+export interface NursePatientSummary {
+ patient_id: string;
+ patient_name: string;
+ pending_actions: number;
+ highest_priority: ActionPriority;
+}
+
+export interface TeamMemberOverview {
+ user_id: string;
+ name: string;
+ title: string;
+ pending_count: number;
+ completed_count: number;
+ overdue_count: number;
+ completion_rate: number;
+}
+
+export interface TeamOverview {
+ members: TeamMemberOverview[];
+ risk_distribution: {
+ high: number;
+ medium: number;
+ low: number;
+ };
+ total_pending: number;
+ total_completed: number;
+}
+
+export const actionInboxApi = {
+ list: async (params?: {
+ status?: string;
+ type?: string;
+ page?: number;
+ page_size?: number;
+ assigned_to_me?: boolean;
+ patient_id?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/action-inbox', { params });
+ return data.data;
+ },
+
+ getThread: async (sourceRef: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: ThreadResponse;
+ }>(`/health/action-inbox/${encodeURIComponent(sourceRef)}/thread`);
+ return data.data;
+ },
+
+ stats: async (params?: { assigned_to_me?: boolean }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: WorkbenchStats;
+ }>('/health/action-inbox/stats', { params });
+ return data.data;
+ },
+
+ myPatients: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: NursePatientSummary[];
+ }>('/health/action-inbox/my-patients');
+ return data.data;
+ },
+
+ team: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: TeamOverview;
+ }>('/health/action-inbox/team');
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/alerts.test.ts b/apps/web/src/api/health/alerts.test.ts
new file mode 100644
index 0000000..716bbfc
--- /dev/null
+++ b/apps/web/src/api/health/alerts.test.ts
@@ -0,0 +1,100 @@
+/**
+ * alerts API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { alertApi, alertRuleApi } from './alerts'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('alertApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('list 应调用 GET /health/alerts 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await alertApi.list({ patient_id: 'p-001', status: 'active', page: 1, page_size: 20 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/alerts', {
+ params: { patient_id: 'p-001', status: 'active', page: 1, page_size: 20 },
+ })
+ })
+
+ it('acknowledge 应调用 PUT /health/alerts/:id/acknowledge 并传递 version', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await alertApi.acknowledge('a-001', 2)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/alerts/a-001/acknowledge', { version: 2 })
+ })
+
+ it('dismiss 应调用 PUT /health/alerts/:id/dismiss', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await alertApi.dismiss('a-001', 1)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/alerts/a-001/dismiss', { version: 1 })
+ })
+
+ it('resolve 应调用 PUT /health/alerts/:id/resolve', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await alertApi.resolve('a-001', 3)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/alerts/a-001/resolve', { version: 3 })
+ })
+})
+
+describe('alertRuleApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('list 应调用 GET /health/alert-rules 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await alertRuleApi.list({ device_type: 'blood_pressure', page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/alert-rules', {
+ params: { device_type: 'blood_pressure', page: 1, page_size: 10 },
+ })
+ })
+
+ it('create 应调用 POST /health/alert-rules 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = {
+ name: '血压偏高告警',
+ device_type: 'blood_pressure',
+ condition_type: 'threshold',
+ condition_params: { field: 'systolic', operator: '>', value: 140 },
+ severity: 'high',
+ }
+ await alertRuleApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/alert-rules', req)
+ })
+
+ it('update 应调用 PUT /health/alert-rules/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { severity: 'critical', version: 1 }
+ await alertRuleApi.update('rule-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/alert-rules/rule-001', req)
+ })
+
+ it('deactivate 应调用 PUT /health/alert-rules/:id/deactivate', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await alertRuleApi.deactivate('rule-001', 2)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/alert-rules/rule-001/deactivate', { version: 2 })
+ })
+})
diff --git a/apps/web/src/api/health/alerts.ts b/apps/web/src/api/health/alerts.ts
new file mode 100644
index 0000000..f1f6f1c
--- /dev/null
+++ b/apps/web/src/api/health/alerts.ts
@@ -0,0 +1,118 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface Alert {
+ id: string;
+ patient_id: string;
+ patient_name?: string;
+ rule_id: string;
+ severity: string;
+ title: string;
+ detail?: Record;
+ status: string;
+ acknowledged_by?: string;
+ acknowledged_by_name?: string;
+ acknowledged_at?: string;
+ resolved_at?: string;
+ created_at: string;
+ version: number;
+}
+
+export interface AlertRule {
+ id: string;
+ name: string;
+ description?: string;
+ device_type: string;
+ condition_type: string;
+ condition_params: Record;
+ severity: string;
+ is_active: boolean;
+ apply_tags?: Record;
+ notify_roles: unknown[];
+ cooldown_minutes: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateAlertRuleReq {
+ name: string;
+ description?: string;
+ device_type: string;
+ condition_type: string;
+ condition_params: Record;
+ severity?: string;
+ apply_tags?: Record;
+ notify_roles?: unknown[];
+ cooldown_minutes?: number;
+}
+
+export interface UpdateAlertRuleReq {
+ name?: string;
+ description?: string;
+ condition_params?: Record;
+ severity?: string;
+ apply_tags?: Record;
+ notify_roles?: unknown[];
+ cooldown_minutes?: number;
+ version: number;
+}
+
+// --- API ---
+export const alertApi = {
+ list: (params?: { patient_id?: string; doctor_id?: string; status?: string; page?: number; page_size?: number }) =>
+ client.get('/health/alerts', { params }).then((r) => r.data.data as PaginatedResponse),
+
+ acknowledge: (id: string, version: number) =>
+ client.put(`/health/alerts/${id}/acknowledge`, { version }).then((r) => r.data.data as Alert),
+
+ dismiss: (id: string, version: number) =>
+ client.put(`/health/alerts/${id}/dismiss`, { version }).then((r) => r.data.data as Alert),
+
+ resolve: (id: string, version: number) =>
+ client.put(`/health/alerts/${id}/resolve`, { version }).then((r) => r.data.data as Alert),
+};
+
+export const alertRuleApi = {
+ list: (params?: { device_type?: string; page?: number; page_size?: number }) =>
+ client.get('/health/alert-rules', { params }).then((r) => r.data.data as PaginatedResponse),
+
+ create: (data: CreateAlertRuleReq) =>
+ client.post('/health/alert-rules', data).then((r) => r.data.data as AlertRule),
+
+ update: (id: string, data: UpdateAlertRuleReq) =>
+ client.put(`/health/alert-rules/${id}`, data).then((r) => r.data.data as AlertRule),
+
+ deactivate: (id: string, version: number) =>
+ client.put(`/health/alert-rules/${id}/deactivate`, { version }).then((r) => r.data.data as AlertRule),
+};
+
+// --- Critical Alerts API ---
+
+export interface CriticalAlert {
+ id: string;
+ patient_id: string;
+ patient_name?: string;
+ alert_type: string;
+ severity: string;
+ title: string;
+ detail?: Record;
+ status: string;
+ acknowledged_by?: string;
+ acknowledged_at?: string;
+ notes?: string;
+ created_at: string;
+ version: number;
+}
+
+export const criticalAlertApi = {
+ list: (params?: { page?: number; page_size?: number }) =>
+ client.get('/health/critical-alerts', { params }).then((r) => r.data.data as PaginatedResponse),
+
+ get: (id: string) =>
+ client.get(`/health/critical-alerts/${id}`).then((r) => r.data.data as CriticalAlert),
+
+ acknowledge: (id: string, req: { notes?: string }) =>
+ client.post(`/health/critical-alerts/${id}/acknowledge`, req).then((r) => r.data),
+};
diff --git a/apps/web/src/api/health/api.test.ts b/apps/web/src/api/health/api.test.ts
new file mode 100644
index 0000000..9ab5d84
--- /dev/null
+++ b/apps/web/src/api/health/api.test.ts
@@ -0,0 +1,172 @@
+/**
+ * 健康模块新增 API 函数的契约测试
+ *
+ * 验证 dialysisApi / pointsAdminApi / healthDataApi 的日常监测与报告审核函数
+ * 是否调用了正确的 HTTP 方法、URL 路径和参数。
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+// --- Mock axios client ---
+// 三个被测文件都 import client from '../client',相对路径一致
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+// 在 mock 生效后导入被测模块
+import { dialysisApi } from './dialysis'
+import { pointsAdminApi } from './points'
+import { healthDataApi } from './healthData'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+// ============================================================
+// dialysisApi
+// ============================================================
+describe('dialysisApi', () => {
+ const fakeResponse = { data: { success: true, data: {} } }
+
+ it('listRecords 应调用 GET /health/patients/:id/dialysis-records 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeResponse)
+ await dialysisApi.listRecords('p-001', { page: 2, page_size: 20 })
+
+ expect(mockGet).toHaveBeenCalledTimes(1)
+ expect(mockGet).toHaveBeenCalledWith(
+ '/health/patients/p-001/dialysis-records',
+ { params: { page: 2, page_size: 20 } },
+ )
+ })
+
+ it('getRecord 应调用 GET /health/dialysis-records/:id', async () => {
+ mockGet.mockResolvedValue(fakeResponse)
+ await dialysisApi.getRecord('rec-123')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/dialysis-records/rec-123')
+ })
+
+ it('createRecord 应调用 POST /health/dialysis-records 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeResponse)
+ const req = { patient_id: 'p-001', dialysis_date: '2026-04-30', dialysis_type: 'hemodialysis' }
+ await dialysisApi.createRecord(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/dialysis-records', req)
+ })
+
+ it('updateRecord 应调用 PUT /health/dialysis-records/:id 并传递请求体', async () => {
+ mockPut.mockResolvedValue(fakeResponse)
+ const req = { dry_weight: 65.0, version: 3 }
+ await dialysisApi.updateRecord('rec-123', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/dialysis-records/rec-123', req)
+ })
+
+ it('deleteRecord 应调用 DELETE /health/dialysis-records/:id 并在 body 中传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await dialysisApi.deleteRecord('rec-123', 3)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/dialysis-records/rec-123', {
+ data: { version: 3 },
+ })
+ })
+
+ it('reviewRecord 应调用 PUT /health/dialysis-records/:id/review', async () => {
+ mockPut.mockResolvedValue(fakeResponse)
+ const req = { version: 2, doctor_notes: '指标正常' }
+ await dialysisApi.reviewRecord('rec-456', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/dialysis-records/rec-456/review', req)
+ })
+})
+
+// ============================================================
+// pointsAdminApi
+// ============================================================
+describe('pointsAdminApi', () => {
+ const fakeResponse = { data: { success: true, data: {} } }
+
+ it('getPatientAccount 应调用 GET /health/admin/points/patients/:id/account', async () => {
+ mockGet.mockResolvedValue(fakeResponse)
+ await pointsAdminApi.getPatientAccount('p-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/patients/p-001/account')
+ })
+
+ it('listPatientTransactions 应调用 GET 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeResponse)
+ await pointsAdminApi.listPatientTransactions('p-001', { page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith(
+ '/health/admin/points/patients/p-001/transactions',
+ { params: { page: 1, page_size: 10 } },
+ )
+ })
+})
+
+// ============================================================
+// healthDataApi — 日常监测 + 报告审核
+// ============================================================
+describe('healthDataApi 日常监测', () => {
+ const fakeResponse = { data: { success: true, data: {} } }
+
+ it('listDailyMonitoring 应调用 GET /health/patients/:id/daily-monitoring 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeResponse)
+ await healthDataApi.listDailyMonitoring('p-001', { page: 1, page_size: 15 })
+
+ expect(mockGet).toHaveBeenCalledWith(
+ '/health/patients/p-001/daily-monitoring',
+ { params: { page: 1, page_size: 15 } },
+ )
+ })
+
+ it('createDailyMonitoring 应调用 POST /health/daily-monitoring 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeResponse)
+ const req = {
+ patient_id: 'p-001',
+ record_date: '2026-04-30',
+ weight: 70.5,
+ blood_sugar: 5.2,
+ }
+ await healthDataApi.createDailyMonitoring(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/daily-monitoring', req)
+ })
+
+ it('updateDailyMonitoring 应调用 PUT /health/daily-monitoring/:id 并传递请求体', async () => {
+ mockPut.mockResolvedValue(fakeResponse)
+ const req = { weight: 71.0, version: 1 }
+ await healthDataApi.updateDailyMonitoring('dm-123', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/daily-monitoring/dm-123', req)
+ })
+
+ it('deleteDailyMonitoring 应调用 DELETE /health/daily-monitoring/:id 并在 body 中传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await healthDataApi.deleteDailyMonitoring('dm-123', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/daily-monitoring/dm-123', {
+ data: { version: 2 },
+ })
+ })
+
+ it('reviewLabReport 应调用 PUT /health/patients/:pid/lab-reports/:rid/review', async () => {
+ mockPut.mockResolvedValue(fakeResponse)
+ const req = { version: 1, doctor_notes: '指标略有异常,建议复查' }
+ await healthDataApi.reviewLabReport('p-001', 'lr-456', req)
+
+ expect(mockPut).toHaveBeenCalledWith(
+ '/health/patients/p-001/lab-reports/lr-456/review',
+ req,
+ )
+ })
+})
diff --git a/apps/web/src/api/health/appointments.test.ts b/apps/web/src/api/health/appointments.test.ts
new file mode 100644
index 0000000..49fc27d
--- /dev/null
+++ b/apps/web/src/api/health/appointments.test.ts
@@ -0,0 +1,106 @@
+/**
+ * appointments API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { appointmentApi } from './appointments'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('appointmentApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/appointments 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await appointmentApi.list({ page: 1, page_size: 20, status: 'confirmed', doctor_id: 'd-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/appointments', {
+ params: { page: 1, page_size: 20, status: 'confirmed', doctor_id: 'd-001' },
+ })
+ })
+
+ it('get 应调用 GET /health/appointments/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await appointmentApi.get('appt-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/appointments/appt-001')
+ })
+
+ it('create 应调用 POST /health/appointments 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = {
+ patient_id: 'p-001',
+ doctor_id: 'd-001',
+ appointment_date: '2026-05-10',
+ start_time: '09:00',
+ end_time: '09:30',
+ }
+ await appointmentApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/appointments', req)
+ })
+
+ it('updateStatus 应调用 PUT /health/appointments/:id/status', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { status: 'cancelled', cancel_reason: '时间冲突', version: 2 }
+ await appointmentApi.updateStatus('appt-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/appointments/appt-001/status', req)
+ })
+
+ it('listSchedules 应调用 GET /health/doctor-schedules 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await appointmentApi.listSchedules({ doctor_id: 'd-001', date: '2026-05-10' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/doctor-schedules', {
+ params: { doctor_id: 'd-001', date: '2026-05-10' },
+ })
+ })
+
+ it('createSchedule 应调用 POST /health/doctor-schedules', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = {
+ doctor_id: 'd-001',
+ schedule_date: '2026-05-10',
+ start_time: '08:00',
+ end_time: '12:00',
+ max_appointments: 10,
+ }
+ await appointmentApi.createSchedule(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/doctor-schedules', req)
+ })
+
+ it('updateSchedule 应调用 PUT /health/doctor-schedules/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { max_appointments: 15, version: 1 }
+ await appointmentApi.updateSchedule('sch-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/doctor-schedules/sch-001', req)
+ })
+
+ it('calendar 应调用 GET /health/doctor-schedules/calendar', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await appointmentApi.calendar({ start_date: '2026-05-01', end_date: '2026-05-31', doctor_id: 'd-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/doctor-schedules/calendar', {
+ params: { start_date: '2026-05-01', end_date: '2026-05-31', doctor_id: 'd-001' },
+ })
+ })
+})
diff --git a/apps/web/src/api/health/appointments.ts b/apps/web/src/api/health/appointments.ts
new file mode 100644
index 0000000..5488412
--- /dev/null
+++ b/apps/web/src/api/health/appointments.ts
@@ -0,0 +1,164 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface Appointment {
+ id: string;
+ patient_id: string;
+ doctor_id?: string;
+ appointment_type: string;
+ appointment_date: string;
+ start_time: string;
+ end_time: string;
+ status: string;
+ cancel_reason?: string;
+ notes?: string;
+ patient_name?: string;
+ doctor_name?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateAppointmentReq {
+ patient_id: string;
+ doctor_id?: string;
+ appointment_type?: string;
+ appointment_date: string;
+ start_time: string;
+ end_time: string;
+ notes?: string;
+}
+
+export interface UpdateAppointmentStatusReq {
+ status: string;
+ cancel_reason?: string;
+}
+
+export interface Schedule {
+ id: string;
+ doctor_id: string;
+ schedule_date: string;
+ period_type: string;
+ start_time: string;
+ end_time: string;
+ max_appointments: number;
+ current_appointments: number;
+ status: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateScheduleReq {
+ doctor_id: string;
+ schedule_date: string;
+ period_type?: string;
+ start_time: string;
+ end_time: string;
+ max_appointments: number;
+}
+
+export interface UpdateScheduleReq {
+ start_time?: string;
+ end_time?: string;
+ max_appointments?: number;
+ status?: string;
+}
+
+export interface CalendarDay {
+ date: string;
+ schedules: Schedule[];
+}
+
+// --- API ---
+export const appointmentApi = {
+ list: async (params: {
+ page?: number;
+ page_size?: number;
+ status?: string;
+ patient_id?: string;
+ doctor_id?: string;
+ date?: string;
+ search?: string;
+ appointment_type?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/appointments', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Appointment;
+ }>(`/health/appointments/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateAppointmentReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Appointment;
+ }>('/health/appointments', req);
+ return data.data;
+ },
+
+ updateStatus: async (
+ id: string,
+ req: UpdateAppointmentStatusReq & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Appointment;
+ }>(`/health/appointments/${id}/status`, req);
+ return data.data;
+ },
+
+ // Schedules
+ listSchedules: async (params: {
+ page?: number;
+ page_size?: number;
+ doctor_id?: string;
+ date?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/doctor-schedules', { params });
+ return data.data;
+ },
+
+ createSchedule: async (req: CreateScheduleReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Schedule;
+ }>('/health/doctor-schedules', req);
+ return data.data;
+ },
+
+ updateSchedule: async (
+ id: string,
+ req: UpdateScheduleReq & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Schedule;
+ }>(`/health/doctor-schedules/${id}`, req);
+ return data.data;
+ },
+
+ calendar: async (params: {
+ start_date: string;
+ end_date: string;
+ doctor_id?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: CalendarDay[];
+ }>('/health/doctor-schedules/calendar', { params });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/articles.test.ts b/apps/web/src/api/health/articles.test.ts
new file mode 100644
index 0000000..3cb9315
--- /dev/null
+++ b/apps/web/src/api/health/articles.test.ts
@@ -0,0 +1,173 @@
+/**
+ * articles API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { articleApi, articleCategoryApi, articleTagApi } from './articles'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('articleApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/articles 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await articleApi.list({ page: 1, page_size: 10, status: 'published', category_id: 'cat-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/articles', {
+ params: { page: 1, page_size: 10, status: 'published', category_id: 'cat-001' },
+ })
+ })
+
+ it('get 应调用 GET /health/articles/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await articleApi.get('art-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/articles/art-001')
+ })
+
+ it('create 应调用 POST /health/articles', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { title: '健康饮食指南', content: '正文内容', content_type: 'markdown' as const }
+ await articleApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles', req)
+ })
+
+ it('update 应调用 PUT /health/articles/:id 并传递请求体', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { title: '健康饮食指南(修订)', version: 1 }
+ await articleApi.update('art-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/articles/art-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/articles/:id', async () => {
+ mockDelete.mockResolvedValue({ data: { success: true, data: null } })
+ await articleApi.delete('art-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/articles/art-001')
+ })
+
+ it('submit 应调用 POST /health/articles/:id/submit 并传递 version', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await articleApi.submit('art-001', 2)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles/art-001/submit', { version: 2 })
+ })
+
+ it('approve 应调用 POST /health/articles/:id/approve', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await articleApi.approve('art-001', 2)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles/art-001/approve', { version: 2 })
+ })
+
+ it('reject 应调用 POST /health/articles/:id/reject 并传递 review_note', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await articleApi.reject('art-001', 2, '内容需要修改')
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles/art-001/reject', {
+ version: 2,
+ review_note: '内容需要修改',
+ })
+ })
+
+ it('unpublish 应调用 POST /health/articles/:id/unpublish', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await articleApi.unpublish('art-001', 3)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles/art-001/unpublish', { version: 3 })
+ })
+
+ it('view 应调用 POST /health/articles/:id/view', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await articleApi.view('art-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/health/articles/art-001/view')
+ })
+})
+
+describe('articleCategoryApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/article-categories', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await articleCategoryApi.list()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/article-categories')
+ })
+
+ it('create 应调用 POST /health/article-categories', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '营养健康', sort_order: 1 }
+ await articleCategoryApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/article-categories', req)
+ })
+
+ it('update 应调用 PUT /health/article-categories/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '营养健康(更新)' }
+ await articleCategoryApi.update('cat-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/article-categories/cat-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/article-categories/:id', async () => {
+ mockDelete.mockResolvedValue({ data: { success: true, data: null } })
+ await articleCategoryApi.delete('cat-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/article-categories/cat-001')
+ })
+})
+
+describe('articleTagApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/article-tags', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await articleTagApi.list()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/article-tags')
+ })
+
+ it('create 应调用 POST /health/article-tags', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '高血压', color: '#ff0000' }
+ await articleTagApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/article-tags', req)
+ })
+
+ it('update 应调用 PUT /health/article-tags/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '高血压管理', version: 1 }
+ await articleTagApi.update('tag-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/article-tags/tag-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/article-tags/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue({ data: { success: true, data: null } })
+ await articleTagApi.delete('tag-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/article-tags/tag-001', { data: { version: 2 } })
+ })
+})
diff --git a/apps/web/src/api/health/articles.ts b/apps/web/src/api/health/articles.ts
new file mode 100644
index 0000000..7dd070c
--- /dev/null
+++ b/apps/web/src/api/health/articles.ts
@@ -0,0 +1,283 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Article Types ---
+
+export type ArticleStatus = 'draft' | 'pending_review' | 'published' | 'rejected';
+export type ArticleContentType = 'rich_text' | 'markdown';
+
+export interface ArticleListItem {
+ id: string;
+ title: string;
+ summary?: string;
+ cover_image?: string;
+ content_type: ArticleContentType;
+ status: ArticleStatus;
+ slug?: string;
+ category_id?: string;
+ category_name?: string;
+ tags?: ArticleTagItem[];
+ author?: string;
+ reviewed_by?: string;
+ reviewed_at?: string;
+ review_note?: string;
+ view_count: number;
+ sort_order: number;
+ is_public: boolean;
+ published_at?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface Article extends ArticleListItem {
+ content?: string;
+}
+
+export interface CreateArticleReq {
+ title: string;
+ summary?: string;
+ content?: string;
+ content_type?: ArticleContentType;
+ cover_image?: string;
+ slug?: string;
+ category_id?: string;
+ tag_ids?: string[];
+ sort_order?: number;
+ is_public?: boolean;
+}
+
+export interface UpdateArticleReq {
+ title?: string;
+ summary?: string;
+ content?: string;
+ content_type?: ArticleContentType;
+ cover_image?: string;
+ slug?: string;
+ category_id?: string;
+ tag_ids?: string[];
+ sort_order?: number;
+ is_public?: boolean;
+ version: number;
+}
+
+export interface ArticleListParams {
+ page?: number;
+ page_size?: number;
+ status?: ArticleStatus;
+ category_id?: string;
+ tag_id?: string;
+ keyword?: string;
+}
+
+// --- Category Types ---
+
+export interface ArticleCategory {
+ id: string;
+ name: string;
+ slug?: string;
+ parent_id?: string;
+ parent_name?: string;
+ sort_order: number;
+ description?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateCategoryReq {
+ name: string;
+ slug?: string;
+ parent_id?: string;
+ sort_order?: number;
+ description?: string;
+}
+
+export interface UpdateCategoryReq {
+ name?: string;
+ slug?: string;
+ parent_id?: string;
+ sort_order?: number;
+ description?: string;
+}
+
+// --- Tag Types ---
+
+export interface ArticleTagItem {
+ id: string;
+ name: string;
+ slug?: string;
+ color?: string;
+ created_at: string;
+ version?: number;
+}
+
+export interface CreateTagReq {
+ name: string;
+ slug?: string;
+ color?: string;
+}
+
+// --- Article API ---
+
+export const articleApi = {
+ list: async (params: ArticleListParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/articles', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateArticleReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>('/health/articles', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateArticleReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/articles/${id}`, { data: { version } });
+ return data.data;
+ },
+
+ submit: async (id: string, version: number) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}/submit`, { version });
+ return data.data;
+ },
+
+ approve: async (id: string, version: number) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}/approve`, { version });
+ return data.data;
+ },
+
+ reject: async (id: string, version: number, review_note: string) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}/reject`, { version, review_note });
+ return data.data;
+ },
+
+ unpublish: async (id: string, version: number) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}/unpublish`, { version });
+ return data.data;
+ },
+
+ view: async (id: string) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Article;
+ }>(`/health/articles/${id}/view`);
+ return data.data;
+ },
+
+ listRevisions: async (id: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse>;
+ }>(`/health/articles/${id}/revisions`, { params });
+ return data.data;
+ },
+};
+
+// --- Category API ---
+
+export const articleCategoryApi = {
+ list: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: ArticleCategory[];
+ }>('/health/article-categories');
+ return data.data;
+ },
+
+ create: async (req: CreateCategoryReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: ArticleCategory;
+ }>('/health/article-categories', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateCategoryReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: ArticleCategory;
+ }>(`/health/article-categories/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/article-categories/${id}`, { data: { version } });
+ return data.data;
+ },
+};
+
+// --- Tag API ---
+
+export const articleTagApi = {
+ list: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: ArticleTagItem[];
+ }>('/health/article-tags');
+ return data.data;
+ },
+
+ create: async (req: CreateTagReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: ArticleTagItem;
+ }>('/health/article-tags', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: { name: string; version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: ArticleTagItem;
+ }>(`/health/article-tags/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/article-tags/${id}`, { data: { version } });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/banners.ts b/apps/web/src/api/health/banners.ts
new file mode 100644
index 0000000..937e2ec
--- /dev/null
+++ b/apps/web/src/api/health/banners.ts
@@ -0,0 +1,116 @@
+import client from '../client';
+
+// ---------------------------------------------------------------------------
+// 轮播图类型
+// ---------------------------------------------------------------------------
+
+export interface BannerItem {
+ id: string;
+ tenant_id: string;
+ media_item_id: string;
+ title?: string;
+ subtitle?: string;
+ link_type?: string;
+ link_target?: string;
+ sort_order: number;
+ status: string;
+ start_time?: string;
+ end_time?: string;
+ image_url?: string;
+ thumbnail_url?: string;
+ media_deleted: boolean;
+ created_at: string;
+ updated_at: string;
+ created_by?: string;
+ updated_by?: string;
+ version: number;
+}
+
+export interface CreateBannerReq {
+ media_item_id: string;
+ title?: string;
+ subtitle?: string;
+ link_type?: string;
+ link_target?: string;
+ sort_order?: number;
+ status?: string;
+ start_time?: string;
+ end_time?: string;
+}
+
+export interface UpdateBannerReq {
+ media_item_id?: string;
+ title?: string;
+ subtitle?: string;
+ link_type?: string;
+ link_target?: string;
+ sort_order?: number;
+ status?: string;
+ start_time?: string;
+ end_time?: string;
+ version: number;
+}
+
+export interface SortBannerReq {
+ items: Array<{ id: string; sort_order: number }>;
+}
+
+// ---------------------------------------------------------------------------
+// 轮播图 API
+// ---------------------------------------------------------------------------
+
+export const bannerApi = {
+ /** 获取轮播图列表(可按状态筛选) */
+ list: async (status?: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: BannerItem[];
+ }>('/health/banners', { params: status ? { status } : undefined });
+ return data.data;
+ },
+
+ /** 获取单个轮播图 */
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: BannerItem;
+ }>(`/health/banners/${id}`);
+ return data.data;
+ },
+
+ /** 创建轮播图 */
+ create: async (req: CreateBannerReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: BannerItem;
+ }>('/health/banners', req);
+ return data.data;
+ },
+
+ /** 更新轮播图 */
+ update: async (id: string, req: UpdateBannerReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: BannerItem;
+ }>(`/health/banners/${id}`, req);
+ return data.data;
+ },
+
+ /** 删除轮播图 */
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/banners/${id}`, { data: { version } });
+ return data.data;
+ },
+
+ /** 轮播图排序 */
+ sort: async (req: SortBannerReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: null;
+ }>('/health/banners/sort', req);
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/bleGateways.ts b/apps/web/src/api/health/bleGateways.ts
new file mode 100644
index 0000000..4c1c8b5
--- /dev/null
+++ b/apps/web/src/api/health/bleGateways.ts
@@ -0,0 +1,170 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface BleGateway {
+ id: string;
+ tenant_id: string;
+ gateway_id: string;
+ name: string;
+ status: string;
+ firmware_version?: string;
+ ip_address?: string;
+ last_heartbeat_at?: string;
+ metadata?: Record;
+ created_at: string;
+ updated_at: string;
+ version: number;
+ api_key?: string;
+ patient_count?: number;
+}
+
+export interface GatewayBinding {
+ id: string;
+ tenant_id: string;
+ gateway_id: string;
+ patient_id: string;
+ peripheral_mac?: string;
+ device_type?: string;
+ status: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateBleGatewayReq {
+ gateway_id: string;
+ name: string;
+ firmware_version?: string;
+ metadata?: Record;
+}
+
+export interface UpdateBleGatewayReq {
+ name?: string;
+ status?: string;
+ firmware_version?: string;
+ metadata?: Record;
+}
+
+export interface ListBleGatewaysParams {
+ page?: number;
+ page_size?: number;
+ status?: string;
+}
+
+export interface CreateBindingReq {
+ patient_id: string;
+ peripheral_mac?: string;
+ device_type?: string;
+}
+
+export interface BatchBindReq {
+ bindings: CreateBindingReq[];
+}
+
+// --- Constants ---
+
+export const GATEWAY_STATUS_OPTIONS = [
+ { label: '在线', value: 'online' },
+ { label: '离线', value: 'offline' },
+ { label: '未激活', value: 'inactive' },
+ { label: '已禁用', value: 'disabled' },
+];
+
+export const GATEWAY_STATUS_COLOR: Record = {
+ online: 'green',
+ offline: 'red',
+ inactive: 'default',
+ disabled: 'error',
+};
+
+export const GATEWAY_STATUS_LABEL: Record = Object.fromEntries(
+ GATEWAY_STATUS_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const BINDING_STATUS_COLOR: Record = {
+ active: 'green',
+ inactive: 'default',
+ unbound: 'error',
+};
+
+// --- API ---
+
+export const bleGatewayApi = {
+ // --- Gateways ---
+
+ list: async (params?: ListBleGatewaysParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/ble-gateways', { params });
+ return data.data;
+ },
+
+ get: async (gatewayId: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: BleGateway;
+ }>(`/health/ble-gateways/${gatewayId}`);
+ return data.data;
+ },
+
+ create: async (req: CreateBleGatewayReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: BleGateway;
+ }>('/health/ble-gateways', req);
+ return data.data;
+ },
+
+ update: async (gatewayId: string, req: UpdateBleGatewayReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: BleGateway;
+ }>(`/health/ble-gateways/${gatewayId}`, req);
+ return data.data;
+ },
+
+ delete: async (gatewayId: string, version: number) => {
+ await client.delete(`/health/ble-gateways/${gatewayId}`, { data: { version } });
+ },
+
+ regenerateKey: async (gatewayId: string) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: BleGateway;
+ }>(`/health/ble-gateways/${gatewayId}/regenerate-key`);
+ return data.data;
+ },
+
+ // --- Bindings ---
+
+ listBindings: async (gatewayId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/ble-gateways/${gatewayId}/bindings`, { params });
+ return data.data;
+ },
+
+ bindPatient: async (gatewayId: string, req: CreateBindingReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: GatewayBinding;
+ }>(`/health/ble-gateways/${gatewayId}/bindings`, req);
+ return data.data;
+ },
+
+ batchBind: async (gatewayId: string, req: BatchBindReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: GatewayBinding[];
+ }>(`/health/ble-gateways/${gatewayId}/bindings/batch`, req);
+ return data.data;
+ },
+
+ unbindPatient: async (gatewayId: string, bindingId: string, version: number) => {
+ await client.delete(`/health/ble-gateways/${gatewayId}/bindings/${bindingId}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/carePlans.ts b/apps/web/src/api/health/carePlans.ts
new file mode 100644
index 0000000..6a8b2c5
--- /dev/null
+++ b/apps/web/src/api/health/carePlans.ts
@@ -0,0 +1,245 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface CarePlan {
+ id: string;
+ patient_id: string;
+ plan_type: string;
+ status: string;
+ title: string;
+ goals?: Record;
+ start_date?: string;
+ end_date?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CarePlanItem {
+ id: string;
+ plan_id: string;
+ item_type: string;
+ title: string;
+ description?: string;
+ status: string;
+ schedule?: string;
+ sort_order?: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CarePlanOutcome {
+ id: string;
+ plan_id: string;
+ item_id?: string;
+ metric: string;
+ baseline_value: string;
+ target_value: string;
+ current_value?: string;
+ measured_at?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateCarePlanReq {
+ patient_id: string;
+ plan_type: string;
+ title: string;
+ goals?: Record;
+ start_date?: string;
+ end_date?: string;
+ notes?: string;
+}
+
+export interface UpdateCarePlanReq {
+ plan_type?: string;
+ title?: string;
+ status?: string;
+ goals?: Record;
+ start_date?: string;
+ end_date?: string;
+ notes?: string;
+}
+
+export interface CreateCarePlanItemReq {
+ item_type: string;
+ title: string;
+ description?: string;
+ schedule?: string;
+ sort_order?: number;
+}
+
+export interface UpdateCarePlanItemReq {
+ item_type?: string;
+ title?: string;
+ description?: string;
+ status?: string;
+ schedule?: string;
+ sort_order?: number;
+}
+
+export interface CreateCarePlanOutcomeReq {
+ item_id?: string;
+ metric: string;
+ baseline_value: string;
+ target_value: string;
+ current_value?: string;
+ measured_at?: string;
+ notes?: string;
+}
+
+export interface UpdateCarePlanOutcomeReq {
+ item_id?: string;
+ metric?: string;
+ baseline_value?: string;
+ target_value?: string;
+ current_value?: string;
+ measured_at?: string;
+ notes?: string;
+}
+
+export interface ListCarePlansParams {
+ page?: number;
+ page_size?: number;
+ patient_id?: string;
+ plan_type?: string;
+ status?: string;
+}
+
+// --- Constants ---
+
+export const PLAN_TYPE_OPTIONS = [
+ { label: '血液透析', value: 'hemodialysis' },
+ { label: '腹膜透析', value: 'peritoneal' },
+ { label: '慢性病管理', value: 'chronic_disease' },
+ { label: '康复计划', value: 'rehabilitation' },
+];
+
+export const PLAN_STATUS_OPTIONS = [
+ { label: '草稿', value: 'draft' },
+ { label: '进行中', value: 'active' },
+ { label: '已完成', value: 'completed' },
+ { label: '已取消', value: 'cancelled' },
+];
+
+export const ITEM_TYPE_OPTIONS = [
+ { label: '药物干预', value: 'medication' },
+ { label: '饮食管理', value: 'diet' },
+ { label: '运动计划', value: 'exercise' },
+ { label: '监测项目', value: 'monitoring' },
+ { label: '教育指导', value: 'education' },
+ { label: '其他', value: 'other' },
+];
+
+export const PLAN_STATUS_COLOR: Record = {
+ draft: 'default',
+ active: 'processing',
+ completed: 'success',
+ cancelled: 'error',
+};
+
+// --- API ---
+
+export const carePlanApi = {
+ list: async (params: ListCarePlansParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/care-plans', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: CarePlan;
+ }>(`/health/care-plans/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateCarePlanReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: CarePlan;
+ }>('/health/care-plans', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateCarePlanReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: CarePlan;
+ }>(`/health/care-plans/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/care-plans/${id}`, { data: { version } });
+ },
+
+ // --- Items ---
+
+ listItems: async (planId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/care-plans/${planId}/items`, { params });
+ return data.data;
+ },
+
+ createItem: async (planId: string, req: CreateCarePlanItemReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: CarePlanItem;
+ }>(`/health/care-plans/${planId}/items`, req);
+ return data.data;
+ },
+
+ updateItem: async (planId: string, itemId: string, req: UpdateCarePlanItemReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: CarePlanItem;
+ }>(`/health/care-plans/${planId}/items/${itemId}`, req);
+ return data.data;
+ },
+
+ deleteItem: async (planId: string, itemId: string, version: number) => {
+ await client.delete(`/health/care-plans/${planId}/items/${itemId}`, { data: { version } });
+ },
+
+ // --- Outcomes ---
+
+ listOutcomes: async (planId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/care-plans/${planId}/outcomes`, { params });
+ return data.data;
+ },
+
+ createOutcome: async (planId: string, req: CreateCarePlanOutcomeReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: CarePlanOutcome;
+ }>(`/health/care-plans/${planId}/outcomes`, req);
+ return data.data;
+ },
+
+ updateOutcome: async (planId: string, outcomeId: string, req: UpdateCarePlanOutcomeReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: CarePlanOutcome;
+ }>(`/health/care-plans/${planId}/outcomes/${outcomeId}`, req);
+ return data.data;
+ },
+
+ deleteOutcome: async (planId: string, outcomeId: string, version: number) => {
+ await client.delete(`/health/care-plans/${planId}/outcomes/${outcomeId}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/consents.ts b/apps/web/src/api/health/consents.ts
new file mode 100644
index 0000000..94ae960
--- /dev/null
+++ b/apps/web/src/api/health/consents.ts
@@ -0,0 +1,92 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface Consent {
+ id: string;
+ patient_id: string;
+ consent_type: string;
+ consent_scope: string;
+ status: string;
+ granted_at?: string;
+ revoked_at?: string;
+ expiry_date?: string;
+ consent_method?: string;
+ witness_name?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateConsentReq {
+ patient_id: string;
+ consent_type: string;
+ consent_scope: string;
+ expiry_date?: string;
+ consent_method?: string;
+ witness_name?: string;
+ notes?: string;
+}
+
+export interface RevokeConsentReq {
+ notes?: string;
+ version: number;
+}
+
+// --- Constants ---
+
+export const CONSENT_TYPE_OPTIONS = [
+ { label: '治疗同意', value: 'treatment' },
+ { label: '数据共享', value: 'data_sharing' },
+ { label: '隐私政策', value: 'privacy' },
+ { label: '研究参与', value: 'research' },
+];
+
+export const CONSENT_SCOPE_OPTIONS = [
+ { label: '全部', value: 'all' },
+ { label: '健康数据', value: 'health_data' },
+ { label: '基本信息', value: 'basic_info' },
+ { label: '体检报告', value: 'examination' },
+];
+
+export const CONSENT_STATUS_COLOR: Record = {
+ active: 'green',
+ revoked: 'red',
+ expired: 'default',
+};
+
+export const CONSENT_STATUS_LABEL: Record = {
+ active: '生效中',
+ revoked: '已撤销',
+ expired: '已过期',
+};
+
+// --- API ---
+
+export const consentApi = {
+ list: async (patientId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/consents`, { params });
+ return data.data;
+ },
+
+ grant: async (req: CreateConsentReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Consent;
+ }>('/health/consents', req);
+ return data.data;
+ },
+
+ revoke: async (consentId: string, req: RevokeConsentReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Consent;
+ }>(`/health/consents/${consentId}/revoke`, req);
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/consultations.test.ts b/apps/web/src/api/health/consultations.test.ts
new file mode 100644
index 0000000..275f53b
--- /dev/null
+++ b/apps/web/src/api/health/consultations.test.ts
@@ -0,0 +1,98 @@
+/**
+ * consultations API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { consultationApi } from './consultations'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('consultationApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listSessions 应调用 GET /health/consultation-sessions 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await consultationApi.listSessions({ page: 1, page_size: 20, status: 'active', patient_id: 'p-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/consultation-sessions', {
+ params: { page: 1, page_size: 20, status: 'active', patient_id: 'p-001' },
+ })
+ })
+
+ it('createSession 应调用 POST /health/consultation-sessions', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { patient_id: 'p-001', doctor_id: 'd-001', consultation_type: 'online' }
+ await consultationApi.createSession(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/consultation-sessions', req)
+ })
+
+ it('getSession 应调用 GET /health/consultation-sessions/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await consultationApi.getSession('sess-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/consultation-sessions/sess-001')
+ })
+
+ it('closeSession 应调用 PUT /health/consultation-sessions/:id/close', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ await consultationApi.closeSession('sess-001', { version: 1 })
+
+ expect(mockPut).toHaveBeenCalledWith('/health/consultation-sessions/sess-001/close', { version: 1 })
+ })
+
+ it('listMessages 应调用 GET /health/consultation-sessions/:id/messages 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await consultationApi.listMessages('sess-001', { page: 2, page_size: 50, after_id: 'msg-100' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/consultation-sessions/sess-001/messages', {
+ params: { page: 2, page_size: 50, after_id: 'msg-100' },
+ })
+ })
+
+ it('createMessage 应调用 POST /health/consultation-messages', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { session_id: 'sess-001', content_type: 'text', content: '你好' }
+ await consultationApi.createMessage(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/consultation-messages', req)
+ })
+
+ it('createFollowUpFromSession 应调用 POST /health/consultation-sessions/:id/follow-up', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { follow_up_type: 'phone', planned_date: '2026-06-01' }
+ await consultationApi.createFollowUpFromSession('sess-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/consultation-sessions/sess-001/follow-up', req)
+ })
+
+ it('triggerAiAnalysisFromSession 应调用 POST /health/consultation-sessions/:id/ai-analysis', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await consultationApi.triggerAiAnalysisFromSession('sess-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/health/consultation-sessions/sess-001/ai-analysis', {})
+ })
+
+ it('triggerAiAnalysisFromSession 传入 analysis_type 时应携带参数', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await consultationApi.triggerAiAnalysisFromSession('sess-001', { analysis_type: 'trend' })
+
+ expect(mockPost).toHaveBeenCalledWith('/health/consultation-sessions/sess-001/ai-analysis', { analysis_type: 'trend' })
+ })
+})
diff --git a/apps/web/src/api/health/consultations.ts b/apps/web/src/api/health/consultations.ts
new file mode 100644
index 0000000..2bfc355
--- /dev/null
+++ b/apps/web/src/api/health/consultations.ts
@@ -0,0 +1,185 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface Session {
+ id: string;
+ patient_id: string;
+ doctor_id?: string;
+ patient_name?: string;
+ doctor_name?: string;
+ consultation_type: string;
+ status: string;
+ last_message_at?: string;
+ unread_count_patient: number;
+ unread_count_doctor: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateSessionReq {
+ patient_id: string;
+ doctor_id?: string;
+ consultation_type?: string;
+}
+
+export interface Message {
+ id: string;
+ session_id: string;
+ sender_id: string;
+ sender_role: string;
+ content_type: string;
+ content: string;
+ is_read: boolean;
+ created_at: string;
+}
+
+export interface CreateMessageReq {
+ session_id: string;
+ content_type?: string;
+ content: string;
+}
+
+// --- 咨询联动请求类型 ---
+export interface CreateFollowUpFromConsultationReq {
+ follow_up_type: string;
+ planned_date: string;
+ assigned_to?: string;
+ content_template?: string;
+}
+
+export interface FollowUpFromConsultationResp {
+ task_id: string;
+ session_id: string;
+ patient_id: string;
+}
+
+export interface TriggerAiAnalysisReq {
+ analysis_type?: string;
+}
+
+export interface AiAnalysisTriggeredResp {
+ session_id: string;
+ patient_id: string;
+ analysis_type: string;
+}
+
+// --- API ---
+export const consultationApi = {
+ listSessions: async (params: {
+ page?: number;
+ page_size?: number;
+ status?: string;
+ patient_id?: string;
+ doctor_id?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/consultation-sessions', { params });
+ return data.data;
+ },
+
+ createSession: async (req: CreateSessionReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Session;
+ }>('/health/consultation-sessions', req);
+ return data.data;
+ },
+
+ getSession: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Session;
+ }>(`/health/consultation-sessions/${id}`);
+ return data.data;
+ },
+
+ closeSession: async (
+ id: string,
+ req: { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Session;
+ }>(`/health/consultation-sessions/${id}/close`, req);
+ return data.data;
+ },
+
+ listMessages: async (
+ sessionId: string,
+ params: { page?: number; page_size?: number; after_id?: string },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/consultation-sessions/${sessionId}/messages`, { params });
+ return data.data;
+ },
+
+ createMessage: async (req: CreateMessageReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Message;
+ }>('/health/consultation-messages', req);
+ return data.data;
+ },
+
+ pollMessages: async (
+ sessionId: string,
+ afterId?: string,
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Message[];
+ }>(`/health/consultation-sessions/${sessionId}/messages/poll`, {
+ params: { after_id: afterId, timeout: 25 },
+ timeout: 30000,
+ });
+ return data.data;
+ },
+
+ markSessionRead: async (id: string) => {
+ await client.put(`/health/consultation-sessions/${id}/read`);
+ },
+
+ exportSessions: async (params?: {
+ status?: string;
+ patient_id?: string;
+ doctor_id?: string;
+ page?: number;
+ page_size?: number;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/consultation-sessions/export', { params });
+ return data.data;
+ },
+
+ /** 从咨询会话创建随访任务 */
+ createFollowUpFromSession: async (
+ sessionId: string,
+ req: CreateFollowUpFromConsultationReq,
+ ) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FollowUpFromConsultationResp;
+ }>(`/health/consultation-sessions/${sessionId}/follow-up`, req);
+ return data.data;
+ },
+
+ /** 从咨询会话触发 AI 分析 */
+ triggerAiAnalysisFromSession: async (
+ sessionId: string,
+ req?: TriggerAiAnalysisReq,
+ ) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: AiAnalysisTriggeredResp;
+ }>(`/health/consultation-sessions/${sessionId}/ai-analysis`, req ?? {});
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/criticalValueThresholds.ts b/apps/web/src/api/health/criticalValueThresholds.ts
new file mode 100644
index 0000000..55f75a4
--- /dev/null
+++ b/apps/web/src/api/health/criticalValueThresholds.ts
@@ -0,0 +1,110 @@
+import client from '../client';
+
+// --- Types ---
+
+export interface CriticalValueThreshold {
+ id: string;
+ tenant_id: string;
+ indicator: string;
+ direction: string;
+ threshold_value: number;
+ level: string;
+ department?: string;
+ age_min?: number;
+ age_max?: number;
+ is_active: boolean;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateThresholdReq {
+ indicator: string;
+ direction: string;
+ threshold_value: number;
+ level?: string;
+ department?: string;
+ age_min?: number;
+ age_max?: number;
+}
+
+export interface UpdateThresholdReq {
+ threshold_value: number;
+ level?: string;
+ department?: string;
+ age_min?: number;
+ age_max?: number;
+ version: number;
+}
+
+// --- Constants ---
+
+export const INDICATOR_OPTIONS = [
+ { label: '收缩压', value: 'systolic_bp' },
+ { label: '舒张压', value: 'diastolic_bp' },
+ { label: '心率', value: 'heart_rate' },
+ { label: '血糖', value: 'blood_sugar' },
+ { label: '空腹血糖', value: 'blood_sugar_fasting' },
+ { label: '餐后血糖', value: 'blood_sugar_postprandial' },
+ { label: '血氧', value: 'blood_oxygen' },
+ { label: '体温', value: 'temperature' },
+];
+
+export const DIRECTION_OPTIONS = [
+ { label: '偏高', value: 'high' },
+ { label: '偏低', value: 'low' },
+];
+
+export const LEVEL_OPTIONS = [
+ { label: '危急', value: 'critical' },
+ { label: '警告', value: 'warning' },
+];
+
+export const LEVEL_COLOR: Record = {
+ critical: 'red',
+ warning: 'orange',
+};
+
+export const INDICATOR_LABEL: Record = Object.fromEntries(
+ INDICATOR_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const DIRECTION_LABEL: Record = Object.fromEntries(
+ DIRECTION_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const LEVEL_LABEL: Record = Object.fromEntries(
+ LEVEL_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+// --- API ---
+
+export const criticalValueThresholdApi = {
+ list: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: CriticalValueThreshold[];
+ }>('/health/critical-value-thresholds');
+ return data.data;
+ },
+
+ create: async (req: CreateThresholdReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: CriticalValueThreshold;
+ }>('/health/critical-value-thresholds', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateThresholdReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: CriticalValueThreshold;
+ }>(`/health/critical-value-thresholds/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string) => {
+ await client.delete(`/health/critical-value-thresholds/${id}`);
+ },
+};
diff --git a/apps/web/src/api/health/dashboard.test.ts b/apps/web/src/api/health/dashboard.test.ts
new file mode 100644
index 0000000..a58b82d
--- /dev/null
+++ b/apps/web/src/api/health/dashboard.test.ts
@@ -0,0 +1,105 @@
+/**
+ * dashboard + actionInbox API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { dashboardApi } from './dashboard'
+import { actionInboxApi } from './actionInbox'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('dashboardApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('getSystemHealth 应调用 GET /health/admin/system-health', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dashboardApi.getSystemHealth()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/system-health')
+ })
+
+ it('getUserActivity 应调用 GET /health/admin/user-activity', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dashboardApi.getUserActivity()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/user-activity')
+ })
+
+ it('getModuleStatus 应调用 GET /health/admin/modules', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dashboardApi.getModuleStatus()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/modules')
+ })
+
+ it('getPointsRecentActivity 应调用 GET /health/points/recent-activity', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dashboardApi.getPointsRecentActivity()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/points/recent-activity')
+ })
+
+ it('getArticleStats 应调用 GET /health/articles/stats', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await dashboardApi.getArticleStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/articles/stats')
+ })
+})
+
+describe('actionInboxApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/action-inbox 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await actionInboxApi.list({ status: 'pending', type: 'alert', page: 1, page_size: 20 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/action-inbox', {
+ params: { status: 'pending', type: 'alert', page: 1, page_size: 20 },
+ })
+ })
+
+ it('getThread 应调用 GET /health/action-inbox/:sourceRef/thread', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await actionInboxApi.getThread('ref-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/action-inbox/ref-001/thread')
+ })
+
+ it('getThread 应对特殊字符 URL 编码', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await actionInboxApi.getThread('ref/with:special')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/action-inbox/ref%2Fwith%3Aspecial/thread')
+ })
+
+ it('stats 应调用 GET /health/action-inbox/stats', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await actionInboxApi.stats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/action-inbox/stats')
+ })
+
+ it('team 应调用 GET /health/action-inbox/team', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await actionInboxApi.team()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/action-inbox/team')
+ })
+})
diff --git a/apps/web/src/api/health/dashboard.ts b/apps/web/src/api/health/dashboard.ts
new file mode 100644
index 0000000..43201ef
--- /dev/null
+++ b/apps/web/src/api/health/dashboard.ts
@@ -0,0 +1,69 @@
+import client from '../client';
+
+export interface ServiceHealthStatus {
+ name: string;
+ status: string;
+ message: string;
+ response_ms: number | null;
+}
+
+export interface SystemHealthResp {
+ services: ServiceHealthStatus[];
+ checked_at: string;
+}
+
+export interface RoleCount {
+ role: string;
+ count: number;
+}
+
+export interface UserActivityResp {
+ daily_active: number;
+ weekly_active: number;
+ monthly_active: number;
+ total_registered: number;
+ by_role: RoleCount[];
+}
+
+export interface ModuleStatusResp {
+ name: string;
+ display_name: string;
+ description: string;
+ active: boolean;
+ entity_count: number | null;
+ route_count: number | null;
+}
+
+export interface PointsActivityItem {
+ id: string;
+ user_name: string;
+ detail: string;
+ amount: string;
+ type: string;
+ created_at: string;
+}
+
+export interface ArticleStatsResp {
+ published: number;
+ draft: number;
+ pending_review: number;
+ rejected: number;
+ total_views: number;
+}
+
+export const dashboardApi = {
+ getSystemHealth: () =>
+ client.get('/health/admin/system-health').then((r) => r.data.data as SystemHealthResp),
+
+ getUserActivity: () =>
+ client.get('/health/admin/user-activity').then((r) => r.data.data as UserActivityResp),
+
+ getModuleStatus: () =>
+ client.get('/health/admin/modules').then((r) => r.data.data as ModuleStatusResp[]),
+
+ getPointsRecentActivity: () =>
+ client.get('/health/points/recent-activity').then((r) => r.data.data as PointsActivityItem[]),
+
+ getArticleStats: () =>
+ client.get('/health/articles/stats').then((r) => r.data.data as ArticleStatsResp),
+};
diff --git a/apps/web/src/api/health/deviceReadings.test.ts b/apps/web/src/api/health/deviceReadings.test.ts
new file mode 100644
index 0000000..ae0b191
--- /dev/null
+++ b/apps/web/src/api/health/deviceReadings.test.ts
@@ -0,0 +1,82 @@
+/**
+ * deviceReadings + devices API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { deviceReadingApi } from './deviceReadings'
+import { deviceApi } from './devices'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('deviceReadingApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('batchCreate 应调用 POST /health/patients/:id/device-readings/batch', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const data = {
+ device_id: 'dev-001',
+ readings: [
+ { device_type: 'blood_pressure', values: { systolic: 130, diastolic: 85 }, measured_at: '2026-05-03T08:00:00Z' },
+ ],
+ }
+ await deviceReadingApi.batchCreate('p-001', data)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/device-readings/batch', data)
+ })
+
+ it('query 应调用 GET /health/patients/:id/device-readings 并剥离 patient_id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await deviceReadingApi.query({ patient_id: 'p-001', device_type: 'blood_pressure', hours: 24 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/device-readings', {
+ params: { device_type: 'blood_pressure', hours: 24 },
+ })
+ })
+
+ it('queryHourly 应调用 GET /health/patients/:id/device-readings/hourly', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await deviceReadingApi.queryHourly({ patient_id: 'p-001', device_type: 'blood_pressure', days: 7 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/device-readings/hourly', {
+ params: { device_type: 'blood_pressure', days: 7 },
+ })
+ })
+})
+
+describe('deviceApi', () => {
+ const fakeRes = { data: { data: {} } }
+
+ it('listDevices 应调用 GET /health/devices 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await deviceApi.listDevices({ patient_id: 'p-001', device_type: 'blood_pressure', page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/devices', {
+ params: { patient_id: 'p-001', device_type: 'blood_pressure', page: 1, page_size: 10 },
+ })
+ })
+
+ it('unbindDevice 应调用 DELETE /health/devices/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue(fakeRes)
+ await deviceApi.unbindDevice('dev-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/devices/dev-001', {
+ data: { version: 2 },
+ })
+ })
+})
diff --git a/apps/web/src/api/health/deviceReadings.ts b/apps/web/src/api/health/deviceReadings.ts
new file mode 100644
index 0000000..94f0424
--- /dev/null
+++ b/apps/web/src/api/health/deviceReadings.ts
@@ -0,0 +1,72 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface DeviceReading {
+ id: string;
+ device_id?: string;
+ device_type: string;
+ device_model?: string;
+ raw_value: Record;
+ measured_at: string;
+ created_at: string;
+}
+
+export interface HourlyReading {
+ id: string;
+ device_type: string;
+ hour_start: string;
+ min_val?: number;
+ max_val?: number;
+ avg_val: number;
+ sample_count: number;
+}
+
+export interface DailyReading {
+ id: string;
+ device_type: string;
+ date_bucket: string;
+ min_val?: number;
+ max_val?: number;
+ avg_val: number;
+ sample_count: number;
+ percentile_95?: number;
+}
+
+export interface BatchReadingRequest {
+ device_id: string;
+ device_model?: string;
+ readings: {
+ device_type: string;
+ values: Record;
+ measured_at: string;
+ }[];
+}
+
+export interface BatchResult {
+ accepted: number;
+ duplicates: number;
+ earliest?: string;
+ latest?: string;
+}
+
+// --- API ---
+export const deviceReadingApi = {
+ batchCreate: (patientId: string, data: BatchReadingRequest) =>
+ client.post(`/health/patients/${patientId}/device-readings/batch`, data).then((r) => r.data.data as BatchResult),
+
+ query: (params: { patient_id: string; device_type?: string; hours?: number; page?: number; page_size?: number }) => {
+ const { patient_id, ...query } = params;
+ return client.get(`/health/patients/${patient_id}/device-readings`, { params: query }).then((r) => r.data.data as PaginatedResponse);
+ },
+
+ queryHourly: (params: { patient_id: string; device_type: string; days?: number; page?: number; page_size?: number }) => {
+ const { patient_id, ...query } = params;
+ return client.get(`/health/patients/${patient_id}/device-readings/hourly`, { params: query }).then((r) => r.data.data as PaginatedResponse);
+ },
+
+ queryDaily: (params: { patient_id: string; device_type?: string; from_date?: string; to_date?: string; page?: number; page_size?: number }) => {
+ const { patient_id, ...query } = params;
+ return client.get(`/health/vital-signs/daily`, { params: { ...query, patient_id } }).then((r) => r.data.data as PaginatedResponse);
+ },
+};
diff --git a/apps/web/src/api/health/devices.ts b/apps/web/src/api/health/devices.ts
new file mode 100644
index 0000000..d7b6cbd
--- /dev/null
+++ b/apps/web/src/api/health/devices.ts
@@ -0,0 +1,37 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface DeviceItem {
+ id: string;
+ patient_id: string;
+ device_id: string;
+ device_model: string;
+ device_type: string;
+ status?: string;
+ firmware_version?: string;
+ manufacturer?: string;
+ connection_type?: string;
+ metadata?: Record;
+ bound_at: string;
+ last_sync_at: string;
+ version: number;
+}
+
+// --- API ---
+export const deviceApi = {
+ listDevices: (params?: {
+ patient_id?: string;
+ device_type?: string;
+ page?: number;
+ page_size?: number;
+ }) =>
+ client
+ .get('/health/devices', { params })
+ .then((r) => r.data.data as PaginatedResponse),
+
+ unbindDevice: (id: string, version: number) =>
+ client
+ .delete(`/health/devices/${id}`, { data: { version } })
+ .then((r) => r.data.data as DeviceItem),
+};
diff --git a/apps/web/src/api/health/diagnoses.ts b/apps/web/src/api/health/diagnoses.ts
new file mode 100644
index 0000000..3fe68e7
--- /dev/null
+++ b/apps/web/src/api/health/diagnoses.ts
@@ -0,0 +1,108 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface Diagnosis {
+ id: string;
+ patient_id: string;
+ health_record_id?: string;
+ icd_code: string;
+ diagnosis_name: string;
+ diagnosis_type: string;
+ diagnosed_date: string;
+ status: string;
+ diagnosed_by?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateDiagnosisReq {
+ icd_code: string;
+ diagnosis_name: string;
+ diagnosis_type?: string;
+ diagnosed_date: string;
+ status?: string;
+ health_record_id?: string;
+ diagnosed_by?: string;
+ notes?: string;
+}
+
+export interface UpdateDiagnosisReq {
+ icd_code?: string;
+ diagnosis_name?: string;
+ diagnosis_type?: string;
+ diagnosed_date?: string;
+ status?: string;
+ health_record_id?: string;
+ diagnosed_by?: string;
+ notes?: string;
+}
+
+// --- Constants ---
+
+export const DIAGNOSIS_TYPE_OPTIONS = [
+ { label: '主要诊断', value: 'primary' },
+ { label: '次要诊断', value: 'secondary' },
+ { label: '合并症', value: 'comorbid' },
+];
+
+export const DIAGNOSIS_STATUS_OPTIONS = [
+ { label: '活跃', value: 'active' },
+ { label: '已缓解', value: 'resolved' },
+ { label: '慢性', value: 'chronic' },
+];
+
+export const DIAGNOSIS_TYPE_COLOR: Record = {
+ primary: 'red',
+ secondary: 'blue',
+ comorbid: 'orange',
+};
+
+export const DIAGNOSIS_STATUS_COLOR: Record = {
+ active: 'green',
+ resolved: 'default',
+ chronic: 'orange',
+};
+
+export const DIAGNOSIS_TYPE_LABEL: Record = Object.fromEntries(
+ DIAGNOSIS_TYPE_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const DIAGNOSIS_STATUS_LABEL: Record = Object.fromEntries(
+ DIAGNOSIS_STATUS_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+// --- API ---
+
+export const diagnosisApi = {
+ list: async (patientId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/diagnoses`, { params });
+ return data.data;
+ },
+
+ create: async (patientId: string, req: CreateDiagnosisReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Diagnosis;
+ }>(`/health/patients/${patientId}/diagnoses`, req);
+ return data.data;
+ },
+
+ update: async (diagnosisId: string, req: UpdateDiagnosisReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Diagnosis;
+ }>(`/health/diagnoses/${diagnosisId}`, req);
+ return data.data;
+ },
+
+ delete: async (diagnosisId: string, version: number) => {
+ await client.delete(`/health/diagnoses/${diagnosisId}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/dialysis.ts b/apps/web/src/api/health/dialysis.ts
new file mode 100644
index 0000000..582941e
--- /dev/null
+++ b/apps/web/src/api/health/dialysis.ts
@@ -0,0 +1,116 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface DialysisRecord {
+ id: string;
+ patient_id: string;
+ dialysis_date: string;
+ start_time?: string;
+ end_time?: string;
+ dry_weight?: number;
+ pre_weight?: number;
+ post_weight?: number;
+ pre_bp_systolic?: number;
+ pre_bp_diastolic?: number;
+ post_bp_systolic?: number;
+ post_bp_diastolic?: number;
+ pre_heart_rate?: number;
+ post_heart_rate?: number;
+ ultrafiltration_volume?: number;
+ dialysis_duration?: number;
+ blood_flow_rate?: number;
+ dialysis_type: string;
+ symptoms?: Record;
+ complication_notes?: string;
+ status: string;
+ reviewed_by?: string;
+ reviewed_at?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateDialysisRecordReq {
+ patient_id: string;
+ dialysis_date: string;
+ start_time?: string;
+ end_time?: string;
+ dry_weight?: number;
+ pre_weight?: number;
+ post_weight?: number;
+ pre_bp_systolic?: number;
+ pre_bp_diastolic?: number;
+ post_bp_systolic?: number;
+ post_bp_diastolic?: number;
+ pre_heart_rate?: number;
+ post_heart_rate?: number;
+ ultrafiltration_volume?: number;
+ dialysis_duration?: number;
+ blood_flow_rate?: number;
+ dialysis_type?: string;
+ complication_notes?: string;
+}
+
+// --- API ---
+
+export const dialysisApi = {
+ listRecords: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/dialysis-records`, { params });
+ return data.data;
+ },
+
+ getRecord: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: DialysisRecord;
+ }>(`/health/dialysis-records/${id}`);
+ return data.data;
+ },
+
+ createRecord: async (req: CreateDialysisRecordReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: DialysisRecord;
+ }>('/health/dialysis-records', req);
+ return data.data;
+ },
+
+ updateRecord: async (
+ id: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: DialysisRecord;
+ }>(`/health/dialysis-records/${id}`, req);
+ return data.data;
+ },
+
+ deleteRecord: async (id: string, version: number) => {
+ await client.delete(`/health/dialysis-records/${id}`, { data: { version } });
+ },
+
+ reviewRecord: async (id: string, req: { version: number; doctor_notes?: string }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Record;
+ }>(`/health/dialysis-records/${id}/review`, req);
+ return data.data;
+ },
+
+ completeRecord: async (id: string, version: number) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: DialysisRecord;
+ }>(`/health/dialysis-records/${id}/complete`, { version });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/doctors.test.ts b/apps/web/src/api/health/doctors.test.ts
new file mode 100644
index 0000000..1c9996d
--- /dev/null
+++ b/apps/web/src/api/health/doctors.test.ts
@@ -0,0 +1,67 @@
+/**
+ * doctors API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { doctorApi } from './doctors'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('doctorApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/doctors 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await doctorApi.list({ page: 1, page_size: 10, search: '王', department: '内科' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/doctors', {
+ params: { page: 1, page_size: 10, search: '王', department: '内科' },
+ })
+ })
+
+ it('get 应调用 GET /health/doctors/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await doctorApi.get('d-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/doctors/d-001')
+ })
+
+ it('create 应调用 POST /health/doctors 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '王医生', department: '内科', title: '主任医师' }
+ await doctorApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/doctors', req)
+ })
+
+ it('update 应调用 PUT /health/doctors/:id 并传递请求体含 version', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { title: '副主任医师', version: 1 }
+ await doctorApi.update('d-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/doctors/d-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/doctors/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await doctorApi.delete('d-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/doctors/d-001')
+ })
+})
diff --git a/apps/web/src/api/health/doctors.ts b/apps/web/src/api/health/doctors.ts
new file mode 100644
index 0000000..3dcfedb
--- /dev/null
+++ b/apps/web/src/api/health/doctors.ts
@@ -0,0 +1,83 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface Doctor {
+ id: string;
+ user_id?: string;
+ name: string;
+ department?: string;
+ title?: string;
+ specialty?: string;
+ license_number?: string;
+ bio?: string;
+ online_status: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateDoctorReq {
+ user_id?: string;
+ name: string;
+ department?: string;
+ title?: string;
+ specialty?: string;
+ license_number?: string;
+ bio?: string;
+}
+
+export interface UpdateDoctorReq {
+ name?: string;
+ department?: string;
+ title?: string;
+ specialty?: string;
+ license_number?: string;
+ bio?: string;
+ online_status?: string;
+}
+
+// --- API ---
+export const doctorApi = {
+ list: async (params: {
+ page?: number;
+ page_size?: number;
+ search?: string;
+ department?: string;
+ title?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/doctors', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Doctor;
+ }>(`/health/doctors/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateDoctorReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Doctor;
+ }>('/health/doctors', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateDoctorReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Doctor;
+ }>(`/health/doctors/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/doctors/${id}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/familyProxy.ts b/apps/web/src/api/health/familyProxy.ts
new file mode 100644
index 0000000..d584c2a
--- /dev/null
+++ b/apps/web/src/api/health/familyProxy.ts
@@ -0,0 +1,109 @@
+import client from '../client';
+
+// --- Types ---
+
+export interface FamilyMember {
+ id: string;
+ patient_id: string;
+ name: string;
+ relationship: string;
+ phone?: string;
+ birth_date?: string;
+ notes?: string;
+ user_id?: string;
+ consent_status: string;
+ access_level: string;
+ consented_at?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface FamilyPatientSummary {
+ family_member_id: string;
+ patient_id: string;
+ patient_name: string;
+ relationship: string;
+ consent_status: string;
+ access_level: string;
+ consented_at?: string;
+}
+
+export interface FamilyHealthSummary {
+ patient_id: string;
+ patient_name: string;
+ latest_vital_signs?: Record;
+ active_care_plan?: Record;
+ recent_alerts_count: number;
+ next_appointment?: Record;
+}
+
+export interface GrantAccessReq {
+ access_level: string;
+}
+
+// --- Constants ---
+
+export const CONSENT_STATUS_OPTIONS = [
+ { label: '已同意', value: 'granted' },
+ { label: '待确认', value: 'pending' },
+ { label: '已撤销', value: 'revoked' },
+ { label: '已过期', value: 'expired' },
+];
+
+export const ACCESS_LEVEL_OPTIONS = [
+ { label: '完全访问', value: 'full' },
+ { label: '只读', value: 'read_only' },
+ { label: '摘要', value: 'summary' },
+];
+
+export const CONSENT_STATUS_COLOR: Record = {
+ granted: 'green',
+ pending: 'orange',
+ revoked: 'red',
+ expired: 'default',
+};
+
+export const ACCESS_LEVEL_LABEL: Record = Object.fromEntries(
+ ACCESS_LEVEL_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const CONSENT_STATUS_LABEL: Record = Object.fromEntries(
+ CONSENT_STATUS_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+// --- API ---
+
+export const familyProxyApi = {
+ grantAccess: async (patientId: string, familyMemberId: string, req: GrantAccessReq, version: number) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FamilyMember;
+ }>(`/health/patients/${patientId}/family-members/${familyMemberId}/grant-access`, { ...req, version });
+ return data.data;
+ },
+
+ revokeAccess: async (patientId: string, familyMemberId: string, version: number) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: FamilyMember;
+ }>(`/health/patients/${patientId}/family-members/${familyMemberId}/revoke-access`, { version });
+ return data.data;
+ },
+
+ listMyPatients: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FamilyPatientSummary[];
+ }>('/health/family/patients');
+ return data.data;
+ },
+
+ getHealthSummary: async (patientId: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FamilyHealthSummary;
+ }>(`/health/family/patients/${patientId}/health-summary`);
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/followUp.test.ts b/apps/web/src/api/health/followUp.test.ts
new file mode 100644
index 0000000..3460c3d
--- /dev/null
+++ b/apps/web/src/api/health/followUp.test.ts
@@ -0,0 +1,97 @@
+/**
+ * followUp API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { followUpApi } from './followUp'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('followUpApi - Tasks', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listTasks 应调用 GET /health/follow-up-tasks 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await followUpApi.listTasks({ page: 1, page_size: 20, patient_id: 'p-001', status: 'pending' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/follow-up-tasks', {
+ params: { page: 1, page_size: 20, patient_id: 'p-001', status: 'pending' },
+ })
+ })
+
+ it('getTask 应调用 GET /health/follow-up-tasks/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await followUpApi.getTask('task-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/follow-up-tasks/task-001')
+ })
+
+ it('createTask 应调用 POST /health/follow-up-tasks', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { patient_id: 'p-001', follow_up_type: 'phone', planned_date: '2026-05-10' }
+ await followUpApi.createTask(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/follow-up-tasks', req)
+ })
+
+ it('updateTask 应调用 PUT /health/follow-up-tasks/:id 并传递 version', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { status: 'completed', version: 1 }
+ await followUpApi.updateTask('task-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/follow-up-tasks/task-001', req)
+ })
+
+ it('deleteTask 应调用 DELETE /health/follow-up-tasks/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await followUpApi.deleteTask('task-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/follow-up-tasks/task-001', {
+ data: { version: 2 },
+ })
+ })
+})
+
+describe('followUpApi - Records', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listRecords 应调用 GET /health/follow-up-records 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await followUpApi.listRecords({ page: 1, page_size: 10, task_id: 'task-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/follow-up-records', {
+ params: { page: 1, page_size: 10, task_id: 'task-001' },
+ })
+ })
+
+ it('createRecord 应调用 POST /health/follow-up-tasks/:taskId/records 并注入 task_id', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = {
+ executed_date: '2026-05-10',
+ result: '已完成',
+ patient_condition: '良好',
+ }
+ await followUpApi.createRecord('task-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/follow-up-tasks/task-001/records', {
+ ...req,
+ task_id: 'task-001',
+ })
+ })
+})
diff --git a/apps/web/src/api/health/followUp.ts b/apps/web/src/api/health/followUp.ts
new file mode 100644
index 0000000..c2b6a44
--- /dev/null
+++ b/apps/web/src/api/health/followUp.ts
@@ -0,0 +1,133 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface FollowUpTask {
+ id: string;
+ patient_id: string;
+ assigned_to?: string;
+ patient_name?: string;
+ assigned_to_name?: string;
+ follow_up_type: string;
+ planned_date: string;
+ status: string;
+ content_template?: string;
+ related_appointment_id?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateFollowUpTaskReq {
+ patient_id: string;
+ assigned_to?: string;
+ follow_up_type: string;
+ planned_date: string;
+ content_template?: string;
+ related_appointment_id?: string;
+}
+
+export interface UpdateFollowUpTaskReq {
+ assigned_to?: string;
+ follow_up_type?: string;
+ planned_date?: string;
+ content_template?: string;
+ status?: string;
+}
+
+export interface FollowUpRecord {
+ id: string;
+ task_id: string;
+ executed_by?: string;
+ executed_date: string;
+ result?: string;
+ patient_condition?: string;
+ medical_advice?: string;
+ next_follow_up_date?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateFollowUpRecordReq {
+ task_id: string;
+ executed_by?: string;
+ executed_date: string;
+ result?: string;
+ patient_condition?: string;
+ medical_advice?: string;
+ next_follow_up_date?: string;
+}
+
+// --- API ---
+export const followUpApi = {
+ // Tasks
+ listTasks: async (params: {
+ page?: number;
+ page_size?: number;
+ patient_id?: string;
+ assigned_to?: string;
+ status?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/follow-up-tasks', { params });
+ return data.data;
+ },
+
+ getTask: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FollowUpTask;
+ }>(`/health/follow-up-tasks/${id}`);
+ return data.data;
+ },
+
+ createTask: async (req: CreateFollowUpTaskReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FollowUpTask;
+ }>('/health/follow-up-tasks', req);
+ return data.data;
+ },
+
+ updateTask: async (
+ id: string,
+ req: UpdateFollowUpTaskReq & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: FollowUpTask;
+ }>(`/health/follow-up-tasks/${id}`, req);
+ return data.data;
+ },
+
+ deleteTask: async (id: string, version: number) => {
+ await client.delete(`/health/follow-up-tasks/${id}`, {
+ data: { version },
+ });
+ },
+
+ // Records
+ listRecords: async (params: {
+ page?: number;
+ page_size?: number;
+ task_id?: string;
+ patient_id?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/follow-up-records', { params });
+ return data.data;
+ },
+
+ createRecord: async (taskId: string, req: Omit) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FollowUpRecord;
+ }>(`/health/follow-up-tasks/${taskId}/records`, { ...req, task_id: taskId });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/followUpTemplates.test.ts b/apps/web/src/api/health/followUpTemplates.test.ts
new file mode 100644
index 0000000..637fb65
--- /dev/null
+++ b/apps/web/src/api/health/followUpTemplates.test.ts
@@ -0,0 +1,75 @@
+/**
+ * followUpTemplates API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { followUpTemplateApi } from './followUpTemplates'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('followUpTemplateApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/follow-up-templates 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await followUpTemplateApi.list({ page: 1, page_size: 10, follow_up_type: 'phone', status: 'active' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/follow-up-templates', {
+ params: { page: 1, page_size: 10, follow_up_type: 'phone', status: 'active' },
+ })
+ })
+
+ it('get 应调用 GET /health/follow-up-templates/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await followUpTemplateApi.get('tpl-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/follow-up-templates/tpl-001')
+ })
+
+ it('create 应调用 POST /health/follow-up-templates 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = {
+ name: '电话随访模板',
+ follow_up_type: 'phone',
+ fields: [
+ { label: '患者状态', field_key: 'patient_status', field_type: 'select', required: true, options: '良好,一般,较差' },
+ ],
+ }
+ await followUpTemplateApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/follow-up-templates', req)
+ })
+
+ it('update 应调用 PUT /health/follow-up-templates/:id 并传递请求体', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '更新后模板', status: 'active', version: 1 }
+ await followUpTemplateApi.update('tpl-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/follow-up-templates/tpl-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/follow-up-templates/:id 并在 body 传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await followUpTemplateApi.delete('tpl-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/follow-up-templates/tpl-001', {
+ data: { version: 2 },
+ })
+ })
+})
diff --git a/apps/web/src/api/health/followUpTemplates.ts b/apps/web/src/api/health/followUpTemplates.ts
new file mode 100644
index 0000000..626e72a
--- /dev/null
+++ b/apps/web/src/api/health/followUpTemplates.ts
@@ -0,0 +1,119 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+export type FollowUpType = 'phone' | 'outpatient' | 'home_visit' | 'online' | 'wechat';
+export type TemplateStatus = 'active' | 'draft' | 'archived';
+
+export interface TemplateField {
+ id: string;
+ template_id: string;
+ label: string;
+ field_key: string;
+ field_type: string;
+ required: boolean;
+ options?: string;
+ placeholder?: string;
+ validation?: string;
+ sort_order: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface TemplateFieldReq {
+ label: string;
+ field_key: string;
+ field_type: string;
+ required?: boolean;
+ options?: string;
+ placeholder?: string;
+ validation?: string;
+ sort_order?: number;
+}
+
+export interface FollowUpTemplate {
+ id: string;
+ name: string;
+ description?: string;
+ follow_up_type: string;
+ applicable_scope?: string;
+ status: string;
+ fields: TemplateField[];
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface FollowUpTemplateListItem {
+ id: string;
+ name: string;
+ description?: string;
+ follow_up_type: string;
+ status: string;
+ field_count: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateTemplateReq {
+ name: string;
+ description?: string;
+ follow_up_type: string;
+ applicable_scope?: string;
+ fields: TemplateFieldReq[];
+}
+
+export interface UpdateTemplateReq {
+ name?: string;
+ description?: string;
+ follow_up_type?: string;
+ applicable_scope?: string;
+ status?: string;
+ fields?: TemplateFieldReq[];
+}
+
+export const followUpTemplateApi = {
+ list: async (params?: {
+ page?: number;
+ page_size?: number;
+ follow_up_type?: string;
+ status?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/follow-up-templates', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FollowUpTemplate;
+ }>(`/health/follow-up-templates/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateTemplateReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FollowUpTemplate;
+ }>('/health/follow-up-templates', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateTemplateReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: FollowUpTemplate;
+ }>(`/health/follow-up-templates/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/follow-up-templates/${id}`, {
+ data: { version },
+ });
+ },
+};
diff --git a/apps/web/src/api/health/healthData.test.ts b/apps/web/src/api/health/healthData.test.ts
new file mode 100644
index 0000000..1f9862e
--- /dev/null
+++ b/apps/web/src/api/health/healthData.test.ts
@@ -0,0 +1,135 @@
+/**
+ * healthData API 契约测试(体征/化验报告/健康记录/趋势/日常监测)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { healthDataApi } from './healthData'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('healthDataApi - Vital Signs', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listVitalSigns 应调用 GET /health/patients/:id/vital-signs 并传递分页', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await healthDataApi.listVitalSigns('p-001', { page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/vital-signs', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createVitalSigns 应调用 POST /health/patients/:id/vital-signs', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { record_date: '2026-05-03', systolic_bp_morning: 120, diastolic_bp_morning: 80 }
+ await healthDataApi.createVitalSigns('p-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/vital-signs', req)
+ })
+
+ it('updateVitalSigns 应调用 PUT /health/patients/:pid/vital-signs/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { systolic_bp_morning: 125, version: 1 }
+ await healthDataApi.updateVitalSigns('p-001', 'vs-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001/vital-signs/vs-001', req)
+ })
+
+ it('deleteVitalSigns 应调用 DELETE /health/patients/:pid/vital-signs/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await healthDataApi.deleteVitalSigns('p-001', 'vs-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001/vital-signs/vs-001')
+ })
+})
+
+describe('healthDataApi - Lab Reports', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listLabReports 应调用 GET /health/patients/:id/lab-reports', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await healthDataApi.listLabReports('p-001', { page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/lab-reports', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createLabReport 应调用 POST /health/patients/:id/lab-reports', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { report_date: '2026-05-03', report_type: 'blood_test' }
+ await healthDataApi.createLabReport('p-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/lab-reports', req)
+ })
+
+ it('reviewLabReport 应调用 PUT /health/patients/:pid/lab-reports/:rid/review', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { version: 1, doctor_notes: '指标正常' }
+ await healthDataApi.reviewLabReport('p-001', 'lr-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001/lab-reports/lr-001/review', req)
+ })
+
+ it('deleteLabReport 应调用 DELETE /health/patients/:pid/lab-reports/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await healthDataApi.deleteLabReport('p-001', 'lr-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001/lab-reports/lr-001')
+ })
+})
+
+describe('healthDataApi - Health Records', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listHealthRecords 应调用 GET /health/patients/:id/health-records', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await healthDataApi.listHealthRecords('p-001', { page: 1, page_size: 10 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/health-records', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createHealthRecord 应调用 POST /health/patients/:id/health-records', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { record_type: 'checkup', record_date: '2026-05-03', content: '体检结果正常' }
+ await healthDataApi.createHealthRecord('p-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/health-records', req)
+ })
+})
+
+describe('healthDataApi - Trends', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listTrends 应调用 GET /health/patients/:id/trends', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await healthDataApi.listTrends('p-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/trends')
+ })
+
+ it('getIndicatorTimeseries 应调用 GET /health/patients/:id/trends/:indicator 并编码', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await healthDataApi.getIndicatorTimeseries('p-001', 'blood_pressure/systolic')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/trends/blood_pressure%2Fsystolic')
+ })
+})
diff --git a/apps/web/src/api/health/healthData.ts b/apps/web/src/api/health/healthData.ts
new file mode 100644
index 0000000..cc766a7
--- /dev/null
+++ b/apps/web/src/api/health/healthData.ts
@@ -0,0 +1,304 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface VitalSigns {
+ id: string;
+ patient_id: string;
+ record_date: string;
+ systolic_bp_morning?: number;
+ diastolic_bp_morning?: number;
+ systolic_bp_evening?: number;
+ diastolic_bp_evening?: number;
+ heart_rate?: number;
+ weight?: number;
+ blood_sugar?: number;
+ water_intake_ml?: number;
+ urine_output_ml?: number;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateVitalSignsReq {
+ record_date: string;
+ systolic_bp_morning?: number;
+ diastolic_bp_morning?: number;
+ systolic_bp_evening?: number;
+ diastolic_bp_evening?: number;
+ heart_rate?: number;
+ weight?: number;
+ blood_sugar?: number;
+ water_intake_ml?: number;
+ urine_output_ml?: number;
+ notes?: string;
+}
+
+export interface LabReport {
+ id: string;
+ patient_id: string;
+ report_date: string;
+ report_type: string;
+ items?: unknown;
+ image_urls?: string[];
+ doctor_notes?: string;
+ source?: string;
+ status: string;
+ reviewed_by?: string;
+ reviewed_at?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateLabReportReq {
+ report_date: string;
+ report_type: string;
+ items?: unknown;
+ image_urls?: string[];
+ doctor_notes?: string;
+}
+
+export interface HealthRecord {
+ id: string;
+ patient_id: string;
+ record_type: string;
+ record_date: string;
+ overall_assessment?: string;
+ report_file_url?: string;
+ source?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateHealthRecordReq {
+ record_type: string;
+ record_date: string;
+ overall_assessment?: string;
+ report_file_url?: string;
+}
+
+export interface DailyMonitoring {
+ id: string;
+ patient_id: string;
+ record_date: string;
+ morning_bp_systolic?: number;
+ morning_bp_diastolic?: number;
+ evening_bp_systolic?: number;
+ evening_bp_diastolic?: number;
+ weight?: number;
+ blood_sugar?: number;
+ fluid_intake?: number;
+ urine_output?: number;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateDailyMonitoringReq {
+ patient_id: string;
+ record_date: string;
+ morning_bp_systolic?: number;
+ morning_bp_diastolic?: number;
+ evening_bp_systolic?: number;
+ evening_bp_diastolic?: number;
+ weight?: number;
+ blood_sugar?: number;
+ fluid_intake?: number;
+ urine_output?: number;
+ notes?: string;
+}
+
+export interface TrendData {
+ id: string;
+ patient_id: string;
+ indicator: string;
+ trend_data: { date: string; value: number }[];
+ generated_at: string;
+}
+
+// --- API ---
+export const healthDataApi = {
+ // Vital Signs
+ listVitalSigns: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/vital-signs`, { params });
+ return data.data;
+ },
+
+ createVitalSigns: async (patientId: string, req: CreateVitalSignsReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: VitalSigns;
+ }>(`/health/patients/${patientId}/vital-signs`, req);
+ return data.data;
+ },
+
+ updateVitalSigns: async (
+ patientId: string,
+ id: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: VitalSigns;
+ }>(`/health/patients/${patientId}/vital-signs/${id}`, req);
+ return data.data;
+ },
+
+ deleteVitalSigns: async (patientId: string, id: string) => {
+ await client.delete(`/health/patients/${patientId}/vital-signs/${id}`);
+ },
+
+ // Lab Reports
+ listLabReports: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/lab-reports`, { params });
+ return data.data;
+ },
+
+ createLabReport: async (patientId: string, req: CreateLabReportReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: LabReport;
+ }>(`/health/patients/${patientId}/lab-reports`, req);
+ return data.data;
+ },
+
+ updateLabReport: async (
+ patientId: string,
+ id: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: LabReport;
+ }>(`/health/patients/${patientId}/lab-reports/${id}`, req);
+ return data.data;
+ },
+
+ deleteLabReport: async (patientId: string, id: string) => {
+ await client.delete(`/health/patients/${patientId}/lab-reports/${id}`);
+ },
+
+ reviewLabReport: async (patientId: string, reportId: string, req: { version: number; doctor_notes?: string }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Record;
+ }>(`/health/patients/${patientId}/lab-reports/${reportId}/review`, req);
+ return data.data;
+ },
+
+ // Health Records
+ listHealthRecords: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/health-records`, { params });
+ return data.data;
+ },
+
+ createHealthRecord: async (
+ patientId: string,
+ req: CreateHealthRecordReq,
+ ) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: HealthRecord;
+ }>(`/health/patients/${patientId}/health-records`, req);
+ return data.data;
+ },
+
+ updateHealthRecord: async (
+ patientId: string,
+ id: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: HealthRecord;
+ }>(`/health/patients/${patientId}/health-records/${id}`, req);
+ return data.data;
+ },
+
+ deleteHealthRecord: async (patientId: string, id: string) => {
+ await client.delete(`/health/patients/${patientId}/health-records/${id}`);
+ },
+
+ // Trends
+ listTrends: async (patientId: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: TrendData[];
+ }>(`/health/patients/${patientId}/trends`);
+ return data.data;
+ },
+
+ generateTrend: async (patientId: string, req: { indicator: string; start_date?: string; end_date?: string }) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: TrendData;
+ }>(`/health/patients/${patientId}/trends/generate`, req);
+ return data.data;
+ },
+
+ getIndicatorTimeseries: async (patientId: string, indicator: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: { date: string; value: number }[];
+ }>(`/health/patients/${patientId}/trends/${encodeURIComponent(indicator)}`);
+ return data.data;
+ },
+
+ // Daily Monitoring
+ listDailyMonitoring: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/daily-monitoring`, { params });
+ return data.data;
+ },
+
+ createDailyMonitoring: async (req: CreateDailyMonitoringReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: DailyMonitoring;
+ }>('/health/daily-monitoring', req);
+ return data.data;
+ },
+
+ updateDailyMonitoring: async (
+ id: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: DailyMonitoring;
+ }>(`/health/daily-monitoring/${id}`, req);
+ return data.data;
+ },
+
+ deleteDailyMonitoring: async (id: string, version: number) => {
+ await client.delete(`/health/daily-monitoring/${id}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/media.ts b/apps/web/src/api/health/media.ts
new file mode 100644
index 0000000..79ebe38
--- /dev/null
+++ b/apps/web/src/api/health/media.ts
@@ -0,0 +1,208 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// ---------------------------------------------------------------------------
+// 媒体文件类型
+// ---------------------------------------------------------------------------
+
+export interface MediaItem {
+ id: string;
+ tenant_id: string;
+ folder_id?: string;
+ filename: string;
+ storage_path: string;
+ thumbnail_path?: string;
+ content_type: string;
+ file_size: number;
+ width?: number;
+ height?: number;
+ alt_text?: string;
+ is_public: boolean;
+ created_at: string;
+ updated_at: string;
+ created_by?: string;
+ updated_by?: string;
+ version: number;
+}
+
+export interface MediaListParams {
+ page?: number;
+ page_size?: number;
+ folder_id?: string;
+ content_type?: string;
+ keyword?: string;
+ is_public?: boolean;
+}
+
+export interface UpdateMediaReq {
+ filename?: string;
+ alt_text?: string;
+ is_public?: boolean;
+ folder_id?: string;
+ version: number;
+}
+
+export interface MoveMediaReq {
+ folder_id?: string;
+ version: number;
+}
+
+export interface CropReq {
+ x: number;
+ y: number;
+ width: number;
+ height: number;
+ version: number;
+}
+
+// ---------------------------------------------------------------------------
+// 文件夹类型
+// ---------------------------------------------------------------------------
+
+export interface FolderItem {
+ id: string;
+ tenant_id: string;
+ name: string;
+ parent_id?: string;
+ sort_order: number;
+ children: FolderItem[];
+ item_count: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateFolderReq {
+ name: string;
+ parent_id?: string;
+ sort_order?: number;
+}
+
+export interface UpdateFolderReq {
+ name?: string;
+ parent_id?: string;
+ sort_order?: number;
+ version: number;
+}
+
+// ---------------------------------------------------------------------------
+// 媒体文件 API
+// ---------------------------------------------------------------------------
+
+export const mediaApi = {
+ /** 分页查询媒体文件列表 */
+ list: async (params: MediaListParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/media', { params });
+ return data.data;
+ },
+
+ /** 上传媒体文件(multipart/form-data) */
+ upload: async (formData: FormData) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: MediaItem;
+ }>('/health/media/upload', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ return data.data;
+ },
+
+ /** 获取单个媒体文件详情 */
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: MediaItem;
+ }>(`/health/media/${id}`);
+ return data.data;
+ },
+
+ /** 更新媒体文件信息 */
+ update: async (id: string, req: UpdateMediaReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: MediaItem;
+ }>(`/health/media/${id}`, req);
+ return data.data;
+ },
+
+ /** 删除媒体文件 */
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/media/${id}`, { data: { version } });
+ return data.data;
+ },
+
+ /** 移动媒体文件到指定文件夹 */
+ move: async (id: string, req: MoveMediaReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: MediaItem;
+ }>(`/health/media/${id}/move`, req);
+ return data.data;
+ },
+
+ /** 批量删除媒体文件 */
+ batchDelete: async (ids: string[]) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: null;
+ }>('/health/media/batch-delete', { ids });
+ return data.data;
+ },
+
+ /** 裁剪媒体文件 */
+ crop: async (id: string, req: CropReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: MediaItem;
+ }>(`/health/media/${id}/crop`, req);
+ return data.data;
+ },
+};
+
+// ---------------------------------------------------------------------------
+// 文件夹 API
+// ---------------------------------------------------------------------------
+
+export const mediaFolderApi = {
+ /** 获取文件夹树形结构 */
+ tree: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FolderItem[];
+ }>('/health/media-folders');
+ return data.data;
+ },
+
+ /** 创建文件夹 */
+ create: async (req: CreateFolderReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FolderItem;
+ }>('/health/media-folders', req);
+ return data.data;
+ },
+
+ /** 更新文件夹 */
+ update: async (id: string, req: UpdateFolderReq) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: FolderItem;
+ }>(`/health/media-folders/${id}`, req);
+ return data.data;
+ },
+
+ /** 删除文件夹 */
+ delete: async (id: string, version: number) => {
+ const { data } = await client.delete<{
+ success: boolean;
+ data: null;
+ }>(`/health/media-folders/${id}`, { data: { version } });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/medicationRecords.ts b/apps/web/src/api/health/medicationRecords.ts
new file mode 100644
index 0000000..6731cef
--- /dev/null
+++ b/apps/web/src/api/health/medicationRecords.ts
@@ -0,0 +1,111 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface MedicationRecord {
+ id: string;
+ patient_id: string;
+ medication_name: string;
+ generic_name?: string;
+ dosage?: string;
+ unit?: string;
+ frequency?: string;
+ route?: string;
+ start_date?: string;
+ end_date?: string;
+ is_current: boolean;
+ prescribed_by?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateMedicationRecordReq {
+ patient_id: string;
+ medication_name: string;
+ generic_name?: string;
+ dosage?: string;
+ unit?: string;
+ frequency?: string;
+ route?: string;
+ start_date?: string;
+ end_date?: string;
+ is_current?: boolean;
+ prescribed_by?: string;
+ notes?: string;
+}
+
+export interface UpdateMedicationRecordReq {
+ medication_name?: string;
+ generic_name?: string;
+ dosage?: string;
+ unit?: string;
+ frequency?: string;
+ route?: string;
+ start_date?: string;
+ end_date?: string;
+ is_current?: boolean;
+ prescribed_by?: string;
+ notes?: string;
+}
+
+// --- Constants ---
+
+export const FREQUENCY_OPTIONS = [
+ { label: '每日一次', value: 'QD' },
+ { label: '每日两次', value: 'BID' },
+ { label: '每日三次', value: 'TID' },
+ { label: '每晚一次', value: 'QN' },
+ { label: '每周一次', value: 'QW' },
+ { label: '必要时', value: 'PRN' },
+];
+
+export const ROUTE_OPTIONS = [
+ { label: '口服', value: 'oral' },
+ { label: '静脉注射', value: 'iv' },
+ { label: '皮下注射', value: 'sc' },
+ { label: '外用', value: 'topical' },
+ { label: '吸入', value: 'inhalation' },
+];
+
+// --- API ---
+
+export const medicationRecordApi = {
+ list: async (patientId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/medications`, { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: MedicationRecord;
+ }>(`/health/medications/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreateMedicationRecordReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: MedicationRecord;
+ }>('/health/medications', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateMedicationRecordReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: MedicationRecord;
+ }>(`/health/medications/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/medications/${id}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/medicationReminders.ts b/apps/web/src/api/health/medicationReminders.ts
new file mode 100644
index 0000000..51a2841
--- /dev/null
+++ b/apps/web/src/api/health/medicationReminders.ts
@@ -0,0 +1,75 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface MedicationReminder {
+ id: string;
+ patient_id: string;
+ medication_name: string;
+ dosage?: string;
+ frequency: string;
+ reminder_times: unknown;
+ start_date?: string;
+ end_date?: string;
+ is_active: boolean;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateMedicationReminderReq {
+ patient_id: string;
+ medication_name: string;
+ dosage?: string;
+ frequency?: string;
+ reminder_times?: unknown;
+ start_date?: string;
+ end_date?: string;
+ is_active?: boolean;
+ notes?: string;
+}
+
+export interface UpdateMedicationReminderReq {
+ medication_name?: string;
+ dosage?: string;
+ frequency?: string;
+ reminder_times?: unknown;
+ start_date?: string;
+ end_date?: string;
+ is_active?: boolean;
+ notes?: string;
+}
+
+// --- API ---
+
+export const medicationReminderApi = {
+ list: async (patientId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/patients/${patientId}/medication-reminders`, { params });
+ return data.data;
+ },
+
+ create: async (req: CreateMedicationReminderReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: MedicationReminder;
+ }>('/health/medication-reminders', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdateMedicationReminderReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: MedicationReminder;
+ }>(`/health/medication-reminders/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/medication-reminders/${id}`, { data: { version } });
+ },
+};
diff --git a/apps/web/src/api/health/oauthClients.ts b/apps/web/src/api/health/oauthClients.ts
new file mode 100644
index 0000000..9ff7615
--- /dev/null
+++ b/apps/web/src/api/health/oauthClients.ts
@@ -0,0 +1,73 @@
+import client from '../client';
+
+// --- Types ---
+export interface OAuthClient {
+ id: string;
+ client_id: string;
+ client_name: string;
+ scopes: string[];
+ rate_limit_per_minute: number;
+ is_active: boolean;
+ token_lifetime_seconds: number;
+ created_at: string;
+ version: number;
+}
+
+export interface OAuthClientDetail extends OAuthClient {
+ tenant_id: string;
+ client_secret: string;
+ allowed_patient_ids?: string[];
+}
+
+export interface CreateOAuthClientReq {
+ client_name: string;
+ scopes: string[];
+ allowed_patient_ids?: string[];
+ rate_limit_per_minute?: number;
+ token_lifetime_seconds?: number;
+}
+
+export interface UpdateOAuthClientReq {
+ client_name?: string;
+ scopes?: string[];
+ allowed_patient_ids?: string[] | null;
+ rate_limit_per_minute?: number;
+ is_active?: boolean;
+ token_lifetime_seconds?: number;
+ version: number;
+}
+
+export interface RegenerateSecretResp {
+ client_id: string;
+ client_secret: string;
+}
+
+// --- FHIR Scope ---
+export const FHIR_SCOPE_OPTIONS = [
+ { value: 'Patient.read', label: 'Patient.read — 读取患者' },
+ { value: 'Observation.read', label: 'Observation.read — 读取体征' },
+ { value: 'Device.read', label: 'Device.read — 读取设备' },
+ { value: 'DiagnosticReport.read', label: 'DiagnosticReport.read — 读取诊断报告' },
+ { value: 'Encounter.read', label: 'Encounter.read — 读取就诊记录' },
+ { value: 'Practitioner.read', label: 'Practitioner.read — 读取医护' },
+ { value: 'Appointment.read', label: 'Appointment.read — 读取预约' },
+ { value: 'Task.read', label: 'Task.read — 读取随访任务' },
+];
+
+// --- API ---
+export const oauthClientApi = {
+ list: () =>
+ client.get('/health/oauth/clients').then((r) => r.data.data as OAuthClient[]),
+
+ create: (data: CreateOAuthClientReq) =>
+ client.post('/health/oauth/clients', data).then((r) => r.data.data as OAuthClientDetail),
+
+ update: (id: string, data: UpdateOAuthClientReq) =>
+ client.put(`/health/oauth/clients/${id}`, data).then((r) => r.data.data as OAuthClient),
+
+ delete: (id: string) =>
+ client.delete(`/health/oauth/clients/${id}`).then((r) => r.data),
+
+ regenerateSecret: (id: string) =>
+ client.post(`/health/oauth/clients/${id}/regenerate-secret`).then((r) => r.data.data as RegenerateSecretResp),
+};
diff --git a/apps/web/src/api/health/patients.test.ts b/apps/web/src/api/health/patients.test.ts
new file mode 100644
index 0000000..9654cc1
--- /dev/null
+++ b/apps/web/src/api/health/patients.test.ts
@@ -0,0 +1,126 @@
+/**
+ * patients API 契约测试
+ *
+ * 验证 patientApi 各函数调用正确的 HTTP 方法、URL 路径和参数序列化。
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { patientApi } from './patients'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('patientApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('list 应调用 GET /health/patients 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await patientApi.list({ page: 1, page_size: 20, search: '张三', status: 'active' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients', {
+ params: { page: 1, page_size: 20, search: '张三', status: 'active' },
+ })
+ })
+
+ it('list 应支持 tag_id 过滤参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await patientApi.list({ tag_id: 'tag-001' })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients', {
+ params: { tag_id: 'tag-001' },
+ })
+ })
+
+ it('get 应调用 GET /health/patients/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await patientApi.get('p-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001')
+ })
+
+ it('create 应调用 POST /health/patients 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '李四', gender: 'male', birth_date: '1990-01-01' }
+ await patientApi.create(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients', req)
+ })
+
+ it('update 应调用 PUT /health/patients/:id 并传递请求体含 version', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '李四改', version: 2 }
+ await patientApi.update('p-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001', req)
+ })
+
+ it('delete 应调用 DELETE /health/patients/:id 并在 body 中传递 version', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await patientApi.delete('p-001', 3)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001', {
+ data: { version: 3 },
+ })
+ })
+
+ it('manageTags 应调用 POST /health/patients/:id/tags 并传递 tag_ids', async () => {
+ mockPost.mockResolvedValue(undefined)
+ await patientApi.manageTags('p-001', ['tag-1', 'tag-2'])
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/tags', {
+ tag_ids: ['tag-1', 'tag-2'],
+ })
+ })
+
+ it('listFamilyMembers 应调用 GET /health/patients/:id/family-members', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await patientApi.listFamilyMembers('p-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patients/p-001/family-members')
+ })
+
+ it('createFamilyMember 应调用 POST /health/patients/:id/family-members', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '家属A', relationship: 'spouse', phone: '13800138000' }
+ await patientApi.createFamilyMember('p-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/patients/p-001/family-members', req)
+ })
+
+ it('updateFamilyMember 应调用 PUT /health/patients/:pid/family-members/:mid', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '家属A改', version: 1 }
+ await patientApi.updateFamilyMember('p-001', 'fm-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/patients/p-001/family-members/fm-001', req)
+ })
+
+ it('deleteFamilyMember 应调用 DELETE /health/patients/:pid/family-members/:mid', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await patientApi.deleteFamilyMember('p-001', 'fm-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/patients/p-001/family-members/fm-001')
+ })
+
+ it('listTags 应调用 GET /health/patient-tags', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await patientApi.listTags()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/patient-tags')
+ })
+})
diff --git a/apps/web/src/api/health/patients.ts b/apps/web/src/api/health/patients.ts
new file mode 100644
index 0000000..89472a0
--- /dev/null
+++ b/apps/web/src/api/health/patients.ts
@@ -0,0 +1,175 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+export interface PatientListItem {
+ id: string;
+ name: string;
+ gender?: string;
+ birth_date?: string;
+ blood_type?: string;
+ status: string;
+ verification_status: string;
+ source?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface PatientDetail {
+ id: string;
+ user_id?: string;
+ name: string;
+ gender?: string;
+ birth_date?: string;
+ blood_type?: string;
+ id_number?: string;
+ allergy_history?: string;
+ medical_history_summary?: string;
+ emergency_contact_name?: string;
+ emergency_contact_phone?: string;
+ status: string;
+ verification_status: string;
+ source?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreatePatientReq {
+ name: string;
+ gender?: string;
+ birth_date?: string;
+ blood_type?: string;
+ id_number?: string;
+ allergy_history?: string;
+ medical_history_summary?: string;
+ emergency_contact_name?: string;
+ emergency_contact_phone?: string;
+ source?: string;
+ notes?: string;
+}
+
+export interface UpdatePatientReq extends Partial {
+ status?: string;
+ verification_status?: string;
+}
+
+export interface FamilyMember {
+ id: string;
+ name: string;
+ relationship: string;
+ phone?: string;
+ id_number?: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateFamilyMemberReq {
+ name: string;
+ relationship: string;
+ phone?: string;
+ id_number?: string;
+ notes?: string;
+}
+
+export interface TagItem {
+ id: string;
+ name: string;
+ color: string | null;
+ description: string | null;
+}
+
+// --- API ---
+export const patientApi = {
+ list: async (params: {
+ page?: number;
+ page_size?: number;
+ search?: string;
+ status?: string;
+ tag_id?: string;
+ }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/patients', { params });
+ return data.data;
+ },
+
+ get: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PatientDetail;
+ }>(`/health/patients/${id}`);
+ return data.data;
+ },
+
+ create: async (req: CreatePatientReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PatientDetail;
+ }>('/health/patients', req);
+ return data.data;
+ },
+
+ update: async (id: string, req: UpdatePatientReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: PatientDetail;
+ }>(`/health/patients/${id}`, req);
+ return data.data;
+ },
+
+ delete: async (id: string, version: number) => {
+ await client.delete(`/health/patients/${id}`, { data: { version } });
+ },
+
+ manageTags: async (id: string, tagIds: string[]) => {
+ await client.post(`/health/patients/${id}/tags`, { tag_ids: tagIds });
+ },
+
+ listFamilyMembers: async (id: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FamilyMember[];
+ }>(`/health/patients/${id}/family-members`);
+ return data.data;
+ },
+
+ createFamilyMember: async (id: string, req: CreateFamilyMemberReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: FamilyMember;
+ }>(`/health/patients/${id}/family-members`, req);
+ return data.data;
+ },
+
+ updateFamilyMember: async (
+ patientId: string,
+ memberId: string,
+ req: Partial & { version: number },
+ ) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: FamilyMember;
+ }>(`/health/patients/${patientId}/family-members/${memberId}`, req);
+ return data.data;
+ },
+
+ deleteFamilyMember: async (patientId: string, memberId: string) => {
+ await client.delete(
+ `/health/patients/${patientId}/family-members/${memberId}`,
+ );
+ },
+
+ listTags: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: TagItem[];
+ }>('/health/patient-tags');
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/points.test.ts b/apps/web/src/api/health/points.test.ts
new file mode 100644
index 0000000..a898c99
--- /dev/null
+++ b/apps/web/src/api/health/points.test.ts
@@ -0,0 +1,230 @@
+/**
+ * points API 契约测试(完整覆盖 pointsApi + pointsAdminApi)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('../client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import { pointsApi, pointsAdminApi } from './points'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('pointsAdminApi', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('getPatientAccount 应调用 GET /health/admin/points/patients/:id/account', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsAdminApi.getPatientAccount('p-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/patients/p-001/account')
+ })
+
+ it('listPatientTransactions 应调用 GET 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsAdminApi.listPatientTransactions('p-001', { page: 2, page_size: 15 })
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/patients/p-001/transactions', {
+ params: { page: 2, page_size: 15 },
+ })
+ })
+})
+
+describe('pointsApi - Rules', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listRules 应调用 GET /health/admin/points/rules', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.listRules()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/rules')
+ })
+
+ it('createRule 应调用 POST /health/admin/points/rules', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { event_type: 'daily_checkin', name: '每日签到', points_value: 10, daily_cap: 1 }
+ await pointsApi.createRule(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/admin/points/rules', req)
+ })
+
+ it('updateRule 应调用 PUT /health/admin/points/rules/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { points_value: 20, version: 1 }
+ await pointsApi.updateRule('rule-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/admin/points/rules/rule-001', {
+ data: req,
+ version: req.version,
+ })
+ })
+
+ it('deleteRule 应调用 DELETE /health/admin/points/rules/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await pointsApi.deleteRule('rule-001', 2)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/admin/points/rules/rule-001', {
+ data: { version: 2 },
+ })
+ })
+})
+
+describe('pointsApi - Products', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listProducts 应调用 GET /health/points/products', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.listProducts()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/points/products', { params: undefined })
+ })
+
+ it('createProduct 应调用 POST /health/admin/points/products', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '体检优惠券', product_type: 'service', points_cost: 500, stock: 100 }
+ await pointsApi.createProduct(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/admin/points/products', req)
+ })
+
+ it('updateProduct 应调用 PUT /health/admin/points/products/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { points_cost: 600, version: 1 }
+ await pointsApi.updateProduct('prod-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/admin/points/products/prod-001', {
+ data: req,
+ version: req.version,
+ })
+ })
+
+ it('deleteProduct 应调用 DELETE /health/admin/points/products/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await pointsApi.deleteProduct('prod-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/admin/points/products/prod-001', {
+ data: { version: 1 },
+ })
+ })
+})
+
+describe('pointsApi - Orders', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listOrders 应调用 GET /health/admin/points/orders', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.listOrders()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/orders', { params: undefined })
+ })
+
+ it('verifyOrder 应调用 POST /health/points/verify', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { qr_code: 'QR-123456' }
+ await pointsApi.verifyOrder(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/points/verify', req)
+ })
+})
+
+describe('pointsApi - Offline Events', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listOfflineEvents 应调用 GET /health/admin/offline-events', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.listOfflineEvents()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/offline-events', { params: undefined })
+ })
+
+ it('createOfflineEvent 应调用 POST /health/admin/offline-events', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { title: '健康讲座', event_date: '2026-05-20', points_reward: 50 }
+ await pointsApi.createOfflineEvent(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/health/admin/offline-events', req)
+ })
+
+ it('updateOfflineEvent 应调用 PUT /health/admin/offline-events/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { title: '健康讲座(更新)', version: 1 }
+ await pointsApi.updateOfflineEvent('evt-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/health/admin/offline-events/evt-001', req)
+ })
+
+ it('deleteOfflineEvent 应调用 DELETE /health/admin/offline-events/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await pointsApi.deleteOfflineEvent('evt-001', 1)
+
+ expect(mockDelete).toHaveBeenCalledWith('/health/admin/offline-events/evt-001', {
+ data: { version: 1 },
+ })
+ })
+})
+
+describe('pointsApi - Statistics', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('getStatistics 应调用 GET /health/admin/points/statistics', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getStatistics()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/points/statistics')
+ })
+
+ it('getPatientStats 应调用 GET /health/admin/statistics/patients', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getPatientStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/patients')
+ })
+
+ it('getConsultationStats 应调用 GET /health/admin/statistics/consultations', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getConsultationStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/consultations')
+ })
+
+ it('getFollowUpStats 应调用 GET /health/admin/statistics/follow-ups', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getFollowUpStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/follow-ups')
+ })
+
+ it('getHealthDataStats 应调用 GET /health/admin/statistics/health-data', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getHealthDataStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/health-data')
+ })
+
+ it('getDialysisStats 应调用 GET /health/admin/statistics/dialysis', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getDialysisStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/dialysis')
+ })
+
+ it('getPersonalStats 应调用 GET /health/admin/statistics/personal-stats', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pointsApi.getPersonalStats()
+
+ expect(mockGet).toHaveBeenCalledWith('/health/admin/statistics/personal-stats')
+ })
+})
diff --git a/apps/web/src/api/health/points.ts b/apps/web/src/api/health/points.ts
new file mode 100644
index 0000000..0265cbf
--- /dev/null
+++ b/apps/web/src/api/health/points.ts
@@ -0,0 +1,446 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface PointsRule {
+ id: string;
+ event_type: string;
+ name: string;
+ description: string | null;
+ points_value: number;
+ daily_cap: number;
+ streak_7d_bonus: number;
+ streak_14d_bonus: number;
+ streak_30d_bonus: number;
+ is_active: boolean;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreatePointsRuleReq {
+ event_type: string;
+ name: string;
+ description?: string;
+ points_value: number;
+ daily_cap?: number;
+ streak_7d_bonus?: number;
+ streak_14d_bonus?: number;
+ streak_30d_bonus?: number;
+}
+
+export interface PointsProduct {
+ id: string;
+ name: string;
+ product_type: string; // physical / service / privilege
+ points_cost: number;
+ stock: number;
+ image_url: string | null;
+ description: string | null;
+ is_active: boolean;
+ sort_order: number;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreatePointsProductReq {
+ name: string;
+ product_type: string;
+ points_cost: number;
+ stock: number;
+ description?: string;
+ image_url?: string;
+ sort_order?: number;
+}
+
+export interface PointsOrder {
+ id: string;
+ patient_id: string;
+ product_id: string;
+ product_name: string | null;
+ points_cost: number;
+ status: string; // pending / verified / cancelled / expired
+ qr_code: string;
+ verified_by: string | null;
+ verified_at: string | null;
+ expires_at: string | null;
+ notes: string | null;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface VerifyOrderReq {
+ qr_code: string;
+}
+
+export interface OfflineEvent {
+ id: string;
+ title: string;
+ description: string | null;
+ event_date: string;
+ start_time: string | null;
+ end_time: string | null;
+ location: string | null;
+ points_reward: number;
+ max_participants: number;
+ current_participants: number;
+ status: string; // draft / published / ongoing / completed / cancelled
+ image_url: string | null;
+ created_at: string;
+ updated_at: string;
+ version: number;
+}
+
+export interface CreateOfflineEventReq {
+ title: string;
+ description?: string;
+ event_date: string;
+ start_time?: string;
+ end_time?: string;
+ location?: string;
+ points_reward?: number;
+ max_participants?: number;
+ status?: string;
+ image_url?: string;
+}
+
+export interface PointsStatistics {
+ total_issued: number;
+ total_spent: number;
+ total_expired: number;
+ active_accounts: number;
+ top_earners: Array<{
+ account_id: string;
+ patient_id: string;
+ patient_name: string;
+ total_earned: number;
+ }>;
+}
+
+export interface PatientStatistics {
+ total_patients: number;
+ new_this_month: number;
+ new_this_week: number;
+ active_this_month: number;
+}
+
+export interface ConsultationStatistics {
+ total_sessions: number;
+ pending_reply: number;
+ avg_response_time_minutes: number | null;
+ this_month: number;
+}
+
+export interface FollowUpStatistics {
+ total_tasks: number;
+ completed: number;
+ pending: number;
+ overdue: number;
+ completion_rate: number;
+}
+
+export interface PersonalStats {
+ my_patients: number;
+ new_patients_this_month: number;
+ follow_up_rate: number;
+ consultations_this_month: number;
+ pending_consultations: number;
+ vital_signs_report_rate: number;
+ today_appointments: number;
+ overdue_follow_ups: number;
+ today_follow_ups: number;
+ abnormal_vital_signs: number;
+ vital_signs_reported: number;
+ vital_signs_total: number;
+ pending_lab_reviews: number;
+ yesterday_my_patients?: number;
+ yesterday_today_appointments?: number;
+ yesterday_consultations_this_month?: number;
+ yesterday_follow_up_rate?: number;
+ yesterday_today_follow_ups?: number;
+ yesterday_overdue_follow_ups?: number;
+}
+
+export interface OverviewStatistics {
+ patients: PatientStatistics;
+ consultations: ConsultationStatistics;
+ follow_ups: FollowUpStatistics;
+ points: PointsStatistics;
+}
+
+// --- Health Data Statistics Types ---
+
+export interface NameValue {
+ name: string;
+ value: number;
+}
+
+export interface DialysisStatistics {
+ total_records: number;
+ this_month: number;
+ type_distribution: NameValue[];
+ complication_rate: number;
+ avg_ultrafiltration: number | null;
+ avg_duration: number | null;
+ pending_review: number;
+}
+
+export interface LabReportStatistics {
+ total_reports: number;
+ this_month: number;
+ type_distribution: NameValue[];
+ abnormal_items: number;
+ pending_review: number;
+ reviewed: number;
+}
+
+export interface AppointmentStatistics {
+ total_appointments: number;
+ this_month: number;
+ status_distribution: NameValue[];
+ type_distribution: NameValue[];
+ cancel_rate: number;
+}
+
+export interface DailyReportRate {
+ date: string;
+ reported: number;
+ total: number;
+ rate: number;
+}
+
+export interface VitalSignsReportRate {
+ total_patients: number;
+ reported_patients: number;
+ report_rate: number;
+ total_records: number;
+ daily_trend: DailyReportRate[];
+}
+
+export interface HealthDataStats {
+ lab_reports: LabReportStatistics;
+ appointments: AppointmentStatistics;
+ vital_signs_report_rate: VitalSignsReportRate;
+}
+
+// --- API ---
+
+export interface PointsAccountDetail {
+ id: string;
+ patient_id: string;
+ balance: number;
+ total_earned: number;
+ total_spent: number;
+ total_expired: number;
+}
+
+export interface PointsTransactionDetail {
+ id: string;
+ account_id: string;
+ transaction_type: string;
+ amount: number;
+ remaining_amount: number;
+ status: string;
+ expires_at: string | null;
+ balance_after: number;
+ description: string | null;
+ created_at: string;
+}
+
+export const pointsAdminApi = {
+ getPatientAccount: async (patientId: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PointsAccountDetail;
+ }>(`/health/admin/points/patients/${patientId}/account`);
+ return data.data;
+ },
+
+ listPatientTransactions: async (
+ patientId: string,
+ params: { page?: number; page_size?: number },
+ ) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/admin/points/patients/${patientId}/transactions`, { params });
+ return data.data;
+ },
+};
+
+// --- API (original) ---
+
+export const pointsApi = {
+ // Rules
+ listRules: async () => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PointsRule[];
+ }>('/health/admin/points/rules');
+ return data.data;
+ },
+
+ createRule: async (req: CreatePointsRuleReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PointsRule;
+ }>('/health/admin/points/rules', req);
+ return data.data;
+ },
+
+ updateRule: async (id: string, req: Partial & { is_active?: boolean; version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: PointsRule;
+ }>(`/health/admin/points/rules/${id}`, req);
+ return data.data;
+ },
+
+ deleteRule: async (id: string, version: number) => {
+ await client.delete(`/health/admin/points/rules/${id}`, {
+ data: { version },
+ });
+ },
+
+ // Products
+ listProducts: async (params?: Record) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/points/products', { params });
+ return data.data;
+ },
+
+ createProduct: async (req: CreatePointsProductReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PointsProduct;
+ }>('/health/admin/points/products', req);
+ return data.data;
+ },
+
+ updateProduct: async (id: string, req: Partial & { is_active?: boolean; version: number }) => {
+ const { version, ...fields } = req;
+ const { data } = await client.put<{
+ success: boolean;
+ data: PointsProduct;
+ }>(`/health/admin/points/products/${id}`, { data: fields, version });
+ return data.data;
+ },
+
+ deleteProduct: async (id: string, version: number) => {
+ await client.delete(`/health/admin/points/products/${id}`, {
+ data: { version },
+ });
+ },
+
+ // Orders
+ listOrders: async (params?: Record) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/admin/points/orders', { params });
+ return data.data;
+ },
+
+ verifyOrder: async (req: VerifyOrderReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PointsOrder;
+ }>('/health/points/verify', req);
+ return data.data;
+ },
+
+ // Offline Events
+ listOfflineEvents: async (params?: Record) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/admin/offline-events', { params });
+ return data.data;
+ },
+
+ createOfflineEvent: async (req: CreateOfflineEventReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: OfflineEvent;
+ }>('/health/admin/offline-events', req);
+ return data.data;
+ },
+
+ updateOfflineEvent: async (id: string, req: Partial & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: OfflineEvent;
+ }>(`/health/admin/offline-events/${id}`, req);
+ return data.data;
+ },
+
+ deleteOfflineEvent: async (id: string, version: number) => {
+ await client.delete(`/health/admin/offline-events/${id}`, {
+ data: { version },
+ });
+ },
+
+ // Points Statistics
+ getStatistics: async (opts?: { silent?: boolean }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PointsStatistics;
+ }>('/health/admin/points/statistics', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ // --- Dashboard Statistics ---
+
+ getPatientStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PatientStatistics;
+ }>('/health/admin/statistics/patients', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ getConsultationStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: ConsultationStatistics;
+ }>('/health/admin/statistics/consultations', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ getFollowUpStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: FollowUpStatistics;
+ }>('/health/admin/statistics/follow-ups', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ getHealthDataStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: HealthDataStats;
+ }>('/health/admin/statistics/health-data', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ getDialysisStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: DialysisStatistics;
+ }>('/health/admin/statistics/dialysis', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+
+ getPersonalStats: async (opts?: { silent?: boolean }): Promise => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PersonalStats;
+ }>('/health/admin/statistics/personal-stats', { skipGlobalError: opts?.silent });
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/health/shifts.ts b/apps/web/src/api/health/shifts.ts
new file mode 100644
index 0000000..05f2fbe
--- /dev/null
+++ b/apps/web/src/api/health/shifts.ts
@@ -0,0 +1,247 @@
+import client from '../client';
+import type { PaginatedResponse } from '../types';
+
+// --- Types ---
+
+export interface Shift {
+ id: string;
+ tenant_id: string;
+ shift_date: string;
+ period: string;
+ nurse_id?: string;
+ status: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+ patient_count?: number;
+ critical_count?: number;
+ attention_count?: number;
+}
+
+export interface PatientAssignment {
+ id: string;
+ tenant_id: string;
+ shift_id: string;
+ patient_id: string;
+ care_level: string;
+ notes?: string;
+ created_at: string;
+ updated_at: string;
+ version: number;
+ patient_name?: string;
+}
+
+export interface HandoffLog {
+ id: string;
+ tenant_id: string;
+ from_shift_id: string;
+ to_shift_id: string;
+ patient_id: string;
+ notes?: string;
+ pending_items?: Record;
+ created_at: string;
+ updated_at: string;
+ version: number;
+ patient_name?: string;
+}
+
+export interface CreateShiftReq {
+ shift_date: string;
+ period: string;
+ nurse_id?: string;
+ notes?: string;
+}
+
+export interface UpdateShiftReq {
+ shift_date?: string;
+ period?: string;
+ nurse_id?: string;
+ status?: string;
+ notes?: string;
+}
+
+export interface ListShiftsParams {
+ page?: number;
+ page_size?: number;
+ shift_date?: string;
+ period?: string;
+ nurse_id?: string;
+ status?: string;
+}
+
+export interface CreatePatientAssignmentReq {
+ patient_id: string;
+ care_level?: string;
+ notes?: string;
+}
+
+export interface BatchAssignReq {
+ patient_ids: string[];
+ care_level?: string;
+}
+
+export interface UpdatePatientAssignmentReq {
+ care_level?: string;
+ notes?: string;
+}
+
+export interface CreateHandoffReq {
+ from_shift_id: string;
+ to_shift_id: string;
+ patient_id: string;
+ notes?: string;
+ pending_items?: Record;
+}
+
+export interface ListHandoffParams {
+ page?: number;
+ page_size?: number;
+ from_shift_id?: string;
+ to_shift_id?: string;
+}
+
+// --- Constants ---
+
+export const PERIOD_OPTIONS = [
+ { label: '上午班', value: 'morning' },
+ { label: '下午班', value: 'afternoon' },
+ { label: '晚班', value: 'evening' },
+ { label: '夜班', value: 'night' },
+];
+
+export const SHIFT_STATUS_OPTIONS = [
+ { label: '待开始', value: 'scheduled' },
+ { label: '进行中', value: 'in_progress' },
+ { label: '已完成', value: 'completed' },
+ { label: '已取消', value: 'cancelled' },
+];
+
+export const CARE_LEVEL_OPTIONS = [
+ { label: '稳定', value: 'stable' },
+ { label: '需关注', value: 'attention' },
+ { label: '危重', value: 'critical' },
+];
+
+export const PERIOD_LABEL: Record = Object.fromEntries(
+ PERIOD_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const SHIFT_STATUS_LABEL: Record = Object.fromEntries(
+ SHIFT_STATUS_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const SHIFT_STATUS_COLOR: Record = {
+ scheduled: 'default',
+ in_progress: 'processing',
+ completed: 'success',
+ cancelled: 'error',
+};
+
+export const CARE_LEVEL_LABEL: Record = Object.fromEntries(
+ CARE_LEVEL_OPTIONS.map((o) => [o.value, o.label]),
+);
+
+export const CARE_LEVEL_COLOR: Record = {
+ stable: 'green',
+ attention: 'orange',
+ critical: 'red',
+};
+
+// --- API ---
+
+export const shiftApi = {
+ // --- Shifts ---
+
+ list: async (params: ListShiftsParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/shifts', { params });
+ return data.data;
+ },
+
+ get: async (shiftId: string) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: Shift;
+ }>(`/health/shifts/${shiftId}`);
+ return data.data;
+ },
+
+ create: async (req: CreateShiftReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: Shift;
+ }>('/health/shifts', req);
+ return data.data;
+ },
+
+ update: async (shiftId: string, req: UpdateShiftReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: Shift;
+ }>(`/health/shifts/${shiftId}`, req);
+ return data.data;
+ },
+
+ delete: async (shiftId: string, version: number) => {
+ await client.delete(`/health/shifts/${shiftId}`, { data: { version } });
+ },
+
+ // --- Assignments ---
+
+ listAssignments: async (shiftId: string, params?: { page?: number; page_size?: number }) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>(`/health/shifts/${shiftId}/assignments`, { params });
+ return data.data;
+ },
+
+ createAssignment: async (shiftId: string, req: CreatePatientAssignmentReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PatientAssignment;
+ }>(`/health/shifts/${shiftId}/assignments`, req);
+ return data.data;
+ },
+
+ batchAssign: async (shiftId: string, req: BatchAssignReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: PatientAssignment[];
+ }>(`/health/shifts/${shiftId}/assignments/batch`, req);
+ return data.data;
+ },
+
+ updateAssignment: async (shiftId: string, assignmentId: string, req: UpdatePatientAssignmentReq & { version: number }) => {
+ const { data } = await client.put<{
+ success: boolean;
+ data: PatientAssignment;
+ }>(`/health/shifts/${shiftId}/assignments/${assignmentId}`, req);
+ return data.data;
+ },
+
+ deleteAssignment: async (shiftId: string, assignmentId: string, version: number) => {
+ await client.delete(`/health/shifts/${shiftId}/assignments/${assignmentId}`, { data: { version } });
+ },
+
+ // --- Handoff Logs ---
+
+ listHandoffs: async (params?: ListHandoffParams) => {
+ const { data } = await client.get<{
+ success: boolean;
+ data: PaginatedResponse;
+ }>('/health/handoff-logs', { params });
+ return data.data;
+ },
+
+ createHandoff: async (req: CreateHandoffReq) => {
+ const { data } = await client.post<{
+ success: boolean;
+ data: HandoffLog;
+ }>('/health/handoff-logs', req);
+ return data.data;
+ },
+};
diff --git a/apps/web/src/api/languages.ts b/apps/web/src/api/languages.ts
new file mode 100644
index 0000000..ba61fdf
--- /dev/null
+++ b/apps/web/src/api/languages.ts
@@ -0,0 +1,34 @@
+import client from './client';
+
+// --- Types ---
+
+export interface LanguageInfo {
+ code: string;
+ name: string;
+ is_active: boolean;
+}
+
+export interface UpdateLanguageRequest {
+ is_active: boolean;
+ name?: string;
+}
+
+// --- API Functions ---
+
+export async function listLanguages(): Promise {
+ const { data } = await client.get<{ success: boolean; data: LanguageInfo[] }>(
+ '/config/languages',
+ );
+ return data.data;
+}
+
+export async function updateLanguage(
+ code: string,
+ req: UpdateLanguageRequest,
+): Promise {
+ const { data } = await client.put<{ success: boolean; data: LanguageInfo }>(
+ `/config/languages/${code}`,
+ req,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/menus.ts b/apps/web/src/api/menus.ts
new file mode 100644
index 0000000..f159088
--- /dev/null
+++ b/apps/web/src/api/menus.ts
@@ -0,0 +1,63 @@
+import client from './client';
+
+export interface MenuInfo {
+ id: string;
+ parent_id?: string;
+ title: string;
+ path?: string;
+ icon?: string;
+ sort_order: number;
+ visible: boolean;
+ menu_type: string;
+ permission?: string;
+ children?: MenuInfo[];
+ version: number;
+}
+
+export interface MenuItemReq {
+ id?: string;
+ parent_id?: string;
+ title: string;
+ path?: string;
+ icon?: string;
+ sort_order?: number;
+ visible?: boolean;
+ menu_type?: string;
+ permission?: string;
+ role_ids?: string[];
+ version?: number;
+}
+
+export async function getMenus() {
+ const { data } = await client.get<{ success: boolean; data: MenuInfo[] }>('/config/menus');
+ return data.data;
+}
+
+export async function getMenusForUser() {
+ const { data } = await client.get<{ success: boolean; data: MenuInfo[] }>('/menus/user');
+ return data.data;
+}
+
+export async function batchSaveMenus(menus: MenuItemReq[]) {
+ await client.put('/config/menus', { menus });
+}
+
+export async function createMenu(req: MenuItemReq) {
+ const { data } = await client.post<{ success: boolean; data: MenuInfo }>(
+ '/config/menus',
+ req,
+ );
+ return data.data;
+}
+
+export async function updateMenu(id: string, req: MenuItemReq) {
+ const { data } = await client.put<{ success: boolean; data: MenuInfo }>(
+ `/config/menus/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deleteMenu(id: string, version: number) {
+ await client.delete(`/config/menus/${id}`, { data: { version } });
+}
diff --git a/apps/web/src/api/messageTemplates.ts b/apps/web/src/api/messageTemplates.ts
new file mode 100644
index 0000000..0cfc4d2
--- /dev/null
+++ b/apps/web/src/api/messageTemplates.ts
@@ -0,0 +1,40 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface MessageTemplateInfo {
+ id: string;
+ tenant_id: string;
+ name: string;
+ code: string;
+ channel: string;
+ title_template: string;
+ body_template: string;
+ language: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface CreateTemplateRequest {
+ name: string;
+ code: string;
+ channel?: string;
+ title_template: string;
+ body_template: string;
+ language?: string;
+}
+
+export async function listTemplates(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/message-templates',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function createTemplate(req: CreateTemplateRequest) {
+ const { data } = await client.post<{ success: boolean; data: MessageTemplateInfo }>(
+ '/message-templates',
+ req,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/messages.test.ts b/apps/web/src/api/messages.test.ts
new file mode 100644
index 0000000..b8ed9cd
--- /dev/null
+++ b/apps/web/src/api/messages.test.ts
@@ -0,0 +1,100 @@
+/**
+ * messages + messageTemplates API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as messagesApi from './messages'
+import * as templateApi from './messageTemplates'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('messages API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listMessages 应调用 GET /messages 并传递查询参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await messagesApi.listMessages({ page: 2, page_size: 10, is_read: false, priority: 'high' })
+
+ expect(mockGet).toHaveBeenCalledWith('/messages', {
+ params: expect.objectContaining({
+ page: 2,
+ page_size: 10,
+ is_read: false,
+ priority: 'high',
+ }),
+ })
+ })
+
+ it('getUnreadCount 应调用 GET /messages/unread-count', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await messagesApi.getUnreadCount()
+
+ expect(mockGet).toHaveBeenCalledWith('/messages/unread-count')
+ })
+
+ it('markRead 应调用 PUT /messages/:id/read', async () => {
+ mockPut.mockResolvedValue({ data: { success: true } })
+ await messagesApi.markRead('msg-001')
+
+ expect(mockPut).toHaveBeenCalledWith('/messages/msg-001/read')
+ })
+
+ it('markAllRead 应调用 PUT /messages/read-all', async () => {
+ mockPut.mockResolvedValue({ data: { success: true } })
+ await messagesApi.markAllRead()
+
+ expect(mockPut).toHaveBeenCalledWith('/messages/read-all')
+ })
+
+ it('deleteMessage 应调用 DELETE /messages/:id', async () => {
+ mockDelete.mockResolvedValue({ data: { success: true } })
+ await messagesApi.deleteMessage('msg-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/messages/msg-001')
+ })
+
+ it('sendMessage 应调用 POST /messages 并传递请求体', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { title: '通知', body: '内容', recipient_id: 'u-001' }
+ await messagesApi.sendMessage(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/messages', req)
+ })
+})
+
+describe('messageTemplates API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listTemplates 应调用 GET /message-templates 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await templateApi.listTemplates(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/message-templates', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('createTemplate 应调用 POST /message-templates', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '预约提醒', code: 'appointment_reminder', title_template: '预约提醒', body_template: '您有预约' }
+ await templateApi.createTemplate(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/message-templates', req)
+ })
+})
diff --git a/apps/web/src/api/messages.ts b/apps/web/src/api/messages.ts
new file mode 100644
index 0000000..7e74795
--- /dev/null
+++ b/apps/web/src/api/messages.ts
@@ -0,0 +1,98 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface MessageInfo {
+ id: string;
+ tenant_id: string;
+ template_id?: string;
+ sender_id?: string;
+ sender_type: string;
+ recipient_id: string;
+ recipient_type: string;
+ title: string;
+ body: string;
+ priority: string;
+ business_type?: string;
+ business_id?: string;
+ is_read: boolean;
+ read_at?: string;
+ is_archived: boolean;
+ status: string;
+ sent_at?: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface SendMessageRequest {
+ title: string;
+ body: string;
+ recipient_id: string;
+ recipient_type?: string;
+ priority?: string;
+ template_id?: string;
+ business_type?: string;
+ business_id?: string;
+}
+
+export interface MessageQuery {
+ page?: number;
+ page_size?: number;
+ is_read?: boolean;
+ priority?: string;
+ business_type?: string;
+ status?: string;
+}
+
+export async function listMessages(query: MessageQuery = {}) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/messages',
+ { params: { page: query.page ?? 1, page_size: query.page_size ?? 20, ...query } },
+ );
+ return data.data;
+}
+
+export async function getUnreadCount() {
+ const { data } = await client.get<{ success: boolean; data: { count: number } }>(
+ '/messages/unread-count',
+ );
+ return data.data;
+}
+
+export async function markRead(id: string) {
+ const { data } = await client.put<{ success: boolean }>(
+ `/messages/${id}/read`,
+ );
+ return data;
+}
+
+export async function markAllRead() {
+ const { data } = await client.put<{ success: boolean }>(
+ '/messages/read-all',
+ );
+ return data;
+}
+
+export async function deleteMessage(id: string) {
+ const { data } = await client.delete<{ success: boolean }>(
+ `/messages/${id}`,
+ );
+ return data;
+}
+
+export async function sendMessage(req: SendMessageRequest) {
+ const { data } = await client.post<{ success: boolean; data: MessageInfo }>(
+ '/messages',
+ req,
+ );
+ return data.data;
+}
+
+export interface SubscriptionUpdateReq {
+ dnd_enabled: boolean;
+ dnd_start?: string;
+ dnd_end?: string;
+}
+
+export async function updateSubscription(req: SubscriptionUpdateReq) {
+ await client.put('/message-subscriptions', req);
+}
diff --git a/apps/web/src/api/numberingRules.ts b/apps/web/src/api/numberingRules.ts
new file mode 100644
index 0000000..fd29bfe
--- /dev/null
+++ b/apps/web/src/api/numberingRules.ts
@@ -0,0 +1,73 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface NumberingRuleInfo {
+ id: string;
+ name: string;
+ code: string;
+ prefix: string;
+ date_format?: string;
+ seq_length: number;
+ seq_start: number;
+ seq_current: number;
+ separator: string;
+ reset_cycle: string;
+ last_reset_date?: string;
+ version: number;
+}
+
+export interface CreateNumberingRuleRequest {
+ name: string;
+ code: string;
+ prefix?: string;
+ date_format?: string;
+ seq_length?: number;
+ seq_start?: number;
+ separator?: string;
+ reset_cycle?: string;
+}
+
+export interface UpdateNumberingRuleRequest {
+ name?: string;
+ prefix?: string;
+ date_format?: string;
+ seq_length?: number;
+ separator?: string;
+ reset_cycle?: string;
+ version: number;
+}
+
+export async function listNumberingRules(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/config/numbering-rules',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function createNumberingRule(req: CreateNumberingRuleRequest) {
+ const { data } = await client.post<{ success: boolean; data: NumberingRuleInfo }>(
+ '/config/numbering-rules',
+ req,
+ );
+ return data.data;
+}
+
+export async function updateNumberingRule(id: string, req: UpdateNumberingRuleRequest) {
+ const { data } = await client.put<{ success: boolean; data: NumberingRuleInfo }>(
+ `/config/numbering-rules/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function generateNumber(id: string) {
+ const { data } = await client.post<{ success: boolean; data: { number: string } }>(
+ `/config/numbering-rules/${id}/generate`,
+ );
+ return data.data;
+}
+
+export async function deleteNumberingRule(id: string, version: number) {
+ await client.delete(`/config/numbering-rules/${id}`, { data: { version } });
+}
diff --git a/apps/web/src/api/orgs.test.ts b/apps/web/src/api/orgs.test.ts
new file mode 100644
index 0000000..d5718d7
--- /dev/null
+++ b/apps/web/src/api/orgs.test.ts
@@ -0,0 +1,126 @@
+/**
+ * orgs API 契约测试(组织/部门/岗位)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as orgsApi from './orgs'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('organizations API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listOrgTree 应调用 GET /organizations', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await orgsApi.listOrgTree()
+
+ expect(mockGet).toHaveBeenCalledWith('/organizations')
+ })
+
+ it('createOrg 应调用 POST /organizations', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '总公司', code: 'HQ' }
+ await orgsApi.createOrg(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/organizations', req)
+ })
+
+ it('updateOrg 应调用 PUT /organizations/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '改名', version: 1 }
+ await orgsApi.updateOrg('org-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/organizations/org-001', req)
+ })
+
+ it('deleteOrg 应调用 DELETE /organizations/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await orgsApi.deleteOrg('org-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/organizations/org-001')
+ })
+})
+
+describe('departments API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listDeptTree 应调用 GET /organizations/:orgId/departments', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await orgsApi.listDeptTree('org-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/organizations/org-001/departments')
+ })
+
+ it('createDept 应调用 POST /organizations/:orgId/departments', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '内科', code: 'NK' }
+ await orgsApi.createDept('org-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/organizations/org-001/departments', req)
+ })
+
+ it('updateDept 应调用 PUT /departments/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '内科(更新)', version: 1 }
+ await orgsApi.updateDept('dept-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/departments/dept-001', req)
+ })
+
+ it('deleteDept 应调用 DELETE /departments/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await orgsApi.deleteDept('dept-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/departments/dept-001')
+ })
+})
+
+describe('positions API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listPositions 应调用 GET /departments/:deptId/positions', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await orgsApi.listPositions('dept-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/departments/dept-001/positions')
+ })
+
+ it('createPosition 应调用 POST /departments/:deptId/positions', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '主治医师', code: 'ZYS' }
+ await orgsApi.createPosition('dept-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/departments/dept-001/positions', req)
+ })
+
+ it('updatePosition 应调用 PUT /positions/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '主任医师', version: 1 }
+ await orgsApi.updatePosition('pos-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/positions/pos-001', req)
+ })
+
+ it('deletePosition 应调用 DELETE /positions/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await orgsApi.deletePosition('pos-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/positions/pos-001')
+ })
+})
diff --git a/apps/web/src/api/orgs.ts b/apps/web/src/api/orgs.ts
new file mode 100644
index 0000000..d70afc3
--- /dev/null
+++ b/apps/web/src/api/orgs.ts
@@ -0,0 +1,174 @@
+import client from './client';
+
+// --- Organization types ---
+
+export interface OrganizationInfo {
+ id: string;
+ name: string;
+ code?: string;
+ parent_id?: string;
+ path?: string;
+ level: number;
+ sort_order: number;
+ children: OrganizationInfo[];
+ version: number;
+}
+
+export interface CreateOrganizationRequest {
+ name: string;
+ code?: string;
+ parent_id?: string;
+ sort_order?: number;
+}
+
+export interface UpdateOrganizationRequest {
+ name?: string;
+ code?: string;
+ sort_order?: number;
+ version: number;
+}
+
+// --- Department types ---
+
+export interface DepartmentInfo {
+ id: string;
+ org_id: string;
+ name: string;
+ code?: string;
+ parent_id?: string;
+ manager_id?: string;
+ path?: string;
+ sort_order: number;
+ children: DepartmentInfo[];
+ version: number;
+}
+
+export interface CreateDepartmentRequest {
+ name: string;
+ code?: string;
+ parent_id?: string;
+ manager_id?: string;
+ sort_order?: number;
+}
+
+export interface UpdateDepartmentRequest {
+ name?: string;
+ code?: string;
+ manager_id?: string;
+ sort_order?: number;
+ version: number;
+}
+
+// --- Position types ---
+
+export interface PositionInfo {
+ id: string;
+ dept_id: string;
+ name: string;
+ code?: string;
+ level: number;
+ sort_order: number;
+ version: number;
+}
+
+export interface CreatePositionRequest {
+ name: string;
+ code?: string;
+ level?: number;
+ sort_order?: number;
+}
+
+export interface UpdatePositionRequest {
+ name?: string;
+ code?: string;
+ level?: number;
+ sort_order?: number;
+ version: number;
+}
+
+// --- Organization API ---
+
+export async function listOrgTree() {
+ const { data } = await client.get<{ success: boolean; data: OrganizationInfo[] }>(
+ '/organizations',
+ );
+ return data.data;
+}
+
+export async function createOrg(req: CreateOrganizationRequest) {
+ const { data } = await client.post<{ success: boolean; data: OrganizationInfo }>(
+ '/organizations',
+ req,
+ );
+ return data.data;
+}
+
+export async function updateOrg(id: string, req: UpdateOrganizationRequest) {
+ const { data } = await client.put<{ success: boolean; data: OrganizationInfo }>(
+ `/organizations/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deleteOrg(id: string) {
+ await client.delete(`/organizations/${id}`);
+}
+
+// --- Department API ---
+
+export async function listDeptTree(orgId: string) {
+ const { data } = await client.get<{ success: boolean; data: DepartmentInfo[] }>(
+ `/organizations/${orgId}/departments`,
+ );
+ return data.data;
+}
+
+export async function createDept(orgId: string, req: CreateDepartmentRequest) {
+ const { data } = await client.post<{ success: boolean; data: DepartmentInfo }>(
+ `/organizations/${orgId}/departments`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deleteDept(id: string) {
+ await client.delete(`/departments/${id}`);
+}
+
+export async function updateDept(id: string, req: UpdateDepartmentRequest) {
+ const { data } = await client.put<{ success: boolean; data: DepartmentInfo }>(
+ `/departments/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+// --- Position API ---
+
+export async function listPositions(deptId: string) {
+ const { data } = await client.get<{ success: boolean; data: PositionInfo[] }>(
+ `/departments/${deptId}/positions`,
+ );
+ return data.data;
+}
+
+export async function createPosition(deptId: string, req: CreatePositionRequest) {
+ const { data } = await client.post<{ success: boolean; data: PositionInfo }>(
+ `/departments/${deptId}/positions`,
+ req,
+ );
+ return data.data;
+}
+
+export async function deletePosition(id: string) {
+ await client.delete(`/positions/${id}`);
+}
+
+export async function updatePosition(id: string, req: UpdatePositionRequest) {
+ const { data } = await client.put<{ success: boolean; data: PositionInfo }>(
+ `/positions/${id}`,
+ req,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/pluginData.test.ts b/apps/web/src/api/pluginData.test.ts
new file mode 100644
index 0000000..378cefc
--- /dev/null
+++ b/apps/web/src/api/pluginData.test.ts
@@ -0,0 +1,131 @@
+/**
+ * pluginData API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockPatch = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ patch: (...args: unknown[]) => mockPatch(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as pluginDataApi from './pluginData'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('pluginData CRUD', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listPluginData 应调用 GET /plugins/:pid/:entity 并传递分页和过滤参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginDataApi.listPluginData('crm', 'customer', 1, 20, {
+ filter: { status: 'active' },
+ search: '张',
+ sort_by: 'name',
+ sort_order: 'asc',
+ })
+
+ expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer', {
+ params: expect.objectContaining({
+ page: '1',
+ page_size: '20',
+ search: '张',
+ sort_by: 'name',
+ sort_order: 'asc',
+ }),
+ })
+ })
+
+ it('getPluginData 应调用 GET /plugins/:pid/:entity/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginDataApi.getPluginData('crm', 'customer', 'rec-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/rec-001')
+ })
+
+ it('createPluginData 应调用 POST /plugins/:pid/:entity 并包裹 data', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const recordData = { name: '客户A', phone: '13800138000' }
+ await pluginDataApi.createPluginData('crm', 'customer', recordData)
+
+ expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer', { data: recordData })
+ })
+
+ it('updatePluginData 应调用 PUT /plugins/:pid/:entity/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const recordData = { name: '客户A(更新)' }
+ await pluginDataApi.updatePluginData('crm', 'customer', 'rec-001', recordData, 2)
+
+ expect(mockPut).toHaveBeenCalledWith('/plugins/crm/customer/rec-001', {
+ data: recordData,
+ version: 2,
+ })
+ })
+
+ it('deletePluginData 应调用 DELETE /plugins/:pid/:entity/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await pluginDataApi.deletePluginData('crm', 'customer', 'rec-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/plugins/crm/customer/rec-001')
+ })
+})
+
+describe('pluginData 高级查询', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('countPluginData 应调用 GET /plugins/:pid/:entity/count', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginDataApi.countPluginData('crm', 'customer', { filter: { status: 'active' } })
+
+ expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/count', {
+ params: expect.objectContaining({
+ filter: '{"status":"active"}',
+ }),
+ })
+ })
+
+ it('aggregatePluginData 应调用 GET /plugins/:pid/:entity/aggregate', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginDataApi.aggregatePluginData('crm', 'customer', 'status')
+
+ expect(mockGet).toHaveBeenCalledWith('/plugins/crm/customer/aggregate', {
+ params: { group_by: 'status' },
+ })
+ })
+
+ it('batchPluginData 应调用 POST /plugins/:pid/:entity/batch', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { action: 'delete', ids: ['rec-1', 'rec-2'] }
+ await pluginDataApi.batchPluginData('crm', 'customer', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/batch', req)
+ })
+
+ it('resolveRefLabels 应调用 POST /plugins/:pid/:entity/resolve-labels', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const fields = { customer_tag_id: ['tag-1', 'tag-2'] }
+ await pluginDataApi.resolveRefLabels('crm', 'customer', fields)
+
+ expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/resolve-labels', { fields })
+ })
+
+ it('importPluginData 应调用 POST /plugins/:pid/:entity/import', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const rows = [{ name: '客户A' }, { name: '客户B' }]
+ await pluginDataApi.importPluginData('crm', 'customer', rows)
+
+ expect(mockPost).toHaveBeenCalledWith('/plugins/crm/customer/import', { rows })
+ })
+})
diff --git a/apps/web/src/api/pluginData.ts b/apps/web/src/api/pluginData.ts
new file mode 100644
index 0000000..302d42f
--- /dev/null
+++ b/apps/web/src/api/pluginData.ts
@@ -0,0 +1,281 @@
+import client from './client';
+
+export interface PluginDataRecord {
+ id: string;
+ data: Record;
+ created_at?: string;
+ updated_at?: string;
+ version?: number;
+}
+
+interface PaginatedDataResponse {
+ data: PluginDataRecord[];
+ total: number;
+ page: number;
+ page_size: number;
+ total_pages: number;
+}
+
+export interface PluginDataListOptions {
+ filter?: Record;
+ search?: string;
+ sort_by?: string;
+ sort_order?: 'asc' | 'desc';
+}
+
+export async function listPluginData(
+ pluginId: string,
+ entity: string,
+ page = 1,
+ pageSize = 20,
+ options?: PluginDataListOptions,
+) {
+ const params: Record = {
+ page: String(page),
+ page_size: String(pageSize),
+ };
+ if (options?.filter) params.filter = JSON.stringify(options.filter);
+ if (options?.search) params.search = options.search;
+ if (options?.sort_by) params.sort_by = options.sort_by;
+ if (options?.sort_order) params.sort_order = options.sort_order;
+
+ const { data } = await client.get<{ success: boolean; data: PaginatedDataResponse }>(
+ `/plugins/${pluginId}/${entity}`,
+ { params },
+ );
+ return data.data;
+}
+
+export async function getPluginData(pluginId: string, entity: string, id: string) {
+ const { data } = await client.get<{ success: boolean; data: PluginDataRecord }>(
+ `/plugins/${pluginId}/${entity}/${id}`,
+ );
+ return data.data;
+}
+
+export async function createPluginData(
+ pluginId: string,
+ entity: string,
+ recordData: Record,
+) {
+ const { data } = await client.post<{ success: boolean; data: PluginDataRecord }>(
+ `/plugins/${pluginId}/${entity}`,
+ { data: recordData },
+ );
+ return data.data;
+}
+
+export async function updatePluginData(
+ pluginId: string,
+ entity: string,
+ id: string,
+ recordData: Record,
+ version: number,
+) {
+ const { data } = await client.put<{ success: boolean; data: PluginDataRecord }>(
+ `/plugins/${pluginId}/${entity}/${id}`,
+ { data: recordData, version },
+ );
+ return data.data;
+}
+
+export async function deletePluginData(
+ pluginId: string,
+ entity: string,
+ id: string,
+) {
+ await client.delete(`/plugins/${pluginId}/${entity}/${id}`);
+}
+
+export async function countPluginData(
+ pluginId: string,
+ entity: string,
+ options?: { filter?: Record; search?: string },
+) {
+ const params: Record = {};
+ if (options?.filter) params.filter = JSON.stringify(options.filter);
+ if (options?.search) params.search = options.search;
+
+ const { data } = await client.get<{ success: boolean; data: number }>(
+ `/plugins/${pluginId}/${entity}/count`,
+ { params },
+ );
+ return data.data;
+}
+
+export interface AggregateItem {
+ key: string;
+ count: number;
+}
+
+export async function aggregatePluginData(
+ pluginId: string,
+ entity: string,
+ groupBy: string,
+ filter?: Record,
+) {
+ const params: Record = { group_by: groupBy };
+ if (filter) params.filter = JSON.stringify(filter);
+
+ const { data } = await client.get<{ success: boolean; data: AggregateItem[] }>(
+ `/plugins/${pluginId}/${entity}/aggregate`,
+ { params },
+ );
+ return data.data;
+}
+
+// ── 批量操作 ──
+
+export async function batchPluginData(
+ pluginId: string,
+ entity: string,
+ req: { action: string; ids: string[]; data?: Record },
+) {
+ const { data } = await client.post<{ success: boolean; data: unknown }>(
+ `/plugins/${pluginId}/${entity}/batch`,
+ req,
+ );
+ return data.data;
+}
+
+// ── 部分更新 ──
+
+export async function patchPluginData(
+ pluginId: string,
+ entity: string,
+ id: string,
+ req: { data: Record; version: number },
+) {
+ const { data } = await client.patch<{ success: boolean; data: PluginDataRecord }>(
+ `/plugins/${pluginId}/${entity}/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+// ── 时间序列 ──
+
+export async function getPluginTimeseries(
+ pluginId: string,
+ entity: string,
+ params: {
+ time_field: string;
+ time_grain: string;
+ start?: string;
+ end?: string;
+ },
+) {
+ const { data } = await client.get<{ success: boolean; data: unknown }>(
+ `/plugins/${pluginId}/${entity}/timeseries`,
+ { params },
+ );
+ return data.data;
+}
+
+// ─── 跨插件引用 API ──────────────────────────────────────────────────
+
+export interface ResolveLabelsResult {
+ labels: Record>;
+ meta: Record;
+}
+
+export async function resolveRefLabels(
+ pluginId: string,
+ entity: string,
+ fields: Record,
+): Promise {
+ const { data } = await client.post<{ success: boolean; data: ResolveLabelsResult }>(
+ `/plugins/${pluginId}/${entity}/resolve-labels`,
+ { fields },
+ );
+ return data.data;
+}
+
+export interface PublicEntity {
+ manifest_id: string;
+ plugin_id: string;
+ entity_name: string;
+ display_name: string;
+}
+
+export async function getPluginEntityRegistry(): Promise {
+ const { data } = await client.get<{ success: boolean; data: PublicEntity[] }>(
+ '/plugin-registry/entities',
+ );
+ return data.data;
+}
+
+// ─── 数据导入导出 API ──────────────────────────────────────────────────
+
+export interface ExportOptions {
+ filter?: Record;
+ search?: string;
+ sort_by?: string;
+ sort_order?: 'asc' | 'desc';
+ format?: 'json' | 'csv' | 'xlsx';
+}
+
+export async function exportPluginData(
+ pluginId: string,
+ entity: string,
+ options?: ExportOptions,
+): Promise[]> {
+ const params: Record = {};
+ if (options?.filter) params.filter = JSON.stringify(options.filter);
+ if (options?.search) params.search = options.search;
+ if (options?.sort_by) params.sort_by = options.sort_by;
+ if (options?.sort_order) params.sort_order = options.sort_order;
+
+ const { data } = await client.get<{ success: boolean; data: Record[] }>(
+ `/plugins/${pluginId}/${entity}/export`,
+ { params },
+ );
+ return data.data;
+}
+
+export async function exportPluginDataAsBlob(
+ pluginId: string,
+ entity: string,
+ format: 'csv' | 'xlsx',
+ options?: Omit,
+): Promise {
+ const params: Record = { format };
+ if (options?.filter) params.filter = JSON.stringify(options.filter);
+ if (options?.search) params.search = options.search;
+ if (options?.sort_by) params.sort_by = options.sort_by;
+ if (options?.sort_order) params.sort_order = options.sort_order;
+
+ const response = await client.get(
+ `/plugins/${pluginId}/${entity}/export`,
+ { params, responseType: 'blob' },
+ );
+ return response.data as Blob;
+}
+
+export interface ImportRowError {
+ row: number;
+ errors: string[];
+}
+
+export interface ImportResult {
+ success_count: number;
+ error_count: number;
+ errors: ImportRowError[];
+}
+
+export async function importPluginData(
+ pluginId: string,
+ entity: string,
+ rows: Record[],
+): Promise {
+ const { data } = await client.post<{ success: boolean; data: ImportResult }>(
+ `/plugins/${pluginId}/${entity}/import`,
+ { rows },
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/plugins.test.ts b/apps/web/src/api/plugins.test.ts
new file mode 100644
index 0000000..cd5b6e8
--- /dev/null
+++ b/apps/web/src/api/plugins.test.ts
@@ -0,0 +1,132 @@
+/**
+ * plugins API 契约测试(插件管理 + 市场)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as pluginsApi from './plugins'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('plugins management API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listPlugins 应调用 GET /admin/plugins 并传递分页和状态', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.listPlugins(1, 10, 'enabled')
+
+ expect(mockGet).toHaveBeenCalledWith('/admin/plugins', {
+ params: { page: 1, page_size: 10, status: 'enabled' },
+ })
+ })
+
+ it('getPlugin 应调用 GET /admin/plugins/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.getPlugin('plug-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/admin/plugins/plug-001')
+ })
+
+ it('installPlugin 应调用 POST /admin/plugins/:id/install', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await pluginsApi.installPlugin('plug-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/admin/plugins/plug-001/install')
+ })
+
+ it('enablePlugin 应调用 POST /admin/plugins/:id/enable', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await pluginsApi.enablePlugin('plug-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/admin/plugins/plug-001/enable')
+ })
+
+ it('disablePlugin 应调用 POST /admin/plugins/:id/disable', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await pluginsApi.disablePlugin('plug-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/admin/plugins/plug-001/disable')
+ })
+
+ it('purgePlugin 应调用 DELETE /admin/plugins/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await pluginsApi.purgePlugin('plug-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/admin/plugins/plug-001')
+ })
+
+ it('getPluginHealth 应调用 GET /admin/plugins/:id/health', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.getPluginHealth('plug-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/admin/plugins/plug-001/health')
+ })
+
+ it('updatePluginConfig 应调用 PUT /admin/plugins/:id/config', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const config = { theme: 'dark' }
+ await pluginsApi.updatePluginConfig('plug-001', config, 1)
+
+ expect(mockPut).toHaveBeenCalledWith('/admin/plugins/plug-001/config', {
+ config,
+ version: 1,
+ })
+ })
+
+ it('getPluginSchema 应调用 GET /admin/plugins/:id/schema', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.getPluginSchema('plug-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/admin/plugins/plug-001/schema')
+ })
+})
+
+describe('plugin market API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listMarketEntries 应调用 GET /market/entries', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.listMarketEntries({ page: 1, page_size: 10, category: 'crm' })
+
+ expect(mockGet).toHaveBeenCalledWith('/market/entries', {
+ params: { page: 1, page_size: 10, category: 'crm' },
+ })
+ })
+
+ it('getMarketEntry 应调用 GET /market/entries/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await pluginsApi.getMarketEntry('mkt-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/market/entries/mkt-001')
+ })
+
+ it('installFromMarket 应调用 POST /market/entries/:id/install', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await pluginsApi.installFromMarket('mkt-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/market/entries/mkt-001/install')
+ })
+
+ it('submitMarketReview 应调用 POST /market/entries/:id/reviews', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const review = { rating: 5, review_text: '很好用' }
+ await pluginsApi.submitMarketReview('mkt-001', review)
+
+ expect(mockPost).toHaveBeenCalledWith('/market/entries/mkt-001/reviews', review)
+ })
+})
diff --git a/apps/web/src/api/plugins.ts b/apps/web/src/api/plugins.ts
new file mode 100644
index 0000000..8450082
--- /dev/null
+++ b/apps/web/src/api/plugins.ts
@@ -0,0 +1,375 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface PluginEntityInfo {
+ name: string;
+ display_name: string;
+ table_name: string;
+}
+
+export interface PluginPermissionInfo {
+ code: string;
+ name: string;
+ description: string;
+}
+
+export type PluginStatus = 'uploaded' | 'installed' | 'enabled' | 'running' | 'disabled' | 'uninstalled';
+
+export interface PluginInfo {
+ id: string;
+ name: string;
+ version: string;
+ description?: string;
+ author?: string;
+ status: PluginStatus;
+ config: Record;
+ installed_at?: string;
+ enabled_at?: string;
+ entities: PluginEntityInfo[];
+ permissions?: PluginPermissionInfo[];
+ record_version: number;
+}
+
+export async function listPlugins(page = 1, pageSize = 20, status?: string) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/admin/plugins',
+ { params: { page, page_size: pageSize, status: status || undefined } },
+ );
+ return data.data;
+}
+
+export async function getPlugin(id: string) {
+ const { data } = await client.get<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}`,
+ );
+ return data.data;
+}
+
+export async function uploadPlugin(wasmFile: File, manifestToml: string) {
+ const formData = new FormData();
+ formData.append('wasm', wasmFile);
+ formData.append('manifest', manifestToml);
+
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ '/admin/plugins/upload',
+ formData,
+ { headers: { 'Content-Type': 'multipart/form-data' }, timeout: 60000 },
+ );
+ return data.data;
+}
+
+export async function installPlugin(id: string) {
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}/install`,
+ );
+ return data.data;
+}
+
+export async function enablePlugin(id: string) {
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}/enable`,
+ );
+ return data.data;
+}
+
+export async function disablePlugin(id: string) {
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}/disable`,
+ );
+ return data.data;
+}
+
+export async function uninstallPlugin(id: string) {
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}/uninstall`,
+ );
+ return data.data;
+}
+
+export async function purgePlugin(id: string) {
+ await client.delete(`/admin/plugins/${id}`);
+}
+
+export async function getPluginHealth(id: string) {
+ const { data } = await client.get<{
+ success: boolean;
+ data: { plugin_id: string; status: string; details: Record };
+ }>(`/admin/plugins/${id}/health`);
+ return data.data;
+}
+
+export async function updatePluginConfig(id: string, config: Record, version: number) {
+ const { data } = await client.put<{ success: boolean; data: PluginInfo }>(
+ `/admin/plugins/${id}/config`,
+ { config, version },
+ );
+ return data.data;
+}
+
+export async function getPluginSchema(id: string): Promise {
+ const { data } = await client.get<{ success: boolean; data: PluginSchemaResponse }>(
+ `/admin/plugins/${id}/schema`,
+ );
+ return data.data;
+}
+
+// ── Schema 类型定义 ──
+
+export interface PluginFieldValidation {
+ pattern?: string;
+ message?: string;
+ min_length?: number;
+ max_length?: number;
+ min_value?: number;
+ max_value?: number;
+}
+
+export interface PluginFieldSchema {
+ name: string;
+ field_type: string;
+ required: boolean;
+ display_name?: string;
+ ui_widget?: string;
+ options?: { label: string; value: string }[];
+ searchable?: boolean;
+ filterable?: boolean;
+ sortable?: boolean;
+ visible_when?: string;
+ unique?: boolean;
+ ref_entity?: string;
+ ref_label_field?: string;
+ ref_search_fields?: string[];
+ ref_plugin?: string;
+ ref_fallback_label?: string;
+ cascade_from?: string;
+ cascade_filter?: string;
+ validation?: PluginFieldValidation;
+}
+
+export interface PluginRelationSchema {
+ entity: string;
+ foreign_key: string;
+ on_delete: 'cascade' | 'nullify' | 'restrict';
+ name?: string;
+ type?: 'one_to_many' | 'many_to_one' | 'many_to_many';
+ display_field?: string;
+}
+
+export interface PluginEntitySchema {
+ name: string;
+ display_name: string;
+ fields: PluginFieldSchema[];
+ relations?: PluginRelationSchema[];
+ data_scope?: boolean;
+ is_public?: boolean;
+ importable?: boolean;
+ exportable?: boolean;
+}
+
+export interface PluginSchemaResponse {
+ entities: PluginEntitySchema[];
+ ui?: PluginUiSchema;
+ settings?: PluginSettings;
+ numbering?: PluginNumbering[];
+ trigger_events?: PluginTriggerEvent[];
+}
+
+export interface PluginUiSchema {
+ pages: PluginPageSchema[];
+}
+
+export type PluginPageSchema =
+ | { type: 'crud'; entity: string; label: string; icon?: string; enable_search?: boolean; enable_views?: string[] }
+ | { type: 'tree'; entity: string; label: string; icon?: string; id_field: string; parent_field: string; label_field: string }
+ | { type: 'detail'; entity: string; label: string; sections: PluginSectionSchema[] }
+ | { type: 'tabs'; label: string; icon?: string; tabs: PluginPageSchema[] }
+ | { type: 'graph'; entity: string; label: string; relationship_entity: string; source_field: string; target_field: string; edge_label_field: string; node_label_field: string }
+ | { type: 'dashboard'; label: string; widgets?: DashboardWidget[] }
+ | {
+ type: 'kanban';
+ entity: string;
+ label: string;
+ icon?: string;
+ lane_field: string;
+ lane_order?: string[];
+ card_title_field: string;
+ card_subtitle_field?: string;
+ card_fields?: string[];
+ enable_drag?: boolean;
+ };
+
+export interface DashboardWidget {
+ type: 'stat_card' | 'bar_chart' | 'pie_chart' | 'funnel_chart' | 'line_chart'
+ | 'stat_cards' | 'action_list' | 'funnel' | 'card_list';
+ entity: string;
+ title: string;
+ icon?: string;
+ color?: string;
+ dimension_field?: string;
+ dimension_order?: string[];
+ metric?: string;
+ // stat_cards
+ cards?: StatCardDef[];
+ // action_list
+ max_items?: number;
+ queries?: ActionQueryDef[];
+ // funnel
+ lane_field?: string;
+ value_field?: string;
+ lane_order?: string[];
+ // card_list
+ filter?: string;
+ title_field?: string;
+ subtitle_field?: string;
+ tags?: string[];
+ label?: string;
+ label_field?: string;
+ action?: string;
+ sort?: string;
+}
+
+export interface StatCardDef {
+ entity: string;
+ aggregate?: string;
+ field?: string;
+ filter?: string;
+ label: string;
+ icon?: string;
+ color?: string;
+}
+
+export interface ActionQueryDef {
+ entity: string;
+ filter?: string;
+ sort?: string;
+ label_field: string;
+ subtitle_field?: string;
+ action: string;
+ icon?: string;
+}
+
+export type PluginSectionSchema =
+ | { type: 'fields'; label: string; fields: string[] }
+ | { type: 'crud'; label: string; entity: string; filter_field?: string; enable_views?: string[] };
+
+// ── P2 平台通用服务 — Settings 类型 ──
+
+export type PluginSettingType =
+ | 'text' | 'number' | 'boolean' | 'select' | 'multiselect'
+ | 'color' | 'date' | 'datetime' | 'json';
+
+export interface PluginSettingField {
+ name: string;
+ display_name: string;
+ field_type: PluginSettingType;
+ default_value?: unknown;
+ required: boolean;
+ description?: string;
+ options?: { label: string; value: string }[];
+ range?: [number, number];
+ group?: string;
+}
+
+export interface PluginSettings {
+ fields: PluginSettingField[];
+}
+
+// ── P2 平台通用服务 — Numbering 类型 ──
+
+export interface PluginNumbering {
+ entity: string;
+ field: string;
+ prefix: string;
+ format: string;
+ reset_rule: 'never' | 'daily' | 'monthly' | 'yearly';
+ seq_length: number;
+ separator?: string;
+}
+
+// ── P2 平台通用服务 — TriggerEvent 类型 ──
+
+export interface PluginTriggerEvent {
+ name: string;
+ display_name: string;
+ description: string;
+ entity: string;
+ on: 'create' | 'update' | 'delete' | 'create_or_update';
+}
+
+// ── 插件市场 API ──
+
+export interface MarketEntry {
+ id: string;
+ plugin_id: string;
+ name: string;
+ version: string;
+ description?: string;
+ author?: string;
+ category?: string;
+ tags?: string[];
+ icon_url?: string;
+ screenshots?: string[];
+ min_platform_version?: string;
+ status: string;
+ download_count: number;
+ rating_avg: number;
+ rating_count: number;
+ changelog?: string;
+ created_at?: string;
+ updated_at?: string;
+}
+
+export interface MarketEntryDetail extends MarketEntry {
+ dependency_warnings: string[];
+}
+
+export interface MarketReview {
+ id: string;
+ user_id: string;
+ market_entry_id: string;
+ rating: number;
+ review_text?: string;
+ created_at?: string;
+}
+
+export async function listMarketEntries(params?: {
+ page?: number;
+ page_size?: number;
+ category?: string;
+ search?: string;
+}) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/market/entries',
+ { params },
+ );
+ return data.data;
+}
+
+export async function getMarketEntry(id: string) {
+ const { data } = await client.get<{ success: boolean; data: MarketEntryDetail }>(
+ `/market/entries/${id}`,
+ );
+ return data.data;
+}
+
+export async function installFromMarket(id: string) {
+ const { data } = await client.post<{ success: boolean; data: PluginInfo }>(
+ `/market/entries/${id}/install`,
+ );
+ return data.data;
+}
+
+export async function listMarketReviews(id: string) {
+ const { data } = await client.get<{ success: boolean; data: MarketReview[] }>(
+ `/market/entries/${id}/reviews`,
+ );
+ return data.data;
+}
+
+export async function submitMarketReview(id: string, review: { rating: number; review_text?: string }) {
+ const { data } = await client.post<{ success: boolean; data: MarketReview }>(
+ `/market/entries/${id}/reviews`,
+ review,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/roles.test.ts b/apps/web/src/api/roles.test.ts
new file mode 100644
index 0000000..ce58021
--- /dev/null
+++ b/apps/web/src/api/roles.test.ts
@@ -0,0 +1,86 @@
+/**
+ * roles API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as rolesApi from './roles'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('roles API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listRoles 应调用 GET /roles 并传递分页参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await rolesApi.listRoles(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/roles', { params: { page: 1, page_size: 10 } })
+ })
+
+ it('getRole 应调用 GET /roles/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await rolesApi.getRole('r-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/roles/r-001')
+ })
+
+ it('createRole 应调用 POST /roles', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '医生', code: 'doctor', description: '医生角色' }
+ await rolesApi.createRole(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/roles', req)
+ })
+
+ it('updateRole 应调用 PUT /roles/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { name: '高级医生', version: 1 }
+ await rolesApi.updateRole('r-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/roles/r-001', req)
+ })
+
+ it('deleteRole 应调用 DELETE /roles/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await rolesApi.deleteRole('r-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/roles/r-001')
+ })
+
+ it('assignPermissions 应调用 POST /roles/:id/permissions', async () => {
+ mockPost.mockResolvedValue(undefined)
+ await rolesApi.assignPermissions('r-001', ['p-1', 'p-2'])
+
+ expect(mockPost).toHaveBeenCalledWith('/roles/r-001/permissions', { permission_ids: ['p-1', 'p-2'] })
+ })
+
+ it('getRolePermissions 应调用 GET /roles/:id/permissions', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await rolesApi.getRolePermissions('r-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/roles/r-001/permissions')
+ })
+
+ it('listPermissions 应调用 GET /permissions', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await rolesApi.listPermissions()
+
+ expect(mockGet).toHaveBeenCalledWith('/permissions')
+ })
+})
diff --git a/apps/web/src/api/roles.ts b/apps/web/src/api/roles.ts
new file mode 100644
index 0000000..d1fd2cb
--- /dev/null
+++ b/apps/web/src/api/roles.ts
@@ -0,0 +1,75 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface RoleInfo {
+ id: string;
+ name: string;
+ code: string;
+ description?: string;
+ is_system: boolean;
+ version: number;
+}
+
+export interface PermissionInfo {
+ id: string;
+ code: string;
+ name: string;
+ resource: string;
+ action: string;
+ description?: string;
+}
+
+export interface CreateRoleRequest {
+ name: string;
+ code: string;
+ description?: string;
+}
+
+export interface UpdateRoleRequest {
+ name?: string;
+ description?: string;
+ version: number;
+}
+
+export async function listRoles(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/roles',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function getRole(id: string) {
+ const { data } = await client.get<{ success: boolean; data: RoleInfo }>(`/roles/${id}`);
+ return data.data;
+}
+
+export async function createRole(req: CreateRoleRequest) {
+ const { data } = await client.post<{ success: boolean; data: RoleInfo }>('/roles', req);
+ return data.data;
+}
+
+export async function updateRole(id: string, req: UpdateRoleRequest) {
+ const { data } = await client.put<{ success: boolean; data: RoleInfo }>(`/roles/${id}`, req);
+ return data.data;
+}
+
+export async function deleteRole(id: string) {
+ await client.delete(`/roles/${id}`);
+}
+
+export async function assignPermissions(roleId: string, permissionIds: string[]) {
+ await client.post(`/roles/${roleId}/permissions`, { permission_ids: permissionIds });
+}
+
+export async function getRolePermissions(roleId: string) {
+ const { data } = await client.get<{ success: boolean; data: PermissionInfo[] }>(
+ `/roles/${roleId}/permissions`,
+ );
+ return data.data;
+}
+
+export async function listPermissions() {
+ const { data } = await client.get<{ success: boolean; data: PermissionInfo[] }>('/permissions');
+ return data.data;
+}
diff --git a/apps/web/src/api/settings.ts b/apps/web/src/api/settings.ts
new file mode 100644
index 0000000..82539bc
--- /dev/null
+++ b/apps/web/src/api/settings.ts
@@ -0,0 +1,30 @@
+import client from './client';
+
+export interface SettingInfo {
+ id: string;
+ scope: string;
+ scope_id?: string;
+ setting_key: string;
+ setting_value: unknown;
+ version: number;
+}
+
+export async function getSetting(key: string, scope?: string, scopeId?: string) {
+ const { data } = await client.get<{ success: boolean; data: SettingInfo }>(
+ `/config/settings/${encodeURIComponent(key)}`,
+ { params: { scope, scope_id: scopeId } },
+ );
+ return data.data;
+}
+
+export async function updateSetting(key: string, settingValue: unknown, version?: number) {
+ const { data } = await client.put<{ success: boolean; data: SettingInfo }>(
+ `/config/settings/${encodeURIComponent(key)}`,
+ { setting_value: settingValue, version },
+ );
+ return data.data;
+}
+
+export async function deleteSetting(key: string, version: number) {
+ await client.delete(`/config/settings/${encodeURIComponent(key)}`, { data: { version } });
+}
diff --git a/apps/web/src/api/themes.ts b/apps/web/src/api/themes.ts
new file mode 100644
index 0000000..4ab075e
--- /dev/null
+++ b/apps/web/src/api/themes.ts
@@ -0,0 +1,49 @@
+import client from './client';
+
+export interface ThemeConfig {
+ primary_color?: string;
+ logo_url?: string;
+ sidebar_style?: 'light' | 'dark';
+ brand_name?: string;
+ brand_slogan?: string;
+ brand_features?: string;
+ brand_copyright?: string;
+}
+
+export async function getTheme() {
+ const { data } = await client.get<{ success: boolean; data: ThemeConfig }>(
+ '/config/themes',
+ );
+ return data.data;
+}
+
+export async function updateTheme(theme: ThemeConfig) {
+ const { data } = await client.put<{ success: boolean; data: ThemeConfig }>(
+ '/config/themes',
+ theme,
+ );
+ return data.data;
+}
+
+export interface BrandConfig {
+ brand_name: string;
+ brand_slogan: string;
+ brand_features: string;
+ brand_copyright: string;
+}
+
+const BRAND_DEFAULTS: BrandConfig = {
+ brand_name: 'HMS 健康管理平台',
+ brand_slogan: '新一代健康管理平台',
+ brand_features: '患者管理 · 健康监测 · 随访管理 · AI 智能分析',
+ brand_copyright: 'HMS 健康管理平台 · ©汕头市智界科技有限公司',
+};
+
+export async function getPublicBrand(): Promise {
+ try {
+ const res = await fetch('/api/v1/public/brand');
+ const json = await res.json();
+ if (json?.success && json?.data) return json.data;
+ } catch {}
+ return BRAND_DEFAULTS;
+}
diff --git a/apps/web/src/api/types.ts b/apps/web/src/api/types.ts
new file mode 100644
index 0000000..8605eae
--- /dev/null
+++ b/apps/web/src/api/types.ts
@@ -0,0 +1,7 @@
+export interface PaginatedResponse {
+ data: T[];
+ total: number;
+ page: number;
+ page_size: number;
+ total_pages: number;
+}
diff --git a/apps/web/src/api/upload.ts b/apps/web/src/api/upload.ts
new file mode 100644
index 0000000..1aa99ce
--- /dev/null
+++ b/apps/web/src/api/upload.ts
@@ -0,0 +1,16 @@
+import client from './client';
+
+export interface UploadResult {
+ url: string;
+ filename?: string;
+ size?: number;
+}
+
+export async function uploadFile(file: File): Promise {
+ const formData = new FormData();
+ formData.append('file', file);
+ const { data: result } = await client.post('/upload', formData, {
+ headers: { 'Content-Type': 'multipart/form-data' },
+ });
+ return result.data;
+}
diff --git a/apps/web/src/api/users.test.ts b/apps/web/src/api/users.test.ts
new file mode 100644
index 0000000..31f86b1
--- /dev/null
+++ b/apps/web/src/api/users.test.ts
@@ -0,0 +1,83 @@
+/**
+ * users API 契约测试
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as usersApi from './users'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('users API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listUsers 应调用 GET /users 并传递分页和搜索参数', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await usersApi.listUsers(2, 10, '张')
+
+ expect(mockGet).toHaveBeenCalledWith('/users', {
+ params: { page: 2, page_size: 10, search: '张' },
+ })
+ })
+
+ it('listUsers 空搜索时应传 search 为 undefined', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await usersApi.listUsers(1, 20, '')
+
+ expect(mockGet).toHaveBeenCalledWith('/users', {
+ params: { page: 1, page_size: 20, search: undefined },
+ })
+ })
+
+ it('getUser 应调用 GET /users/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await usersApi.getUser('u-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/users/u-001')
+ })
+
+ it('createUser 应调用 POST /users', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { username: 'newuser', password: 'pass123', display_name: '新用户' }
+ await usersApi.createUser(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/users', req)
+ })
+
+ it('updateUser 应调用 PUT /users/:id', async () => {
+ mockPut.mockResolvedValue(fakeRes)
+ const req = { display_name: '改名', version: 1 }
+ await usersApi.updateUser('u-001', req)
+
+ expect(mockPut).toHaveBeenCalledWith('/users/u-001', req)
+ })
+
+ it('deleteUser 应调用 DELETE /users/:id', async () => {
+ mockDelete.mockResolvedValue(undefined)
+ await usersApi.deleteUser('u-001')
+
+ expect(mockDelete).toHaveBeenCalledWith('/users/u-001')
+ })
+
+ it('assignRoles 应调用 POST /users/:id/roles', async () => {
+ mockPost.mockResolvedValue(undefined)
+ await usersApi.assignRoles('u-001', ['role-1', 'role-2'])
+
+ expect(mockPost).toHaveBeenCalledWith('/users/u-001/roles', { role_ids: ['role-1', 'role-2'] })
+ })
+})
diff --git a/apps/web/src/api/users.ts b/apps/web/src/api/users.ts
new file mode 100644
index 0000000..64b93c6
--- /dev/null
+++ b/apps/web/src/api/users.ts
@@ -0,0 +1,54 @@
+import client from './client';
+import type { UserInfo } from './auth';
+import type { PaginatedResponse } from './types';
+
+export interface CreateUserRequest {
+ username: string;
+ password: string;
+ email?: string;
+ phone?: string;
+ display_name?: string;
+}
+
+export interface UpdateUserRequest {
+ email?: string;
+ phone?: string;
+ display_name?: string;
+ status?: string;
+ version: number;
+}
+
+export async function listUsers(page = 1, pageSize = 20, search = '') {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/users',
+ { params: { page, page_size: pageSize, search: search || undefined } }
+ );
+ return data.data;
+}
+
+export async function getUser(id: string) {
+ const { data } = await client.get<{ success: boolean; data: UserInfo }>(`/users/${id}`);
+ return data.data;
+}
+
+export async function createUser(req: CreateUserRequest) {
+ const { data } = await client.post<{ success: boolean; data: UserInfo }>('/users', req);
+ return data.data;
+}
+
+export async function updateUser(id: string, req: UpdateUserRequest) {
+ const { data } = await client.put<{ success: boolean; data: UserInfo }>(`/users/${id}`, req);
+ return data.data;
+}
+
+export async function deleteUser(id: string) {
+ await client.delete(`/users/${id}`);
+}
+
+export async function assignRoles(userId: string, roleIds: string[]) {
+ await client.post(`/users/${userId}/roles`, { role_ids: roleIds });
+}
+
+export async function resetPassword(id: string, req: { new_password: string; version: number }) {
+ await client.post(`/users/${id}/reset-password`, req);
+}
diff --git a/apps/web/src/api/workflow.test.ts b/apps/web/src/api/workflow.test.ts
new file mode 100644
index 0000000..d2c262a
--- /dev/null
+++ b/apps/web/src/api/workflow.test.ts
@@ -0,0 +1,141 @@
+/**
+ * workflow API 契约测试(definitions + instances + tasks)
+ */
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+
+const mockGet = vi.fn()
+const mockPost = vi.fn()
+const mockPut = vi.fn()
+const mockDelete = vi.fn()
+
+vi.mock('./client', () => ({
+ default: {
+ get: (...args: unknown[]) => mockGet(...args),
+ post: (...args: unknown[]) => mockPost(...args),
+ put: (...args: unknown[]) => mockPut(...args),
+ delete: (...args: unknown[]) => mockDelete(...args),
+ },
+}))
+
+import * as defApi from './workflowDefinitions'
+import * as instApi from './workflowInstances'
+import * as taskApi from './workflowTasks'
+
+beforeEach(() => {
+ vi.clearAllMocks()
+})
+
+describe('workflowDefinitions API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listProcessDefinitions 应调用 GET /workflow/definitions', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await defApi.listProcessDefinitions(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/workflow/definitions', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('getProcessDefinition 应调用 GET /workflow/definitions/:id', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await defApi.getProcessDefinition('wf-001')
+
+ expect(mockGet).toHaveBeenCalledWith('/workflow/definitions/wf-001')
+ })
+
+ it('createProcessDefinition 应调用 POST /workflow/definitions', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { name: '审批流程', key: 'approval', nodes: [], edges: [] }
+ await defApi.createProcessDefinition(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/definitions', req)
+ })
+
+ it('publishProcessDefinition 应调用 POST /workflow/definitions/:id/publish', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await defApi.publishProcessDefinition('wf-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/definitions/wf-001/publish')
+ })
+})
+
+describe('workflowInstances API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('startInstance 应调用 POST /workflow/instances', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { definition_id: 'wf-001', business_key: 'BIZ-001' }
+ await instApi.startInstance(req)
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/instances', req)
+ })
+
+ it('listInstances 应调用 GET /workflow/instances 并传递分页', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await instApi.listInstances(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/workflow/instances', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('suspendInstance 应调用 POST /workflow/instances/:id/suspend', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await instApi.suspendInstance('inst-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/instances/inst-001/suspend')
+ })
+
+ it('resumeInstance 应调用 POST /workflow/instances/:id/resume', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await instApi.resumeInstance('inst-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/instances/inst-001/resume')
+ })
+
+ it('terminateInstance 应调用 POST /workflow/instances/:id/terminate', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ await instApi.terminateInstance('inst-001')
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/instances/inst-001/terminate')
+ })
+})
+
+describe('workflowTasks API', () => {
+ const fakeRes = { data: { success: true, data: {} } }
+
+ it('listPendingTasks 应调用 GET /workflow/tasks/pending', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await taskApi.listPendingTasks(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/workflow/tasks/pending', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('listCompletedTasks 应调用 GET /workflow/tasks/completed', async () => {
+ mockGet.mockResolvedValue(fakeRes)
+ await taskApi.listCompletedTasks(1, 10)
+
+ expect(mockGet).toHaveBeenCalledWith('/workflow/tasks/completed', {
+ params: { page: 1, page_size: 10 },
+ })
+ })
+
+ it('completeTask 应调用 POST /workflow/tasks/:id/complete', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { outcome: 'approved', form_data: { comment: '同意' } }
+ await taskApi.completeTask('task-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/tasks/task-001/complete', req)
+ })
+
+ it('delegateTask 应调用 POST /workflow/tasks/:id/delegate', async () => {
+ mockPost.mockResolvedValue(fakeRes)
+ const req = { delegate_to: 'u-002' }
+ await taskApi.delegateTask('task-001', req)
+
+ expect(mockPost).toHaveBeenCalledWith('/workflow/tasks/task-001/delegate', req)
+ })
+})
diff --git a/apps/web/src/api/workflowDefinitions.ts b/apps/web/src/api/workflowDefinitions.ts
new file mode 100644
index 0000000..4490fd3
--- /dev/null
+++ b/apps/web/src/api/workflowDefinitions.ts
@@ -0,0 +1,90 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface NodeDef {
+ id: string;
+ type: 'StartEvent' | 'EndEvent' | 'UserTask' | 'ServiceTask' | 'ExclusiveGateway' | 'ParallelGateway';
+ name: string;
+ assignee_id?: string;
+ candidate_groups?: string[];
+ service_type?: string;
+ position?: { x: number; y: number };
+}
+
+export interface EdgeDef {
+ id: string;
+ source: string;
+ target: string;
+ condition?: string;
+ label?: string;
+}
+
+export interface ProcessDefinitionInfo {
+ id: string;
+ name: string;
+ key: string;
+ version: number;
+ category?: string;
+ description?: string;
+ nodes: NodeDef[];
+ edges: EdgeDef[];
+ status: string;
+ created_at: string;
+ updated_at: string;
+}
+
+export interface CreateProcessDefinitionRequest {
+ name: string;
+ key: string;
+ category?: string;
+ description?: string;
+ nodes: NodeDef[];
+ edges: EdgeDef[];
+}
+
+export interface UpdateProcessDefinitionRequest {
+ name?: string;
+ category?: string;
+ description?: string;
+ nodes?: NodeDef[];
+ edges?: EdgeDef[];
+ version: number;
+}
+
+export async function listProcessDefinitions(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/workflow/definitions',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function getProcessDefinition(id: string) {
+ const { data } = await client.get<{ success: boolean; data: ProcessDefinitionInfo }>(
+ `/workflow/definitions/${id}`,
+ );
+ return data.data;
+}
+
+export async function createProcessDefinition(req: CreateProcessDefinitionRequest) {
+ const { data } = await client.post<{ success: boolean; data: ProcessDefinitionInfo }>(
+ '/workflow/definitions',
+ req,
+ );
+ return data.data;
+}
+
+export async function updateProcessDefinition(id: string, req: UpdateProcessDefinitionRequest) {
+ const { data } = await client.put<{ success: boolean; data: ProcessDefinitionInfo }>(
+ `/workflow/definitions/${id}`,
+ req,
+ );
+ return data.data;
+}
+
+export async function publishProcessDefinition(id: string) {
+ const { data } = await client.post<{ success: boolean; data: ProcessDefinitionInfo }>(
+ `/workflow/definitions/${id}/publish`,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/workflowInstances.ts b/apps/web/src/api/workflowInstances.ts
new file mode 100644
index 0000000..7b99f47
--- /dev/null
+++ b/apps/web/src/api/workflowInstances.ts
@@ -0,0 +1,72 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface TokenInfo {
+ id: string;
+ node_id: string;
+ status: string;
+ created_at: string;
+}
+
+export interface ProcessInstanceInfo {
+ id: string;
+ definition_id: string;
+ definition_name?: string;
+ business_key?: string;
+ status: string;
+ started_by: string;
+ started_at: string;
+ completed_at?: string;
+ created_at: string;
+ active_tokens: TokenInfo[];
+}
+
+export interface StartInstanceRequest {
+ definition_id: string;
+ business_key?: string;
+ variables?: Array<{ name: string; var_type?: string; value: unknown }>;
+}
+
+export async function startInstance(req: StartInstanceRequest) {
+ const { data } = await client.post<{ success: boolean; data: ProcessInstanceInfo }>(
+ '/workflow/instances',
+ req,
+ );
+ return data.data;
+}
+
+export async function listInstances(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/workflow/instances',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function getInstance(id: string) {
+ const { data } = await client.get<{ success: boolean; data: ProcessInstanceInfo }>(
+ `/workflow/instances/${id}`,
+ );
+ return data.data;
+}
+
+export async function suspendInstance(id: string) {
+ const { data } = await client.post<{ success: boolean; data: null }>(
+ `/workflow/instances/${id}/suspend`,
+ );
+ return data.data;
+}
+
+export async function resumeInstance(id: string) {
+ const { data } = await client.post<{ success: boolean; data: null }>(
+ `/workflow/instances/${id}/resume`,
+ );
+ return data.data;
+}
+
+export async function terminateInstance(id: string) {
+ const { data } = await client.post<{ success: boolean; data: null }>(
+ `/workflow/instances/${id}/terminate`,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/api/workflowTasks.ts b/apps/web/src/api/workflowTasks.ts
new file mode 100644
index 0000000..c5b47cb
--- /dev/null
+++ b/apps/web/src/api/workflowTasks.ts
@@ -0,0 +1,61 @@
+import client from './client';
+import type { PaginatedResponse } from './types';
+
+export interface TaskInfo {
+ id: string;
+ instance_id: string;
+ token_id: string;
+ node_id: string;
+ node_name?: string;
+ assignee_id?: string;
+ candidate_groups?: unknown;
+ status: string;
+ outcome?: string;
+ form_data?: unknown;
+ due_date?: string;
+ completed_at?: string;
+ created_at: string;
+ definition_name?: string;
+ business_key?: string;
+}
+
+export interface CompleteTaskRequest {
+ outcome: string;
+ form_data?: Record;
+}
+
+export interface DelegateTaskRequest {
+ delegate_to: string;
+}
+
+export async function listPendingTasks(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/workflow/tasks/pending',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function listCompletedTasks(page = 1, pageSize = 20) {
+ const { data } = await client.get<{ success: boolean; data: PaginatedResponse }>(
+ '/workflow/tasks/completed',
+ { params: { page, page_size: pageSize } },
+ );
+ return data.data;
+}
+
+export async function completeTask(id: string, req: CompleteTaskRequest) {
+ const { data } = await client.post<{ success: boolean; data: TaskInfo }>(
+ `/workflow/tasks/${id}/complete`,
+ req,
+ );
+ return data.data;
+}
+
+export async function delegateTask(id: string, req: DelegateTaskRequest) {
+ const { data } = await client.post<{ success: boolean; data: TaskInfo }>(
+ `/workflow/tasks/${id}/delegate`,
+ req,
+ );
+ return data.data;
+}
diff --git a/apps/web/src/components/ActionThreadDrawer.tsx b/apps/web/src/components/ActionThreadDrawer.tsx
new file mode 100644
index 0000000..0f986c9
--- /dev/null
+++ b/apps/web/src/components/ActionThreadDrawer.tsx
@@ -0,0 +1,226 @@
+import { useCallback, useEffect, useState } from 'react';
+import { Drawer, Timeline, Button, Spin, Result, Space, Tag } from 'antd';
+import {
+ CheckCircleOutlined,
+ ClockCircleOutlined,
+ MinusCircleOutlined,
+ CloseCircleOutlined,
+ UserOutlined,
+} from '@ant-design/icons';
+import { useNavigate } from 'react-router-dom';
+import {
+ actionInboxApi,
+ type ActionItem,
+ type ThreadResponse,
+ type ActionPriority,
+} from '../api/health/actionInbox';
+import client from '../api/client';
+
+interface Props {
+ open: boolean;
+ item: ActionItem | null;
+ onClose: () => void;
+ onActionComplete?: () => void;
+}
+
+const PRIORITY_COLOR: Record = {
+ urgent: 'red',
+ high: 'orange',
+ medium: 'blue',
+ low: 'default',
+};
+
+const PRIORITY_LABEL: Record = {
+ urgent: '紧急',
+ high: '高',
+ medium: '中',
+ low: '低',
+};
+
+export default function ActionThreadDrawer({
+ open,
+ item,
+ onClose,
+ onActionComplete,
+}: Props) {
+ const navigate = useNavigate();
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [threadData, setThreadData] = useState(null);
+ const [actionLoading, setActionLoading] = useState(null);
+
+ const fetchThread = useCallback(async () => {
+ if (!item) return;
+ setLoading(true);
+ setError(null);
+ try {
+ const data = await actionInboxApi.getThread(item.source_ref);
+ setThreadData(data);
+ } catch (e: unknown) {
+ const msg = e instanceof Error ? e.message : '获取线程失败';
+ setError(msg);
+ } finally {
+ setLoading(false);
+ }
+ }, [item]);
+
+ useEffect(() => {
+ if (open && item) fetchThread();
+ if (!open) setThreadData(null);
+ }, [open, item, fetchThread]);
+
+ const handleAction = async (endpoint: string, key: string) => {
+ setActionLoading(key);
+ try {
+ await client.post(endpoint, { action: key });
+ onActionComplete?.();
+ fetchThread();
+ } catch {
+ // 全局拦截器处理
+ } finally {
+ setActionLoading(null);
+ }
+ };
+
+ const handleLinkClick = (linkTo?: string) => {
+ if (linkTo) {
+ onClose();
+ navigate(linkTo);
+ }
+ };
+
+ const timelineDot = (status: string) => {
+ switch (status) {
+ case 'completed':
+ return ;
+ case 'in_progress':
+ return ;
+ case 'dismissed':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ return (
+
+ {loading && (
+
+
+
+ )}
+
+ {error && (
+
+
+
+ )}
+
+ {threadData && !loading && (
+ <>
+
+
+ {threadData.action_item.title}
+
+
+ {threadData.action_item.patient_name}
+
+ {PRIORITY_LABEL[threadData.action_item.priority]}
+
+
+
+
+
+
+ 处理进度
+
+
({
+ color:
+ evt.status === 'completed'
+ ? 'green'
+ : evt.status === 'in_progress'
+ ? 'blue'
+ : 'gray',
+ dot: timelineDot(evt.status),
+ children: (
+
+ ),
+ }))}
+ />
+
+
+ {threadData.available_actions.length > 0 && (
+
+
+ {threadData.available_actions.map((action) => (
+
+ ))}
+
+
+ )}
+ >
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/AuthButton.tsx b/apps/web/src/components/AuthButton.tsx
new file mode 100644
index 0000000..31b9c81
--- /dev/null
+++ b/apps/web/src/components/AuthButton.tsx
@@ -0,0 +1,13 @@
+import type { ReactNode } from 'react';
+import { usePermission } from '../hooks/usePermission';
+
+interface AuthButtonProps {
+ code: string;
+ children: ReactNode;
+}
+
+export function AuthButton({ code, children }: AuthButtonProps) {
+ const { hasPermission } = usePermission(code);
+ if (!hasPermission) return null;
+ return <>{children}>;
+}
diff --git a/apps/web/src/components/Copilot/CopilotAlert.tsx b/apps/web/src/components/Copilot/CopilotAlert.tsx
new file mode 100644
index 0000000..b61a69a
--- /dev/null
+++ b/apps/web/src/components/Copilot/CopilotAlert.tsx
@@ -0,0 +1,106 @@
+import { useState, useEffect, useCallback } from 'react';
+import { Alert, Badge, List, Button, Space, Typography, Spin } from 'antd';
+import { CheckOutlined } from '@ant-design/icons';
+import { listAlerts, dismissInsight } from '../../api/copilot';
+import type { CopilotInsight } from '../../api/copilot';
+
+const severityConfig: Record = {
+ critical: { type: 'error', label: '危急' },
+ warning: { type: 'warning', label: '警告' },
+ info: { type: 'processing', label: '提示' },
+};
+
+export function CopilotAlert() {
+ const [alerts, setAlerts] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [dismissing, setDismissing] = useState(null);
+
+ const fetchAlerts = useCallback(async () => {
+ setLoading(true);
+ try {
+ const res = await listAlerts({ page_size: 50 });
+ const payload = (res.data as { data?: CopilotInsight[] }).data ?? [];
+ setAlerts(payload);
+ } catch {
+ // 静默
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ fetchAlerts();
+ const timer = setInterval(fetchAlerts, 30_000);
+ return () => clearInterval(timer);
+ }, [fetchAlerts]);
+
+ const handleDismiss = async (id: string) => {
+ setDismissing(id);
+ try {
+ await dismissInsight(id);
+ setAlerts((prev) => prev.filter((a) => a.id !== id));
+ } finally {
+ setDismissing(null);
+ }
+ };
+
+ if (!alerts.length && !loading) return null;
+
+ const criticalCount = alerts.filter((a) => a.severity === 'critical').length;
+
+ return (
+
+ {criticalCount > 0 && (
+
+ )}
+ {loading && alerts.length === 0 ? (
+
+ ) : (
+
{
+ const config = severityConfig[item.severity] ?? severityConfig.info;
+ return (
+ }
+ loading={dismissing === item.id}
+ onClick={() => handleDismiss(item.id)}
+ >
+ 已知悉
+ ,
+ ]}
+ >
+
+
+ {item.title}
+
+ }
+ description={
+ item.content?.suggestion ? (
+
+ {item.content.suggestion as string}
+
+ ) : undefined
+ }
+ />
+
+ );
+ }}
+ />
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/Copilot/CopilotBadge.tsx b/apps/web/src/components/Copilot/CopilotBadge.tsx
new file mode 100644
index 0000000..827a50f
--- /dev/null
+++ b/apps/web/src/components/Copilot/CopilotBadge.tsx
@@ -0,0 +1,28 @@
+import { Tag, Tooltip } from 'antd';
+import type { RiskLevel } from '../../api/copilot';
+import { useCopilotRisk } from './useCopilotRisk';
+
+const levelConfig: Record = {
+ low: { color: 'green', label: '低风险' },
+ medium: { color: 'orange', label: '中风险' },
+ high: { color: 'red', label: '高风险' },
+ critical: { color: '#cf1322', label: '危急' },
+};
+
+interface CopilotBadgeProps {
+ patientId: string | undefined;
+}
+
+export function CopilotBadge({ patientId }: CopilotBadgeProps) {
+ const { data, loading } = useCopilotRisk(patientId);
+
+ if (!data || loading) return null;
+
+ const config = levelConfig[data.level as RiskLevel] ?? levelConfig.low;
+
+ return (
+
+ {config.label} {data.score}/10
+
+ );
+}
diff --git a/apps/web/src/components/Copilot/CopilotCard.tsx b/apps/web/src/components/Copilot/CopilotCard.tsx
new file mode 100644
index 0000000..24abc5f
--- /dev/null
+++ b/apps/web/src/components/Copilot/CopilotCard.tsx
@@ -0,0 +1,76 @@
+import { Card, List, Tag, Button, Empty, Spin, Typography } from 'antd';
+import { CloseOutlined } from '@ant-design/icons';
+import { useState } from 'react';
+import { dismissInsight } from '../../api/copilot';
+import type { CopilotInsight } from '../../api/copilot';
+import { useCopilotInsights } from './useCopilotInsights';
+
+const severityColor: Record = {
+ info: 'blue',
+ warning: 'orange',
+ critical: 'red',
+};
+
+interface CopilotCardProps {
+ patientId: string | undefined;
+}
+
+export function CopilotCard({ patientId }: CopilotCardProps) {
+ const { data, loading, refresh } = useCopilotInsights(patientId);
+ const [dismissing, setDismissing] = useState(null);
+
+ const handleDismiss = async (id: string) => {
+ setDismissing(id);
+ try {
+ await dismissInsight(id);
+ refresh();
+ } finally {
+ setDismissing(null);
+ }
+ };
+
+ return (
+
+ {loading ? (
+
+ ) : data.length === 0 ? (
+
+ ) : (
+ (
+ }
+ loading={dismissing === item.id}
+ onClick={() => handleDismiss(item.id)}
+ />,
+ ]}
+ >
+
+ {item.severity}
+ {item.title}
+
+ }
+ description={
+ item.llm_supplement ? (
+
+ {item.llm_supplement}
+
+ ) : undefined
+ }
+ />
+
+ )}
+ />
+ )}
+
+ );
+}
diff --git a/apps/web/src/components/Copilot/index.ts b/apps/web/src/components/Copilot/index.ts
new file mode 100644
index 0000000..888a35b
--- /dev/null
+++ b/apps/web/src/components/Copilot/index.ts
@@ -0,0 +1,5 @@
+export { CopilotBadge } from './CopilotBadge';
+export { CopilotCard } from './CopilotCard';
+export { CopilotAlert } from './CopilotAlert';
+export { useCopilotRisk } from './useCopilotRisk';
+export { useCopilotInsights } from './useCopilotInsights';
diff --git a/apps/web/src/components/Copilot/useCopilotInsights.ts b/apps/web/src/components/Copilot/useCopilotInsights.ts
new file mode 100644
index 0000000..5f319b5
--- /dev/null
+++ b/apps/web/src/components/Copilot/useCopilotInsights.ts
@@ -0,0 +1,31 @@
+import { useState, useEffect, useCallback } from 'react';
+import { listInsights } from '../../api/copilot';
+import type { CopilotInsight } from '../../api/copilot';
+
+export function useCopilotInsights(patientId: string | undefined) {
+ const [data, setData] = useState([]);
+ const [total, setTotal] = useState(0);
+ const [loading, setLoading] = useState(false);
+
+ const fetch = useCallback(async () => {
+ if (!patientId) return;
+ setLoading(true);
+ try {
+ const res = await listInsights({ patient_id: patientId, page_size: 20 });
+ const payload = (res.data as { data?: CopilotInsight[]; total?: number }).data ?? [];
+ const total = (res.data as { total?: number }).total ?? 0;
+ setData(payload);
+ setTotal(total);
+ } catch {
+ // 静默失败
+ } finally {
+ setLoading(false);
+ }
+ }, [patientId]);
+
+ useEffect(() => {
+ fetch();
+ }, [fetch]);
+
+ return { data, total, loading, refresh: fetch };
+}
diff --git a/apps/web/src/components/Copilot/useCopilotRisk.ts b/apps/web/src/components/Copilot/useCopilotRisk.ts
new file mode 100644
index 0000000..38243c8
--- /dev/null
+++ b/apps/web/src/components/Copilot/useCopilotRisk.ts
@@ -0,0 +1,29 @@
+import { useState, useEffect, useCallback } from 'react';
+import { getPatientRisk } from '../../api/copilot';
+import type { RiskScore } from '../../api/copilot';
+
+export function useCopilotRisk(patientId: string | undefined) {
+ const [data, setData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+
+ const fetch = useCallback(async () => {
+ if (!patientId) return;
+ setLoading(true);
+ setError(null);
+ try {
+ const res = await getPatientRisk(patientId);
+ setData(res ?? null);
+ } catch (err) {
+ setError(err instanceof Error ? err.message : '加载风险评分失败');
+ } finally {
+ setLoading(false);
+ }
+ }, [patientId]);
+
+ useEffect(() => {
+ fetch();
+ }, [fetch]);
+
+ return { data, loading, error, refresh: fetch };
+}
diff --git a/apps/web/src/components/DrawerForm.tsx b/apps/web/src/components/DrawerForm.tsx
new file mode 100644
index 0000000..dbb65cd
--- /dev/null
+++ b/apps/web/src/components/DrawerForm.tsx
@@ -0,0 +1,107 @@
+import React from 'react';
+import { Drawer, Form, Typography, Divider, Button, Space } from 'antd';
+import { useThemeMode } from '../hooks/useThemeMode';
+
+export interface FormSection {
+ title: string;
+ fields: React.ReactNode;
+ defaultCollapsed?: boolean;
+}
+
+interface DrawerFormProps {
+ title: string;
+ open: boolean;
+ onClose: () => void;
+ onSubmit: (values: Record) => Promise;
+ initialValues?: Record;
+ loading?: boolean;
+ width?: number | string;
+ sections?: FormSection[];
+ children?: React.ReactNode;
+ columns?: 1 | 2;
+ form?: ReturnType[0];
+ onValuesChange?: (changedValues: Record, allValues: Record) => void;
+}
+
+export function DrawerForm({
+ title,
+ open,
+ onClose,
+ onSubmit,
+ initialValues,
+ loading,
+ width = 640,
+ sections,
+ children,
+ columns = 2,
+ form: externalForm,
+ onValuesChange,
+}: DrawerFormProps) {
+ const [internalForm] = Form.useForm();
+ const form = externalForm ?? internalForm;
+ const isDark = useThemeMode();
+
+ React.useEffect(() => {
+ if (open) {
+ form.resetFields();
+ if (initialValues) {
+ form.setFieldsValue(initialValues);
+ }
+ }
+ }, [open, initialValues, form]);
+
+ const handleSubmit = async () => {
+ try {
+ const values = await form.validateFields();
+ await onSubmit(values);
+ } catch (error: unknown) {
+ // validateFields 失败时 error 包含 errorFields(预期行为,不记录)
+ // 其他类型的错误才记录
+ if (error && typeof error === 'object' && !('errorFields' in error)) {
+ console.error('[DrawerForm] submit error:', error);
+ }
+ }
+ };
+
+ const gridStyle: React.CSSProperties =
+ columns === 2
+ ? { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0 16px' }
+ : {};
+
+ return (
+
+
+
+
+ }
+ >
+
+
+ );
+}
diff --git a/apps/web/src/components/EntityName.tsx b/apps/web/src/components/EntityName.tsx
new file mode 100644
index 0000000..d3c8562
--- /dev/null
+++ b/apps/web/src/components/EntityName.tsx
@@ -0,0 +1,23 @@
+import { Tooltip, Typography } from 'antd';
+
+interface EntityNameProps {
+ name?: string | null;
+ id?: string;
+ fallbackLabel?: string;
+}
+
+export function EntityName({ name, id, fallbackLabel = '未知' }: EntityNameProps) {
+ if (name !== undefined && name !== null && name !== '') return {name};
+
+ if (id) {
+ return (
+
+
+ {fallbackLabel}
+
+
+ );
+ }
+
+ return {fallbackLabel};
+}
diff --git a/apps/web/src/components/EntitySelect.tsx b/apps/web/src/components/EntitySelect.tsx
new file mode 100644
index 0000000..b5f1795
--- /dev/null
+++ b/apps/web/src/components/EntitySelect.tsx
@@ -0,0 +1,141 @@
+import { Select, Spin, Input, Tooltip } from 'antd';
+import { QuestionCircleOutlined } from '@ant-design/icons';
+import { useState, useEffect, useCallback } from 'react';
+import { listPluginData, getPluginEntityRegistry } from '../api/pluginData';
+
+interface EntitySelectProps {
+ pluginId: string;
+ entity: string;
+ labelField: string;
+ searchFields?: string[];
+ /** 跨插件引用的目标插件 manifest ID(如 "erp-crm") */
+ refPlugin?: string;
+ /** 目标插件未安装时的降级显示文本 */
+ fallbackLabel?: string;
+ value?: string;
+ onChange?: (value: string, label: string) => void;
+ cascadeFrom?: string;
+ cascadeFilter?: string;
+ cascadeValue?: string;
+ placeholder?: string;
+}
+
+export default function EntitySelect({
+ pluginId,
+ entity,
+ labelField,
+ searchFields: _searchFields,
+ refPlugin,
+ fallbackLabel,
+ value,
+ onChange,
+ cascadeFrom,
+ cascadeFilter,
+ cascadeValue,
+ placeholder,
+}: EntitySelectProps) {
+ const [options, setOptions] = useState<{ value: string; label: string }[]>([]);
+ const [loading, setLoading] = useState(false);
+ const [targetUnavailable, setTargetUnavailable] = useState(false);
+ const [resolvedPluginId, setResolvedPluginId] = useState(null);
+
+ // 跨插件时:先解析 manifest_id → plugin UUID
+ useEffect(() => {
+ if (!refPlugin) {
+ setResolvedPluginId(pluginId);
+ return;
+ }
+ let cancelled = false;
+ (async () => {
+ try {
+ const registry = await getPluginEntityRegistry();
+ const match = registry.find((e) => e.manifest_id === refPlugin && e.entity_name === entity);
+ if (!cancelled) {
+ setResolvedPluginId(match ? match.plugin_id : null);
+ if (!match) setTargetUnavailable(true);
+ }
+ } catch {
+ if (!cancelled) {
+ setTargetUnavailable(true);
+ setResolvedPluginId(null);
+ }
+ }
+ })();
+ return () => { cancelled = true; };
+ }, [refPlugin, pluginId, entity]);
+
+ const effectivePluginId = resolvedPluginId || pluginId;
+
+ const fetchData = useCallback(
+ async (keyword?: string) => {
+ if (!resolvedPluginId && refPlugin) return;
+ setLoading(true);
+ try {
+ const filter: Record | undefined =
+ cascadeFrom && cascadeFilter && cascadeValue
+ ? { [cascadeFilter]: cascadeValue }
+ : undefined;
+
+ const result = await listPluginData(effectivePluginId, entity, 1, 20, {
+ search: keyword,
+ filter,
+ });
+
+ const items = (result.data || []).map((item) => ({
+ value: item.id,
+ label: String(item.data?.[labelField] ?? item.id),
+ }));
+ setOptions(items);
+ setTargetUnavailable(false);
+ } catch {
+ if (refPlugin) {
+ setTargetUnavailable(true);
+ setOptions([]);
+ }
+ } finally {
+ setLoading(false);
+ }
+ },
+ [effectivePluginId, entity, labelField, cascadeFrom, cascadeFilter, cascadeValue, refPlugin, resolvedPluginId],
+ );
+
+ useEffect(() => {
+ if (resolvedPluginId || !refPlugin) {
+ fetchData();
+ }
+ }, [fetchData, resolvedPluginId, refPlugin]);
+
+ // 目标插件未安装 → 降级显示
+ if (targetUnavailable) {
+ return (
+
+
+
+ }
+ />
+ );
+ }
+
+ return (
+