diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e218bea2..f450fb13 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -24,5 +24,8 @@ jobs: - name: Run type checker run: npm run typecheck + - name: Run unit tests + run: npm run test + - name: Test-Build run: npm run build diff --git a/package-lock.json b/package-lock.json index 457b771e..3aaec330 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,13 @@ "version": "1.2.0", "license": "MIT", "dependencies": { + "@eeholmes/zarrita-pcodec": "github:eeholmes/zarrita-pcodec", "@fortawesome/fontawesome-free": "^7.2.0", "@hscmap/healpix": "^1.4.12", "@primevue/themes": "^4.5.4", - "@vuepic/vue-datepicker": "13.0.0", - "@vueuse/core": "^14.2.1", - "axios": "^1.15.2", + "@vuepic/vue-datepicker": "14.0.0", + "@vueuse/core": "^14.3.0", + "axios": "^1.18.0", "bulma": "^1.0.4", "canvas-txt": "^4.1.1", "chart.js": "^4.5.1", @@ -22,68 +23,70 @@ "d3-delaunay": "^6.0.4", "d3-geo": "^3.1.1", "d3-geo-projection": "^4.0.0", - "dayjs": "^1.11.20", + "dayjs": "^1.11.21", "fflate": "^0.8.3", "geokdbush": "2.1.0", "humanize-duration": "^3.33.2", "icechunk-js": "^0.4.0", - "kdbush": "4.0.2", + "kdbush": "4.1.0", "pinia": "^3.0.4", "primevue": "^4.5.5", + "proj4": "^2.20.9", "qrcode": "^1.5.4", "quick-lru": "^7.3.0", "three": "^0.184", "three-conic-polygon-geometry": "^2.1.3", "three-geojson-geometry": "^2.1.1", - "vue": "^3.5.33", + "vue": "^3.5.38", "vue-json-pretty": "^2.6.0", - "vue-router": "^5.0.6", + "vue-router": "^5.1.0", "zarrita": "^0.7.3" }, "devDependencies": { - "@commitlint/cli": "^20.5.0", - "@commitlint/config-conventional": "^20.5.0", + "@commitlint/cli": "^21.0.2", + "@commitlint/config-conventional": "^21.0.2", "@types/d3-delaunay": "^6.0.4", "@types/d3-geo": "^3.1.0", "@types/geojson": "7946.0.16", "@types/humanize-duration": "^3.27.4", - "@types/node": "^20.17", + "@types/node": "~24", "@types/qrcode": "^1.5.6", "@types/three": "0.184.1", - "@vitejs/plugin-vue": "^6.0.6", + "@vitejs/plugin-vue": "^6.0.7", "@vue/tsconfig": "0.9.1", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-import-resolver-typescript": "^4.4.4", + "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-boundaries": "^6.0.2", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-prettier": "^5.5.5", - "eslint-plugin-promise": "^7.2.1", - "eslint-plugin-vue": "10.8", - "globals": "^17.5.0", + "eslint-plugin-prettier": "^5.5.6", + "eslint-plugin-promise": "^7.3.0", + "eslint-plugin-vue": "10.9", + "globals": "^17.6.0", "glslify": "^7.1.1", "husky": "^9.1.7", - "lint-staged": "^16.4.0", - "prettier": "^3.8.3", + "lint-staged": "^17.0.7", + "prettier": "^3.8.4", "sass": "~1.89.2", "typescript": "^6.0.3", "typescript-eslint": "^8.59.0", "vite": "^8.0.10", "vite-plugin-glsl": "^1.6.0", + "vitest": "^4.1.9", "vue-tsc": "^3.2.7" }, "engines": { - "node": ">=20.17.0" + "node": ">=24.16.0" } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "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.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -92,46 +95,93 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0-rc.6.tgz", + "integrity": "sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^8.0.0-rc.6", + "@babel/types": "^8.0.0-rc.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", + "@types/jsesc": "^2.5.0", "jsesc": "^3.0.2" }, "engines": { - "node": ">=6.9.0" + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/helper-string-parser": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0-rc.6.tgz", + "integrity": "sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.0-rc.6.tgz", + "integrity": "sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==", + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/parser": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0-rc.6.tgz", + "integrity": "sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==", + "license": "MIT", + "dependencies": { + "@babel/types": "^8.0.0-rc.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + } + }, + "node_modules/@babel/generator/node_modules/@babel/types": { + "version": "8.0.0-rc.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0-rc.6.tgz", + "integrity": "sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^8.0.0-rc.6", + "@babel/helper-validator-identifier": "^8.0.0-rc.6" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "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==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "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==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "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==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -141,13 +191,13 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -191,59 +241,59 @@ "license": "MIT" }, "node_modules/@commitlint/cli": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz", - "integrity": "sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.0.2.tgz", + "integrity": "sha512-YMmfLbqBg+ZRvvmPhc+cilSQFrh/AgzVgCT1U/OifmUZEwPbvCtA8rN//YNaF9d5eoZphxVMGYtmwA2QgQORgg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/format": "^20.5.0", - "@commitlint/lint": "^20.5.0", - "@commitlint/load": "^20.5.0", - "@commitlint/read": "^20.5.0", - "@commitlint/types": "^20.5.0", + "@commitlint/format": "^21.0.1", + "@commitlint/lint": "^21.0.2", + "@commitlint/load": "^21.0.2", + "@commitlint/read": "^21.0.2", + "@commitlint/types": "^21.0.1", "tinyexec": "^1.0.0", - "yargs": "^17.0.0" + "yargs": "^18.0.0" }, "bin": { "commitlint": "cli.js" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/config-conventional": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz", - "integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.0.2.tgz", + "integrity": "sha512-P/ZRhryQmkj0Z0dY9FOoRwe3xkwJyyAdtXwt01NT2kuZttcG2CNYp1q5Ci3u+nDT2jcbJRw2kt13Czl1qKNPfg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", + "@commitlint/types": "^21.0.1", "conventional-changelog-conventionalcommits": "^9.2.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/config-validator": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.5.0.tgz", - "integrity": "sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.0.1.tgz", + "integrity": "sha512-Zd2UFdndeMMaW2O96HK0tdfT4gOImUvidMpAd/pws2zZ4m1nrAZ/9b/v2JYuE8fs86GpXv9F7LNaIuCIWhY+pA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", + "@commitlint/types": "^21.0.1", "ajv": "^8.11.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -265,156 +315,150 @@ "license": "MIT" }, "node_modules/@commitlint/ensure": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.0.tgz", - "integrity": "sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.0.1.tgz", + "integrity": "sha512-jJ1037967wU7YN/xkv+iRlOBlmaOXPhPO5KQSqya6GyXzBlwuLzELBFao16DVg9dZyqmNrhewzwZ3SAibetHBQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", - "lodash.camelcase": "^4.3.0", - "lodash.kebabcase": "^4.1.1", - "lodash.snakecase": "^4.1.1", - "lodash.startcase": "^4.4.0", - "lodash.upperfirst": "^4.3.1" + "@commitlint/types": "^21.0.1", + "es-toolkit": "^1.46.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/execute-rule": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", - "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-21.0.1.tgz", + "integrity": "sha512-RifH+FmImozKBE6mozhF4K3r2RRKP7SMi/Q/zLCmExtp5e05lhHOUYqGBlFBAGNHaZxU/WYw1XuugYK9jQzqnA==", "dev": true, "license": "MIT", "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/format": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.5.0.tgz", - "integrity": "sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.0.1.tgz", + "integrity": "sha512-ksmG2+cHGtuDPQQbhBbC4unwm444+6TiPw0d1bKf67hntgZqZ8E0g1MuYKUuyT5IH4IMmXZhKq22/Z3jBvtQIw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", + "@commitlint/types": "^21.0.1", "picocolors": "^1.1.1" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/is-ignored": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.5.0.tgz", - "integrity": "sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.0.2.tgz", + "integrity": "sha512-H5z4t8PC9tUsmZ/o+EptM3Nq8sTFtskAShdcqxCoyzklW5eaVT5xbrDAET2uypzir9Vsj4ZZmBtyKjYe2XqgeQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", + "@commitlint/types": "^21.0.1", "semver": "^7.6.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/lint": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.0.tgz", - "integrity": "sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.0.2.tgz", + "integrity": "sha512-PnUmLYGeGLfW8oVatR9KpNxSHYAnJOEWlMZzfdeFOUq6WUrFx1fGQaWCWJqMoIll/xPM+GdfJV+tKHZVHhl0Fg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^20.5.0", - "@commitlint/parse": "^20.5.0", - "@commitlint/rules": "^20.5.0", - "@commitlint/types": "^20.5.0" + "@commitlint/is-ignored": "^21.0.2", + "@commitlint/parse": "^21.0.2", + "@commitlint/rules": "^21.0.2", + "@commitlint/types": "^21.0.1" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/load": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.0.tgz", - "integrity": "sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.0.2.tgz", + "integrity": "sha512-lwUE70hN0/qE/ZRROhbaX65ly/FF12DrqfReLCESo37M0OQCFAf2jRS+2tSCSORq+bm4Kdju7qNDj46uc1QzTA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.5.0", - "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.5.0", - "@commitlint/types": "^20.5.0", + "@commitlint/config-validator": "^21.0.1", + "@commitlint/execute-rule": "^21.0.1", + "@commitlint/resolve-extends": "^21.0.1", + "@commitlint/types": "^21.0.1", "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", + "es-toolkit": "^1.46.0", "is-plain-obj": "^4.1.0", - "lodash.mergewith": "^4.6.2", "picocolors": "^1.1.1" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/message": { - "version": "20.4.3", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-20.4.3.tgz", - "integrity": "sha512-6akwCYrzcrFcTYz9GyUaWlhisY4lmQ3KvrnabmhoeAV8nRH4dXJAh4+EUQ3uArtxxKQkvxJS78hNX2EU3USgxQ==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-21.0.2.tgz", + "integrity": "sha512-5n4aqHGD/FNnom/D5L8i7cYtV+xjuXcBL832C3w9VglEsZzIsoHpJsvxzJ7cgiOsOdc/2jU4t5+7qMHh7GBX3g==", "dev": true, "license": "MIT", "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/parse": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-20.5.0.tgz", - "integrity": "sha512-SeKWHBMk7YOTnnEWUhx+d1a9vHsjjuo6Uo1xRfPNfeY4bdYFasCH1dDpAv13Lyn+dDPOels+jP6D2GRZqzc5fA==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.0.2.tgz", + "integrity": "sha512-QVZJhGHTm+oiuWyEKOCTQ0ZM3mfJ0eGWFeHuj7WzSKEth+UukcCHac9GD8pgdFlg/qGkFWOtyaNd1T8REgagaw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", + "@commitlint/types": "^21.0.1", "conventional-changelog-angular": "^8.2.0", "conventional-commits-parser": "^6.3.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/read": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-20.5.0.tgz", - "integrity": "sha512-JDEIJ2+GnWpK8QqwfmW7O42h0aycJEWNqcdkJnyzLD11nf9dW2dWLTVEa8Wtlo4IZFGLPATjR5neA5QlOvIH1w==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.0.2.tgz", + "integrity": "sha512-BtsrnLVycSSKf4Q0gMch4giCj5NNlmcbhc8ra5vONgGtP2IjRDo33bEFtr5Pm+2N+5fXGWb2MksWPrspPfdhdw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/top-level": "^20.4.3", - "@commitlint/types": "^20.5.0", + "@commitlint/top-level": "^21.0.2", + "@commitlint/types": "^21.0.1", "git-raw-commits": "^5.0.0", - "minimist": "^1.2.8", "tinyexec": "^1.0.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/resolve-extends": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.0.tgz", - "integrity": "sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.0.1.tgz", + "integrity": "sha512-0DhjYWL6uYrY16Efa032fYk3woGJDU4AGWiG1XXltT9AMUNYKyb5cIZU2ivbaMZ3+kKFqUjikD2cjh66Sbh/Sg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.5.0", - "@commitlint/types": "^20.5.0", - "global-directory": "^4.0.1", - "import-meta-resolve": "^4.0.0", - "lodash.mergewith": "^4.6.2", + "@commitlint/config-validator": "^21.0.1", + "@commitlint/types": "^21.0.1", + "es-toolkit": "^1.46.0", + "global-directory": "^5.0.0", "resolve-from": "^5.0.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/resolve-extends/node_modules/resolve-from": { @@ -428,48 +472,48 @@ } }, "node_modules/@commitlint/rules": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.0.tgz", - "integrity": "sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.0.2.tgz", + "integrity": "sha512-k6tQ69Td7t2qUSIbik8D3TL1q3ZJpkEbV+yLogDzCRAdOxJm4ndhtBNREsLA1/puRfWvzS9eioF2w43WT+hHgQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.5.0", - "@commitlint/message": "^20.4.3", - "@commitlint/to-lines": "^20.0.0", - "@commitlint/types": "^20.5.0" + "@commitlint/ensure": "^21.0.1", + "@commitlint/message": "^21.0.2", + "@commitlint/to-lines": "^21.0.1", + "@commitlint/types": "^21.0.1" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/to-lines": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-20.0.0.tgz", - "integrity": "sha512-2l9gmwiCRqZNWgV+pX1X7z4yP0b3ex/86UmUFgoRt672Ez6cAM2lOQeHFRUTuE6sPpi8XBCGnd8Kh3bMoyHwJw==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-21.0.1.tgz", + "integrity": "sha512-bd1BFII7p1EQZre9Kaj+kKaMFP3cFCdt21K7DItVux9XP5WjLgJ0/Uy1pJJh9aPwVJ6SKg62PxqlZaHI8hQAXw==", "dev": true, "license": "MIT", "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/top-level": { - "version": "20.4.3", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-20.4.3.tgz", - "integrity": "sha512-qD9xfP6dFg5jQ3NMrOhG0/w5y3bBUsVGyJvXxdWEwBm8hyx4WOk3kKXw28T5czBYvyeCVJgJJ6aoJZUWDpaacQ==", + "version": "21.0.2", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-21.0.2.tgz", + "integrity": "sha512-s9KKM+e+mXgFeIh4n7KmOGAVT3mkJ3Fp1bBYHIK5pjeUwlEMzp/tZfb5u0Poa680AsQTXMEMRxZi1vQ9m2X5ug==", "dev": true, "license": "MIT", "dependencies": { "escalade": "^3.2.0" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@commitlint/types": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-20.5.0.tgz", - "integrity": "sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.0.1.tgz", + "integrity": "sha512-4u7w8jcoCUFWhjWnASYzZHAP34OqOtuFBN87nQmFvqda03YU0T6z+yB4w0gSAMpekiRqqGk5rt+qSlW+a2vSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -477,13 +521,13 @@ "picocolors": "^1.1.1" }, "engines": { - "node": ">=v18" + "node": ">=22.12.0" } }, "node_modules/@conventional-changelog/git-client": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz", - "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", "dev": true, "license": "MIT", "dependencies": { @@ -496,7 +540,7 @@ }, "peerDependencies": { "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.3.0" + "conventional-commits-parser": "^6.4.0" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -519,11 +563,22 @@ "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==", "dev": true }, + "node_modules/@eeholmes/zarrita-pcodec": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/eeholmes/zarrita-pcodec.git#ef4c1b6337be9287eba8fcaccf6b9cd4d61eb1f2", + "peerDependencies": { + "zarrita": "^0.7.3" + }, + "peerDependenciesMeta": { + "zarrita": { + "optional": true + } + } + }, "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": { @@ -535,7 +590,6 @@ "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": { @@ -546,7 +600,6 @@ "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": { @@ -923,7 +976,7 @@ "version": "0.127.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -933,7 +986,6 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", - "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { @@ -972,7 +1024,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -993,7 +1044,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1014,7 +1064,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1035,7 +1084,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1056,7 +1104,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1077,7 +1124,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1098,7 +1144,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1119,7 +1164,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1140,7 +1184,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1160,7 +1203,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1180,7 +1222,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1201,7 +1242,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1222,7 +1262,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1237,13 +1276,13 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^14.18.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/pkgr" @@ -1337,7 +1376,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1354,7 +1392,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1371,7 +1408,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1388,7 +1424,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1405,7 +1440,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1422,7 +1456,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1439,7 +1472,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1456,7 +1488,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1473,7 +1504,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1490,7 +1520,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1507,7 +1536,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1524,7 +1552,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1541,7 +1568,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1557,7 +1583,6 @@ "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": { @@ -1579,7 +1604,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1596,7 +1620,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1610,7 +1633,7 @@ "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@rtsao/scc": { @@ -1649,6 +1672,13 @@ "url": "https://ko-fi.com/dangreen" } }, + "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/@turf/boolean-point-in-polygon": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-7.2.0.tgz", @@ -1699,13 +1729,23 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/@types/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-delaunay": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", @@ -1722,6 +1762,13 @@ "@types/geojson": "*" } }, + "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/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1740,6 +1787,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", + "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", @@ -1755,13 +1808,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.39", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", - "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", - "dev": true, + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", + "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", + "devOptional": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/qrcode": { @@ -2358,13 +2411,13 @@ ] }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.6.tgz", - "integrity": "sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.13" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -2375,12 +2428,135 @@ } }, "node_modules/@vitejs/plugin-vue/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz", - "integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==", + "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/@vitest/expect": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz", + "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz", + "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.9", + "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/mocker/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/@vitest/pretty-format": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz", + "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz", + "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz", + "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "@vitest/utils": "4.1.9", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz", + "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz", + "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.9", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@volar/language-core": { "version": "2.4.28", "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", @@ -2438,53 +2614,53 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.33.tgz", - "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.33", + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz", - "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.33.tgz", - "integrity": "sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.33", - "@vue/compiler-dom": "3.5.33", - "@vue/compiler-ssr": "3.5.33", - "@vue/shared": "3.5.33", + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.10", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.33.tgz", - "integrity": "sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/devtools-api": { @@ -2547,53 +2723,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.33.tgz", - "integrity": "sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.33" + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.33.tgz", - "integrity": "sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.33.tgz", - "integrity": "sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.33", - "@vue/runtime-core": "3.5.33", - "@vue/shared": "3.5.33", + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.33.tgz", - "integrity": "sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { - "vue": "3.5.33" + "vue": "3.5.38" } }, "node_modules/@vue/shared": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.33.tgz", - "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", "license": "MIT" }, "node_modules/@vue/tsconfig": { @@ -2616,15 +2792,15 @@ } }, "node_modules/@vuepic/vue-datepicker": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-13.0.0.tgz", - "integrity": "sha512-7emyDtXcTDn0w1+RLcyYhdZFw2pE9EGbDuyFrN3XJju8nJVPcU822M2znrzmNdZU82R5ItyBeagZBtsYzUVy3g==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-14.0.0.tgz", + "integrity": "sha512-zDl1U2MRk+udu0gYA3pdY2f0O+ckqUPiKgWmp7qQV3D7CRgDKYvUXFpnt+rgMQ+uLydtlRqzy4eS6nvtVjNS4A==", "license": "MIT", "dependencies": { - "@date-fns/tz": "^1.4.1", + "@date-fns/tz": "^1.5.0", "@floating-ui/vue": "^1.1.11", "@vueuse/core": "^14.3.0", - "date-fns": "^4.2.1" + "date-fns": "^4.4.0" }, "engines": { "node": ">=18.12.0" @@ -2916,6 +3092,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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-kit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", @@ -2933,13 +3119,14 @@ } }, "node_modules/ast-walker-scope": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", - "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.9.0.tgz", + "integrity": "sha512-IJdzo2vLiElBxKzwS36VsCue/62d6IdWjnPB2v3nuPKeWGynp6FF/CYoLa5i/3jXH/z97ZDdsXz6abpgM6w07A==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.4", - "ast-kit": "^2.1.3" + "@babel/parser": "^7.29.2", + "@babel/types": "^7.29.0", + "ast-kit": "^2.2.0" }, "engines": { "node": ">=20.19.0" @@ -2981,9 +3168,9 @@ } }, "node_modules/axios": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", - "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz", + "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", @@ -3039,7 +3226,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, + "devOptional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -3132,6 +3319,16 @@ "integrity": "sha512-kD47Nh9PC7HiZ+MHZn9/DKNbnMGT+xuLZHLOgbcWZo84jo7gRDTFCBqpehZBT+OFSSpYw2GKHl5hPvDa1q4y8A==", "license": "MIT" }, + "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", @@ -3173,7 +3370,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "devOptional": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -3218,81 +3415,71 @@ } }, "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==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=20" } }, - "node_modules/cliui/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==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cliui/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==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/cliui/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==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui/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==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/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" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -3314,13 +3501,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3424,6 +3604,13 @@ "node": ">=18" } }, + "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/copy-anything": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", @@ -3446,9 +3633,9 @@ "license": "MIT" }, "node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", "dev": true, "license": "MIT", "dependencies": { @@ -3473,13 +3660,13 @@ } }, "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.3.0.tgz", + "integrity": "sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==", "dev": true, "license": "MIT", "dependencies": { - "jiti": "^2.6.1" + "jiti": "2.6.1" }, "engines": { "node": ">=v18" @@ -3723,9 +3910,9 @@ } }, "node_modules/date-fns": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.3.0.tgz", - "integrity": "sha512-OYcL+3N/jyWbYdFGqoMAhytDgxP9pbYPUUiRCOgn4Fewaadk9l/Wam4Avciiyp2BgkpfQyBV9B+ehnVJych+eQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", + "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", "license": "MIT", "funding": { "type": "github", @@ -3733,9 +3920,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.20", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", - "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "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": { @@ -3827,7 +4014,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -4048,6 +4234,13 @@ "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.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -4106,6 +4299,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.1.tgz", + "integrity": "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4273,9 +4477,9 @@ } }, "node_modules/eslint-import-resolver-typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", - "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.5.tgz", + "integrity": "sha512-nbE5XLph6TLtGYcu/U6e6ZVXyKBhbDWK5cLGk76eJ7NdZpwf1P9EFkpt1Z01mNZNrrilsAYWKH6zUkL4reoXbw==", "dev": true, "license": "ISC", "dependencies": { @@ -4411,14 +4615,14 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.6.tgz", + "integrity": "sha512-ifetmTcxWfz+4qRW3pH/ujdTq2jQIj59AxJMIN26K5avYgU8dxycUETQonWiW+wPrYXA0j3Try0l1CnwVQtDqQ==", "dev": true, "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.1", - "synckit": "^0.11.12" + "synckit": "^0.11.13" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4442,10 +4646,11 @@ } }, "node_modules/eslint-plugin-promise": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", - "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.3.0.tgz", + "integrity": "sha512-6uGiOR0INuujr6PEQmeSSP7GbIMJ/ebEXXiEzb/nOj68LknH5Pxzb/AbZivmr6VE6TkTE8rTjRK9zhKpK6HsRA==", "dev": true, + "license": "ISC", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0" }, @@ -4456,13 +4661,13 @@ "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-vue": { - "version": "10.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.8.0.tgz", - "integrity": "sha512-f1J/tcbnrpgC8suPN5AtdJ5MQjuXbSU9pGRSSYAuF3SHoiYCOdEX6O22pLaRyLHXvDcOe+O5ENgc1owQ587agA==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.9.2.tgz", + "integrity": "sha512-4g7ZP3pYcuqd7Zp0pzUKcos0W+RkjBz4EGdhJ92FcYk6v03Ti/GK5NwjgsjxHK+98eXDbHeK7VtX1az7/8doZA==", "dev": true, "license": "MIT", "dependencies": { @@ -4480,7 +4685,7 @@ "@stylistic/eslint-plugin": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "@typescript-eslint/parser": "^7.0.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "vue-eslint-parser": "^10.0.0" + "vue-eslint-parser": "^10.3.0" }, "peerDependenciesMeta": { "@stylistic/eslint-plugin": { @@ -4615,6 +4820,16 @@ "node": ">=0.8.x" } }, + "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/exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", @@ -4713,7 +4928,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, + "devOptional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4830,7 +5045,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -4916,9 +5130,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "dev": true, "license": "MIT", "engines": { @@ -5026,25 +5240,25 @@ } }, "node_modules/global-directory": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", "dev": true, "license": "MIT", "dependencies": { - "ini": "4.1.1" + "ini": "6.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globals": { - "version": "17.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", - "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", + "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", "dev": true, "license": "MIT", "engines": { @@ -5500,7 +5714,7 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -5519,17 +5733,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -5547,13 +5750,13 @@ "license": "ISC" }, "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", "dev": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/internal-slot": { @@ -5735,7 +5938,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -5796,7 +5999,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, + "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -5834,7 +6037,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.12.0" } @@ -6052,7 +6255,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -6130,9 +6333,9 @@ } }, "node_modules/kdbush": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", - "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz", + "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==", "license": "ISC" }, "node_modules/keyv": { @@ -6161,7 +6364,7 @@ "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, + "devOptional": true, "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -6194,7 +6397,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6215,7 +6417,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6236,7 +6437,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6257,7 +6457,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6278,7 +6477,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6299,7 +6497,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6320,7 +6517,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6341,7 +6537,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6362,7 +6557,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6383,7 +6577,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6404,7 +6597,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MPL-2.0", "optional": true, "os": [ @@ -6422,7 +6614,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -6436,37 +6628,28 @@ "license": "MIT" }, "node_modules/lint-staged": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", - "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", + "version": "17.0.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-17.0.7.tgz", + "integrity": "sha512-JrSobt+tW3rH8IOMi8tDZd3foorM5yPEkLD/V2NxobgHrFfHWGee4MOLVuZeScgxftEwbHrPHIFA/ZL+nUJeuA==", "dev": true, "license": "MIT", "dependencies": { - "commander": "^14.0.3", - "listr2": "^9.0.5", - "picomatch": "^4.0.3", + "listr2": "^10.2.1", + "picomatch": "^4.0.4", "string-argv": "^0.3.2", - "tinyexec": "^1.0.4", - "yaml": "^2.8.2" + "tinyexec": "^1.2.4" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": ">=20.17" + "node": ">=22.22.1" }, "funding": { "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" + }, + "optionalDependencies": { + "yaml": "^2.9.0" } }, "node_modules/lint-staged/node_modules/picomatch": { @@ -6483,21 +6666,20 @@ } }, "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", + "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", "dev": true, "license": "MIT", "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", + "cli-truncate": "^5.2.0", + "eventemitter3": "^5.0.4", "log-update": "^6.1.0", "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" + "wrap-ansi": "^10.0.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.13.0" } }, "node_modules/local-pkg": { @@ -6532,54 +6714,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", - "dev": true, - "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 }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.startcase": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", - "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.upperfirst": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", - "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", - "dev": true, - "license": "MIT" - }, "node_modules/log-update": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", @@ -6613,6 +6753,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -6630,6 +6777,42 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -6703,11 +6886,17 @@ "dev": true, "license": "MIT" }, + "node_modules/mgrs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", + "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==", + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, + "devOptional": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6826,15 +7015,16 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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" }, @@ -6875,7 +7065,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "optional": true }, "node_modules/nth-check": { @@ -6995,6 +7184,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7177,7 +7380,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7246,9 +7449,9 @@ } }, "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -7265,7 +7468,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7297,9 +7500,9 @@ } }, "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { @@ -7348,6 +7551,27 @@ "dev": true, "license": "MIT" }, + "node_modules/proj4": { + "version": "2.20.9", + "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.20.9.tgz", + "integrity": "sha512-GLBGqXaTcdWnppre3o1sMmy4DcMGSGq/ng+9k2MTNddarRK6SveINqlqYzi3xEXuy06ljY1TTrC6H9C4f360IQ==", + "license": "MIT", + "dependencies": { + "mgrs": "1.0.0", + "wkt-parser": "^1.5.5" + }, + "funding": { + "url": "https://github.com/sponsors/ahocevar" + }, + "peerDependencies": { + "geotiff": "*" + }, + "peerDependenciesMeta": { + "geotiff": { + "optional": true + } + } + }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", @@ -7608,7 +7832,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 14.18.0" }, @@ -7763,7 +7987,7 @@ "version": "1.0.0-rc.17", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@oxc-project/types": "=0.127.0", @@ -7873,7 +8097,7 @@ "version": "1.89.2", "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", @@ -8068,6 +8292,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", @@ -8156,6 +8387,13 @@ "node": "*" } }, + "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/static-eval": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", @@ -8166,6 +8404,13 @@ "escodegen": "^2.1.0" } }, + "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/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -8215,9 +8460,9 @@ } }, "node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "dev": true, "license": "MIT", "dependencies": { @@ -8366,13 +8611,13 @@ } }, "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", + "integrity": "sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.9" + "@pkgr/core": "^0.3.6" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -8435,10 +8680,17 @@ "xtend": "~4.0.1" } }, + "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.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", "engines": { @@ -8496,11 +8748,21 @@ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", "license": "ISC" }, + "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/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "devOptional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -8714,10 +8976,10 @@ } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "devOptional": true, "license": "MIT" }, "node_modules/unplugin": { @@ -8839,7 +9101,7 @@ "version": "8.0.10", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", @@ -8938,6 +9200,109 @@ } }, "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", + "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.9", + "@vitest/mocker": "4.1.9", + "@vitest/pretty-format": "4.1.9", + "@vitest/runner": "4.1.9", + "@vitest/snapshot": "4.1.9", + "@vitest/spy": "4.1.9", + "@vitest/utils": "4.1.9", + "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.9", + "@vitest/browser-preview": "4.1.9", + "@vitest/browser-webdriverio": "4.1.9", + "@vitest/coverage-istanbul": "4.1.9", + "@vitest/coverage-v8": "4.1.9", + "@vitest/ui": "4.1.9", + "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/vitest/node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", @@ -8958,16 +9323,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.33.tgz", - "integrity": "sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.33", - "@vue/compiler-sfc": "3.5.33", - "@vue/runtime-dom": "3.5.33", - "@vue/server-renderer": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { "typescript": "*" @@ -8979,16 +9344,17 @@ } }, "node_modules/vue-eslint-parser": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.2.0.tgz", - "integrity": "sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.4.1.tgz", + "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "debug": "^4.4.0", - "eslint-scope": "^8.2.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "eslint-scope": "^8.2.0 || ^9.0.0", + "eslint-visitor-keys": "^4.2.0 || ^5.0.0", + "espree": "^10.3.0 || ^11.0.0", "esquery": "^1.6.0", "semver": "^7.6.3" }, @@ -8999,7 +9365,7 @@ "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0" } }, "node_modules/vue-json-pretty": { @@ -9016,37 +9382,38 @@ } }, "node_modules/vue-router": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.6.tgz", - "integrity": "sha512-9+kmUTGbKMyW9Asoy98IXXYIzrTMT7JDAdpDDeEkorHvybpUvBI2wsrSM5jFOXrFydpzRFJ9vAh+80DN2PGu9w==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.1.0.tgz", + "integrity": "sha512-HAbiLzLEHQwxPgvsbOJDAwtavszEgLwri6XfyrsPECIFez8+59xc9LofWVdc/HEaSRT822lJ8H9Ns38VVond5g==", "license": "MIT", "dependencies": { - "@babel/generator": "^7.28.6", + "@babel/generator": "^8.0.0-rc.4", "@vue-macros/common": "^3.1.1", - "@vue/devtools-api": "^8.0.6", - "ast-walker-scope": "^0.8.3", + "@vue/devtools-api": "^8.1.2", + "ast-walker-scope": "^0.9.0", "chokidar": "^5.0.0", "json5": "^2.2.3", "local-pkg": "^1.1.2", "magic-string": "^0.30.21", - "mlly": "^1.8.0", + "mlly": "^1.8.2", "muggle-string": "^0.4.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "scule": "^1.3.0", - "tinyglobby": "^0.2.15", + "tinyglobby": "^0.2.16", "unplugin": "^3.0.0", "unplugin-utils": "^0.3.1", - "yaml": "^2.8.2" + "yaml": "^2.9.0" }, "funding": { "url": "https://github.com/sponsors/posva" }, "peerDependencies": { "@pinia/colada": ">=0.21.2", - "@vue/compiler-sfc": "^3.5.17", + "@vue/compiler-sfc": "^3.5.34", "pinia": "^3.0.4", - "vue": "^3.5.0" + "vite": "^7.0.0 || ^8.0.0", + "vue": "^3.5.34" }, "peerDependenciesMeta": { "@pinia/colada": { @@ -9057,34 +9424,37 @@ }, "pinia": { "optional": true + }, + "vite": { + "optional": true } } }, "node_modules/vue-router/node_modules/@vue/devtools-api": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.1.tgz", - "integrity": "sha512-bsDMJ07b3GN1puVwJb/fyFnj/U2imyswK5UQVLZwVl7O05jDrt6BHxeG5XffmOOdasOj/bOmIjxJvGPxU7pcqw==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz", + "integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==", "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^8.1.1" + "@vue/devtools-kit": "^8.1.2" } }, "node_modules/vue-router/node_modules/@vue/devtools-kit": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.1.tgz", - "integrity": "sha512-gVBaBv++i+adg4JpH71k9ppl4soyR7Y2McEqO5YNgv0BI1kMZ7BDX5gnwkZ5COYgiCyhejZG+yGNrBAjj6Coqg==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz", + "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==", "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^8.1.1", + "@vue/devtools-shared": "^8.1.2", "birpc": "^2.6.1", "hookable": "^5.5.3", "perfect-debounce": "^2.0.0" } }, "node_modules/vue-router/node_modules/@vue/devtools-shared": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.1.tgz", - "integrity": "sha512-+h4ttmJYl/txpxHKaoZcaKpC+pvckgLzIDiSQlaQ7kKthKh8KuwoLW2D8hPJEnqKzXOvu15UHEoGyngAXCz0EQ==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz", + "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==", "license": "MIT" }, "node_modules/vue-router/node_modules/chokidar": { @@ -9278,6 +9648,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/wkt-parser": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.5.5.tgz", + "integrity": "sha512-/zMYi94/7D7fxcOSlVmWn6vnOMj3Gq5d1xvVjaYOS9n6h0qOJ4I7YYVxBWYcH1vq9+suhqzXkn05Yx47zQNUIA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ahocevar" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -9295,18 +9691,18 @@ "license": "MIT" }, "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9325,31 +9721,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9387,9 +9758,9 @@ } }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -9402,80 +9773,56 @@ } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "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==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, "license": "ISC", "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yargs/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/yargs/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==", + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/yargs/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==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/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" + "node": ">=18" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index ae6964e6..deb72a80 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,12 @@ "dev": "vite --port 3000", "build": "vue-tsc -b && vite build", "preview": "vite preview --port 5050", + "test": "vitest run", + "test:watch": "vitest", "typecheck": "vue-tsc --noEmit", - "lint": "eslint src", - "lint-ci": "eslint src --max-warnings 0", - "lint:fix": "eslint src --fix", + "lint": "eslint src tests", + "lint-ci": "eslint src tests --max-warnings 0", + "lint:fix": "eslint src tests --fix", "prepare": "husky" }, "lint-staged": { @@ -26,12 +28,13 @@ }, "type": "module", "dependencies": { + "@eeholmes/zarrita-pcodec": "github:eeholmes/zarrita-pcodec", "@fortawesome/fontawesome-free": "^7.2.0", "@hscmap/healpix": "^1.4.12", "@primevue/themes": "^4.5.4", - "@vuepic/vue-datepicker": "13.0.0", - "@vueuse/core": "^14.2.1", - "axios": "^1.15.2", + "@vuepic/vue-datepicker": "14.0.0", + "@vueuse/core": "^14.3.0", + "axios": "^1.18.0", "bulma": "^1.0.4", "canvas-txt": "^4.1.1", "chart.js": "^4.5.1", @@ -39,57 +42,59 @@ "d3-delaunay": "^6.0.4", "d3-geo": "^3.1.1", "d3-geo-projection": "^4.0.0", - "dayjs": "^1.11.20", + "dayjs": "^1.11.21", "fflate": "^0.8.3", "geokdbush": "2.1.0", "humanize-duration": "^3.33.2", "icechunk-js": "^0.4.0", - "kdbush": "4.0.2", + "kdbush": "4.1.0", "pinia": "^3.0.4", "primevue": "^4.5.5", + "proj4": "^2.20.9", "qrcode": "^1.5.4", "quick-lru": "^7.3.0", "three": "^0.184", "three-conic-polygon-geometry": "^2.1.3", "three-geojson-geometry": "^2.1.1", - "vue": "^3.5.33", + "vue": "^3.5.38", "vue-json-pretty": "^2.6.0", - "vue-router": "^5.0.6", + "vue-router": "^5.1.0", "zarrita": "^0.7.3" }, "devDependencies": { - "@commitlint/cli": "^20.5.0", - "@commitlint/config-conventional": "^20.5.0", + "@commitlint/cli": "^21.0.2", + "@commitlint/config-conventional": "^21.0.2", "@types/d3-delaunay": "^6.0.4", "@types/d3-geo": "^3.1.0", "@types/geojson": "7946.0.16", "@types/humanize-duration": "^3.27.4", - "@types/node": "^20.17", + "@types/node": "~24", "@types/qrcode": "^1.5.6", "@types/three": "0.184.1", - "@vitejs/plugin-vue": "^6.0.6", + "@vitejs/plugin-vue": "^6.0.7", "@vue/tsconfig": "0.9.1", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-import-resolver-typescript": "^4.4.4", + "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-boundaries": "^6.0.2", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-prettier": "^5.5.5", - "eslint-plugin-promise": "^7.2.1", - "eslint-plugin-vue": "10.8", - "globals": "^17.5.0", + "eslint-plugin-prettier": "^5.5.6", + "eslint-plugin-promise": "^7.3.0", + "eslint-plugin-vue": "10.9", + "globals": "^17.6.0", "glslify": "^7.1.1", "husky": "^9.1.7", - "lint-staged": "^16.4.0", - "prettier": "^3.8.3", + "lint-staged": "^17.0.7", + "prettier": "^3.8.4", "sass": "~1.89.2", "typescript": "^6.0.3", "typescript-eslint": "^8.59.0", "vite": "^8.0.10", "vite-plugin-glsl": "^1.6.0", + "vitest": "^4.1.9", "vue-tsc": "^3.2.7" }, "engines": { - "node": ">=20.17.0" + "node": ">=24.16.0" } } diff --git a/src/lib/data/ZarrDataManager.ts b/src/lib/data/ZarrDataManager.ts index 166be1e1..6c52929b 100644 --- a/src/lib/data/ZarrDataManager.ts +++ b/src/lib/data/ZarrDataManager.ts @@ -1,7 +1,12 @@ -import { IcechunkStore } from "icechunk-js"; import QuickLRU from "quick-lru"; import * as zarr from "zarrita"; +import { + createIcechunkStore, + isIcechunkStorePath, + parseStorePath, +} from "./icechunkStore.ts"; + import { ZARR_FORMAT, type TDataSource, @@ -26,7 +31,6 @@ export type TZarrVariableMetadata = { }; type TDatasetSource = Pick; -type TIcechunkStore = zarr.AsyncReadable & Pick; export class ZarrDataManager { private static pendingStore: Promise< @@ -42,33 +46,17 @@ export class ZarrDataManager { return dataset.replace(/^\/+/, "").replace(/\/+$/, ""); } - static isIcechunkStorePath(storePath: string) { - return this.normalizeStorePath(storePath.split(/[?#]/)[0]).endsWith( - ".icechunk" - ); - } - - private static async createIcechunkStore( - storePath: string - ): Promise { - return await IcechunkStore.open(this.normalizeStorePath(storePath)); - } - - static async createListableIcechunkStore(storePath: string) { - const store = await this.createIcechunkStore(storePath); - const contents = store.listNodes().map((node) => ({ - path: node.path as zarr.AbsolutePath, - kind: node.nodeData.type, - })); - return Object.assign(store, { contents: () => contents }); - } - public static async createNewStore(storePath: string, isIcechunk = false) { + const parsed = parseStorePath(storePath); let store: zarr.AsyncReadable | undefined = undefined; - if (isIcechunk || this.isIcechunkStorePath(storePath)) { - store = await this.createIcechunkStore(storePath); + if ( + isIcechunk || + parsed.backend === "icechunk" || + isIcechunkStorePath(storePath) + ) { + store = await createIcechunkStore(storePath); } else { - store = new zarr.FetchStore(storePath, { useSuffixRequest: true }); + store = new zarr.FetchStore(parsed.url, { useSuffixRequest: true }); } const cache = new QuickLRU({ @@ -150,6 +138,28 @@ export class ZarrDataManager { return array; } + static async getParentGroup( + datasources: TSources, + varname: string, + format?: TZarrFormat + ): Promise> { + const groupPath = await ZarrDataManager.resolveGroupPath(varname); + const source = ZarrDataManager.getDatasetSource(datasources, varname); + const target = (await ZarrDataManager.getDataset(source)).resolve( + groupPath + ); + + let dataset: zarr.Group; + if (format === ZARR_FORMAT.V2) { + dataset = await zarr.open.v2(target, { kind: "group" }); + } else if (format === ZARR_FORMAT.V3) { + dataset = await zarr.open.v3(target, { kind: "group" }); + } else { + dataset = await zarr.open(target, { kind: "group" }); + } + return dataset; + } + static async getVariableInfoByDatasetSources( datasource: TSources, variable: string @@ -211,6 +221,13 @@ export class ZarrDataManager { if (group.attrs?.grid_mapping) { return String(group.attrs.grid_mapping).split(":")[0]; } + if ( + (datavar.attrs?.coordinates as string | undefined)?.includes( + "spatial_ref" + ) + ) { + return "spatial_ref"; + } return "crs"; } @@ -235,6 +252,14 @@ export class ZarrDataManager { return datavar.dimensionNames ?? []; } + static resolveGroupPath(variable: string): string { + if (!variable.includes("/")) { + return "/"; + } + + return variable.split("/").slice(0, -1).join("/"); + } + static resolveVariablePath( contextVariable: string, variable: string diff --git a/src/lib/data/codecs.ts b/src/lib/data/codecs.ts index 3a19b767..41621ce2 100644 --- a/src/lib/data/codecs.ts +++ b/src/lib/data/codecs.ts @@ -1,5 +1,6 @@ +import { registerPCodec } from "@eeholmes/zarrita-pcodec"; import { registry } from "zarrita"; import { Fletcher32Codec } from "./fletcher32.ts"; - registry.set("numcodecs.fletcher32", async () => Fletcher32Codec); +registerPCodec(registry); diff --git a/src/lib/data/coordinateVariables.ts b/src/lib/data/coordinateVariables.ts index ec5ce35a..6304f6c1 100644 --- a/src/lib/data/coordinateVariables.ts +++ b/src/lib/data/coordinateVariables.ts @@ -1,3 +1,4 @@ +import proj4 from "proj4"; import * as zarr from "zarrita"; import { decodeVariableChunkInPlace } from "./variableDecoding.ts"; @@ -5,7 +6,25 @@ import { ZarrDataManager } from "./ZarrDataManager.ts"; import { type TSources } from "@/lib/types/GlobeTypes.ts"; -const EARTH_RADIUS = 6378137; +const WGS84 = "EPSG:4326"; +const WEB_MERCATOR = "EPSG:3857"; + +export const ProjectedCoordinateName = { + X: "x", + Y: "y", +} as const; + +export type TProjectedCoordinateName = + (typeof ProjectedCoordinateName)[keyof typeof ProjectedCoordinateName]; + +export const CrsWktAttributeName = { + CRS_WKT: "crs_wkt", + SPATIAL_REF: "spatial_ref", + PROJECTION: "projection", +} as const; + +export type TCrsWktAttributeName = + (typeof CrsWktAttributeName)[keyof typeof CrsWktAttributeName]; export function isWebMercatorCRS(crsWkt: string): boolean { return ( @@ -17,46 +36,227 @@ export function isWebMercatorCRS(crsWkt: string): boolean { } export function isProjectedXName(name: string): boolean { - return name === "x"; + return getVariableLocalName(name) === ProjectedCoordinateName.X; } export function isProjectedYName(name: string): boolean { - return name === "y"; + return getVariableLocalName(name) === ProjectedCoordinateName.Y; } -export function webMercatorToLonLat( - x: Float64Array, - y: Float64Array +function transformProjectedAxesToLonLat( + x: Float32Array, + y: Float32Array, + crsWkt: string ): { - longitudes: Float64Array; - latitudes: Float64Array; + longitudes: Float32Array; + latitudes: Float32Array; } { - const longitudes = new Float64Array(x.length); - const latitudes = new Float64Array(y.length); + const transformer = proj4(crsWkt, WGS84); + const longitudes = new Float32Array(x.length); + const latitudes = new Float32Array(y.length); + for (let i = 0; i < x.length; i++) { - longitudes[i] = (x[i] / EARTH_RADIUS) * (180 / Math.PI); + const [lon] = transformer.forward([x[i], 0]); + longitudes[i] = lon; } for (let i = 0; i < y.length; i++) { - latitudes[i] = - (Math.atan(Math.exp(y[i] / EARTH_RADIUS)) * 2 - Math.PI / 2) * - (180 / Math.PI); + const [, lat] = transformer.forward([0, y[i]]); + latitudes[i] = lat; } + return { longitudes, latitudes }; } +export function webMercatorToLonLat( + x: Float32Array, + y: Float32Array +): { + longitudes: Float32Array; + latitudes: Float32Array; +} { + return transformProjectedAxesToLonLat(x, y, WEB_MERCATOR); +} + +export function projectedAxisCoordinatesToLonLat( + x: Float32Array, + y: Float32Array, + crsWkt: string | null +): { + longitudes: Float32Array; + latitudes: Float32Array; +} { + if (!crsWkt) { + return { + longitudes: new Float32Array(x), + latitudes: new Float32Array(y), + }; + } + if (isWebMercatorCRS(crsWkt)) { + return transformProjectedAxesToLonLat(x, y, crsWkt); + } + return { + longitudes: new Float32Array(x), + latitudes: new Float32Array(y), + }; +} + +function getStringAttribute( + attrs: zarr.Attributes, + name: TCrsWktAttributeName +) { + const value = attrs[name]; + return typeof value === "string" ? value : null; +} + +function getWktFromAttrs(attrs: zarr.Attributes) { + return ( + getStringAttribute(attrs, CrsWktAttributeName.CRS_WKT) ?? + getStringAttribute(attrs, CrsWktAttributeName.SPATIAL_REF) ?? + getStringAttribute(attrs, CrsWktAttributeName.PROJECTION) + ); +} + +async function getGroupCRSWkt(datasources: TSources, variable: string) { + const group = await ZarrDataManager.getDatasetGroup( + ZarrDataManager.getDatasetSource(datasources, variable) + ); + return getWktFromAttrs(group.attrs); +} + export async function getCRSWkt( datasources: TSources, variable: string ): Promise { try { const crs = await ZarrDataManager.getCRSInfo(datasources, variable); - const wkt = crs.attrs["crs_wkt"] ?? crs.attrs["spatial_ref"]; - return typeof wkt === "string" ? wkt : null; + const wkt = getWktFromAttrs(crs.attrs); + if (wkt) { + return wkt; + } + } catch { + // Fall through to group attrs. + } + try { + return await getGroupCRSWkt(datasources, variable); } catch { return null; } } +function createFloat32Chunk( + data: Float32Array, + shape: number[] +): zarr.Chunk<"float32"> { + let strideValue = 1; + const stride = new Array(shape.length); + for (let i = shape.length - 1; i >= 0; i--) { + stride[i] = strideValue; + strideValue *= shape[i]; + } + return { data, shape, stride }; +} + +function projectXYGridToLonLat( + x: Float32Array, + y: Float32Array, + crsWkt: string | null +) { + const shape = [y.length, x.length]; + const longitudes = new Float32Array(x.length * y.length); + const latitudes = new Float32Array(x.length * y.length); + const transformer = crsWkt ? proj4(crsWkt, WGS84) : null; + + for (let j = 0; j < y.length; j++) { + for (let i = 0; i < x.length; i++) { + const index = j * x.length + i; + if (transformer) { + const [lon, lat] = transformer.forward([x[i], y[j]]); + longitudes[index] = lon; + latitudes[index] = lat; + } else { + longitudes[index] = x[i]; + latitudes[index] = y[j]; + } + } + } + + return { + latitudes: createFloat32Chunk(latitudes, shape), + longitudes: createFloat32Chunk(longitudes, shape), + }; +} + +function getProjectedXYNames(dimensionNames: string[]) { + const xName = dimensionNames.find(isProjectedXName); + const yName = dimensionNames.find(isProjectedYName); + if (!xName || !yName) { + throw new Error("Projected x/y dimensions not found"); + } + return { xName, yName }; +} + +async function fetchProjectedXYVariables( + datasources: TSources, + variable: string, + xName: string, + yName: string +) { + const gridsource = datasources.levels[0].grid; + const [xVar, yVar] = await Promise.all([ + ZarrDataManager.getVariableInfo( + gridsource, + ZarrDataManager.resolveVariablePath(variable, xName) + ), + ZarrDataManager.getVariableInfo( + gridsource, + ZarrDataManager.resolveVariablePath(variable, yName) + ), + ]); + return { xVar, yVar }; +} + +export async function getProjectedXYLonLatData( + variable: string, + datavar: zarr.Array, + datasources: TSources | undefined, + dimensionNames = datavar.dimensionNames ?? [] +) { + const { xName, yName } = getProjectedXYNames(dimensionNames); + const { xVar, yVar } = await fetchProjectedXYVariables( + datasources!, + variable, + xName, + yName + ); + const [xCoordinates, yCoordinates] = await Promise.all([ + ZarrDataManager.getVariableDataFromArray(xVar), + ZarrDataManager.getVariableDataFromArray(yVar), + ]); + decodeVariableChunkInPlace(xCoordinates, xVar.attrs); + decodeVariableChunkInPlace(yCoordinates, yVar.attrs); + + const crsWkt = await getCRSWkt(datasources!, variable); + const { latitudes, longitudes } = projectXYGridToLonLat( + xCoordinates.data as Float32Array, + yCoordinates.data as Float32Array, + crsWkt + ); + const geographicDimensionNames = [yName, xName]; + + return { + latitudesAttrs: { + dimensionNames: geographicDimensionNames, + units: "degrees_north", + }, + latitudes, + longitudesAttrs: { + dimensionNames: geographicDimensionNames, + units: "degrees_east", + }, + longitudes, + }; +} + type TLatLonNames = { latitudeName: string | null; longitudeName: string | null; diff --git a/src/lib/data/dimensionData.ts b/src/lib/data/dimensionData.ts index 1173ecb2..3539476a 100644 --- a/src/lib/data/dimensionData.ts +++ b/src/lib/data/dimensionData.ts @@ -104,27 +104,23 @@ export async function fetchDimensionDetails( dimensionRanges: TDimensionRange[], dimSlidersValues: (number | zarr.Slice | null)[] ): Promise { - const array: TDimInfo[] = []; - for (let i = 0; i < dimensionRanges.length; i++) { - const dim = dimensionRanges[i]; - if (dim?.name === "time") { - const timeInfo = await getTimeInfo( - datasources, - dimensionRanges, - i, - dimSlidersValues[i] as number, - currentVariable - ); - array.push(timeInfo); - } else { - const dimInfo = await getDimensionInfo( + return await Promise.all( + dimensionRanges.map((dim, i) => { + if (dim?.name === "time") { + return getTimeInfo( + datasources, + dimensionRanges, + i, + dimSlidersValues[i] as number, + currentVariable + ); + } + return getDimensionInfo( datasources.levels[0].datasources[currentVariable], dim!, dimSlidersValues[i] as number, currentVariable ); - array.push(dimInfo); - } - } - return array; + }) + ); } diff --git a/src/lib/data/gridTypeDetector.ts b/src/lib/data/gridTypeDetector.ts index d27b4012..40ae5fa5 100644 --- a/src/lib/data/gridTypeDetector.ts +++ b/src/lib/data/gridTypeDetector.ts @@ -1,15 +1,17 @@ import * as zarr from "zarrita"; import { + getCRSWkt, getLatLonData, isLatitudeName, isLongitudeName, isProjectedXName, isProjectedYName, + isWebMercatorCRS, } from "./coordinateVariables.ts"; import { ZarrDataManager } from "./ZarrDataManager.ts"; -import type { TSources } from "@/lib/types/GlobeTypes.ts"; +import type { TSources, TZarrDggsMetadata } from "@/lib/types/GlobeTypes.ts"; export const GRID_TYPES = { REGULAR: "regular", @@ -48,7 +50,7 @@ export const GRID_TYPE_DISPLAY_OVERRIDES: Partial< async function checkTriangularGrid( datasources: TSources | undefined, variable: string -): Promise { +): Promise { try { const gridsource = datasources!.levels[0].grid; const resolvedPath = ZarrDataManager.resolveVariablePath( @@ -60,9 +62,9 @@ async function checkTriangularGrid( resolvedPath, datasources?.zarr_format ); - return true; + return GRID_TYPES.TRIANGULAR; } catch { - return false; + return null; } } @@ -107,12 +109,25 @@ function checkGaussianGrid(latitudes: Float64Array, longitudes: Float64Array) { // Check if grid is regular based on dimension names // Also accepts lat-only grids (e.g., zonally averaged data) -function checkRegularGridFromDimensions(dimensions: string[]): boolean { +async function checkRegularGridFromDimensions( + datasources: TSources, + varnameSelector: string +): Promise { + const dimensions = await ZarrDataManager.getDimensionNames( + datasources!, + varnameSelector + ); + const latitudeIndex = dimensions.findIndex((dim) => isLatitudeName(dim)); const longitudeIndex = dimensions.findIndex((dim) => isLongitudeName(dim)); const hasLatLon = latitudeIndex !== -1 && longitudeIndex !== -1; const hasLatOnly = latitudeIndex !== -1 && longitudeIndex === -1; - return hasLatLon || hasLatOnly; + + if (hasLatLon || hasLatOnly) { + return GRID_TYPES.REGULAR; + } + + return null; } // Check if grid uses projected x/y coordinates (e.g. EPSG:3857 with spatial_ref) @@ -120,6 +135,25 @@ function checkProjectedXYDimensions(dimensions: string[]): boolean { return dimensions.some(isProjectedXName) && dimensions.some(isProjectedYName); } +async function determineProjectedXYGridType( + datasources: TSources | undefined, + variable: string, + dimensions: string[] +): Promise { + if (!checkProjectedXYDimensions(dimensions)) { + return null; + } + if (!datasources) { + return GRID_TYPES.REGULAR; + } + + const crsWkt = await getCRSWkt(datasources, variable); + if (crsWkt && !isWebMercatorCRS(crsWkt)) { + return GRID_TYPES.CURVILINEAR; + } + return GRID_TYPES.REGULAR; +} + // Attempt to determine grid type from CRS information async function determineGridTypeFromCRS( datasources: TSources, @@ -146,16 +180,61 @@ async function determineGridTypeFromCRS( return null; } +function determineGridTypeFromDGGSZarrConvention( + metadata: TZarrDggsMetadata +): T_GRID_TYPES | null { + if (metadata["name"] !== "healpix") { + // unsupported DGGS, for now + return GRID_TYPES.ERROR; + } + + return GRID_TYPES.HEALPIX; +} + +async function determineGridTypeFromZarrConvention( + datasources: TSources, + varnameSelector: string +): Promise { + const group = await ZarrDataManager.getParentGroup( + datasources, + varnameSelector, + datasources?.zarr_format + ); + const metadata = group.attrs; + + if (!("zarr_conventions" in metadata)) { + return null; + } + + const dggsMetadata: TZarrDggsMetadata | unknown = metadata["dggs"]; + if (dggsMetadata) { + return determineGridTypeFromDGGSZarrConvention( + dggsMetadata as TZarrDggsMetadata + ); + } + + return null; +} + // Determine grid type from lat/lon data analysis async function determineGridTypeFromData( - variable: string, - datavar: zarr.Array, - datasources: TSources | undefined, - dimensions: string[] + datasources: TSources, + varnameSelector: string ): Promise { + const dimensions = await ZarrDataManager.getDimensionNames( + datasources!, + varnameSelector + ); + try { + const datavar = await ZarrDataManager.getVariableInfo( + ZarrDataManager.getDatasetSource(datasources!, varnameSelector), + varnameSelector, + datasources?.zarr_format + ); + const { latitudes, longitudes } = await getLatLonData( - variable, + varnameSelector, datavar, datasources ); @@ -175,10 +254,11 @@ async function determineGridTypeFromData( // an irregular grid return GRID_TYPES.IRREGULAR; } catch { - if (checkProjectedXYDimensions(dimensions)) { - return GRID_TYPES.REGULAR; - } - return null; + return await determineProjectedXYGridType( + datasources, + varnameSelector, + dimensions + ); } } @@ -194,42 +274,29 @@ export async function getGridType( return GRID_TYPES.ERROR; } - if (await checkTriangularGrid(datasources, varnameSelector)) { - return GRID_TYPES.TRIANGULAR; - } - - try { - const datavar = await ZarrDataManager.getVariableInfo( - ZarrDataManager.getDatasetSource(datasources!, varnameSelector), - varnameSelector, - datasources?.zarr_format - ); - + const gridDetectionFunctions: (( + datasources: TSources, + varnameSelector: string + ) => Promise)[] = [ + // Check triangular grids + checkTriangularGrid, // Check CRS-based grid types - const crsGridType = await determineGridTypeFromCRS( - datasources!, - varnameSelector - ); - if (crsGridType) { - return crsGridType; - } + determineGridTypeFromCRS, + // zarr convention metadata + determineGridTypeFromZarrConvention, + checkRegularGridFromDimensions, + determineGridTypeFromData, + ]; - const dimensions = await ZarrDataManager.getDimensionNames( - datasources!, - varnameSelector - ); - if (checkRegularGridFromDimensions(dimensions)) { - return GRID_TYPES.REGULAR; - } - - const dataGridType = await determineGridTypeFromData( - varnameSelector, - datavar, - datasources, - dimensions - ); - if (dataGridType) { - return dataGridType; + try { + for (const gridDetectionFunction of gridDetectionFunctions) { + const gridType = await gridDetectionFunction( + datasources!, + varnameSelector + ); + if (gridType) { + return gridType; + } } logError("No matching grid type found", "Could not determine grid type"); diff --git a/src/lib/data/icechunkStore.ts b/src/lib/data/icechunkStore.ts new file mode 100644 index 00000000..402f8020 --- /dev/null +++ b/src/lib/data/icechunkStore.ts @@ -0,0 +1,84 @@ +import { IcechunkStore } from "icechunk-js"; +import * as zarr from "zarrita"; + +const ICECHUNK_PREFIX = "icechunk+"; + +type TIcechunkStore = zarr.AsyncReadable & Pick; + +function normalizeStorePath(store: string) { + return store.replace(/\/+$/, ""); +} + +function toIcechunkStorePath(storeUrl: string) { + return storeUrl.startsWith(ICECHUNK_PREFIX) + ? storeUrl + : `${ICECHUNK_PREFIX}${storeUrl}`; +} + +export function parseStorePath(storePath: string): { + backend: "fetch" | "icechunk"; + url: string; +} { + const normalizedStorePath = normalizeStorePath(storePath); + if (normalizedStorePath.startsWith(ICECHUNK_PREFIX)) { + return { + backend: "icechunk", + url: normalizedStorePath.slice(ICECHUNK_PREFIX.length), + }; + } + return { backend: "fetch", url: normalizedStorePath }; +} + +export function isIcechunkStorePath(storePath: string) { + if (normalizeStorePath(storePath).startsWith(ICECHUNK_PREFIX)) { + return true; + } + return normalizeStorePath(storePath.split(/[?#]/)[0]).endsWith(".icechunk"); +} + +export async function createIcechunkStore( + storePath: string +): Promise { + return await IcechunkStore.open(parseStorePath(storePath).url); +} + +export async function createListableIcechunkStore(storePath: string) { + const store = await createIcechunkStore(storePath); + const contents = store.listNodes().map((node) => ({ + path: node.path as zarr.AbsolutePath, + kind: node.nodeData.type, + })); + return Object.assign(store, { contents: () => contents }); +} + +export async function splitIcechunkStoreAndGroup( + src: string +): Promise<{ storePath: string; groupPath: string }> { + const rawUrl = src.startsWith(ICECHUNK_PREFIX) + ? src.slice(ICECHUNK_PREFIX.length) + : src; + const normalizedUrl = normalizeStorePath(rawUrl); + const urlParts = normalizedUrl.split("/"); + let minSegments = urlParts.length; + + if (urlParts.length > 2 && urlParts[0].endsWith(":") && urlParts[1] === "") { + minSegments = 3; + } + + for (let i = urlParts.length; i >= minSegments; i--) { + const storeUrl = urlParts.slice(0, i).join("/"); + const groupPath = urlParts.slice(i).join("/"); + const storePath = toIcechunkStorePath(storeUrl); + try { + await createIcechunkStore(storePath); + return { storePath, groupPath }; + } catch { + // Not an Icechunk repository root at this path; try the parent URL. + } + } + + return { + storePath: toIcechunkStorePath(normalizedUrl), + groupPath: "", + }; +} diff --git a/src/lib/data/sourceIndexing.ts b/src/lib/data/sourceIndexing.ts index ff69cd72..3e846f9b 100644 --- a/src/lib/data/sourceIndexing.ts +++ b/src/lib/data/sourceIndexing.ts @@ -7,6 +7,11 @@ import { type TZarrFormat, } from "../types/GlobeTypes.ts"; +import { + createListableIcechunkStore, + isIcechunkStorePath, + splitIcechunkStoreAndGroup, +} from "./icechunkStore.ts"; import { ZarrDataManager } from "./ZarrDataManager.ts"; import trim from "@/utils/trim.ts"; @@ -58,10 +63,69 @@ function searchDimensionsAndCoordinates( } } +function getVariablePathInGroup(path: string, datasetPath: string) { + const normalizedPath = path.replace(/^\/+/, ""); + if (!datasetPath) { + return normalizedPath; + } + + const datasetPrefix = `${datasetPath}/`; + if (!normalizedPath.startsWith(datasetPrefix)) { + return null; + } + return normalizedPath.slice(datasetPrefix.length); +} + +type TStoreContent = { + path: zarr.AbsolutePath; + kind: "array" | "group"; +}; + +async function collectVariable( + root: zarr.Group, + src: string, + datasetPath: string, + dimensions: Set, + { path, kind }: TStoreContent +) { + if (kind !== "array") { + return {}; + } + + const varname = getVariablePathInGroup(path, datasetPath); + if (!varname) { + return {}; + } + + const variable = await zarr.open(root.resolve(path), { + kind: "array", + }); + + searchDimensionsAndCoordinates(dimensions, variable, varname); + return { + [varname]: { + store: src, + dataset: datasetPath, + hidden: !isValidVariable( + varname, + variable.shape, + variable.dimensionNames as string[] + ), + attrs: { + ...variable.attrs, + dimensionNames: variable.dimensionNames, + }, + shape: variable.shape, + dtype: String(variable.dtype), + }, + }; +} + async function collectVariables( store: zarr.Listable, root: zarr.Group, - src: string + src: string, + datasetPath = "" ): Promise<{ candidates: PromiseSettledResult>[]; dimensions: Set; @@ -70,43 +134,8 @@ async function collectVariables( const candidates = await Promise.allSettled( store .contents() - .map( - async ({ - path, - kind, - }: { - path: zarr.AbsolutePath; - kind: "array" | "group"; - }) => { - if (kind !== "array") { - return {}; - } - - const variable = await zarr.open(root.resolve(path), { - kind: "array", - }); - - const varname = path.slice(1); - - searchDimensionsAndCoordinates(dimensions, variable, varname); - return { - [varname]: { - store: src, - dataset: "", - hidden: !isValidVariable( - varname, - variable.shape, - variable.dimensionNames as string[] - ), - attrs: { - ...variable.attrs, - dimensionNames: variable.dimensionNames, - }, - shape: variable.shape, - dtype: String(variable.dtype), - }, - }; - } + .map((content) => + collectVariable(root, src, datasetPath, dimensions, content) ) ); @@ -116,9 +145,15 @@ async function collectVariables( async function processZarrVariables( store: zarr.Listable, root: zarr.Group, - src: string + src: string, + datasetPath = "" ): Promise> { - const { candidates, dimensions } = await collectVariables(store, root, src); + const { candidates, dimensions } = await collectVariables( + store, + root, + src, + datasetPath + ); // Filter and merge datasources const datasources = candidates @@ -143,7 +178,8 @@ function createIndex( title: string, datasources: Record, src: string, - zarrFormat: TZarrFormat + zarrFormat: TZarrFormat, + datasetPath = "" ): TSources { return { name: title, @@ -152,11 +188,11 @@ function createIndex( { time: { store: src, - dataset: "", + dataset: datasetPath, }, grid: { store: src, - dataset: "", + dataset: datasetPath, }, datasources, }, @@ -165,19 +201,29 @@ function createIndex( } export async function indexFromIcechunk(src: string): Promise { - const store = await ZarrDataManager.createListableIcechunkStore(src); + const { storePath, groupPath } = await splitIcechunkStoreAndGroup(src); + const store = await createListableIcechunkStore(storePath); const root = await zarr.open.v3(store, { kind: "group" }); - const datasources = await processZarrVariables(store, root, src); + const group = groupPath + ? await zarr.open.v3(root.resolve(groupPath), { kind: "group" }) + : root; + const datasources = await processZarrVariables( + store, + root, + storePath, + groupPath + ); return createIndex( - root.attrs?.title as string, + group.attrs?.title as string, datasources, - src, - ZARR_FORMAT.ICECHUNK + storePath, + ZARR_FORMAT.ICECHUNK, + groupPath ); } export async function indexFromZarr(src: string): Promise { - if (ZarrDataManager.isIcechunkStorePath(src)) { + if (isIcechunkStorePath(src)) { return indexFromIcechunk(src); } try { diff --git a/src/lib/data/variableDecoding.ts b/src/lib/data/variableDecoding.ts index 2fa92c1f..ecf13b52 100644 --- a/src/lib/data/variableDecoding.ts +++ b/src/lib/data/variableDecoding.ts @@ -184,24 +184,7 @@ export function decodeVariableDataAndGetBounds( /** * Gridlook cannot handle Float64 and integer types in textures, so cast to Float32 */ -export function castDataVarToFloat32( - rawData: - | unknown[] - | Int8Array - | Int16Array - | Int32Array - | BigInt64Array - | Uint8Array - | Uint16Array - | Uint32Array - | BigUint64Array - | Float32Array - | Float64Array - | zarr.BoolArray - | zarr.UnicodeStringArray - | zarr.ByteStringArray - | zarr.Chunk -) { +export function castDataVarToFloat32(rawData: zarr.TypedArray) { if (rawData instanceof Float32Array) { return rawData; } diff --git a/src/lib/shaders/glsl/pointFalloff.frag.glsl b/src/lib/shaders/glsl/pointFalloff.frag.glsl index ff6ecf66..550a1afc 100644 --- a/src/lib/shaders/glsl/pointFalloff.frag.glsl +++ b/src/lib/shaders/glsl/pointFalloff.frag.glsl @@ -8,6 +8,7 @@ uniform float scaleFactor; uniform int colormap; uniform float posterizeLevels; uniform float hideBelowValue; +uniform float hideAboveValue; void main() { vec2 uv = gl_PointCoord * 2.0 - 1.0; @@ -16,7 +17,7 @@ void main() { float falloff = exp(-r2 * 2.0); if (falloff < 0.01) discard; - if (is_nan(v_value) || v_value <= hideBelowValue) { + if (is_nan(v_value) || v_value <= hideBelowValue || v_value >= hideAboveValue) { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); return; } diff --git a/src/lib/shaders/glsl/scalarColormap.frag.glsl b/src/lib/shaders/glsl/scalarColormap.frag.glsl index 06650e29..64b1c972 100644 --- a/src/lib/shaders/glsl/scalarColormap.frag.glsl +++ b/src/lib/shaders/glsl/scalarColormap.frag.glsl @@ -9,6 +9,7 @@ uniform float scaleFactor; uniform int colormap; uniform float posterizeLevels; uniform float hideBelowValue; +uniform float hideAboveValue; uniform int projectionType; uniform float projectionRadius; uniform int edgeQuality; @@ -19,7 +20,8 @@ void main() { if ( (edgeQuality > 0 && !isInsideProjectionDomain(vProjectedXY, projectionType, projectionRadius)) || is_nan(v_value) || - v_value <= hideBelowValue + v_value <= hideBelowValue || + v_value >= hideAboveValue ) { discard; } diff --git a/src/lib/shaders/glsl/textureColormap.frag.glsl b/src/lib/shaders/glsl/textureColormap.frag.glsl index d523a3ad..130b61c9 100644 --- a/src/lib/shaders/glsl/textureColormap.frag.glsl +++ b/src/lib/shaders/glsl/textureColormap.frag.glsl @@ -8,6 +8,7 @@ uniform float scaleFactor; uniform int colormap; uniform float posterizeLevels; uniform float hideBelowValue; +uniform float hideAboveValue; uniform sampler2D data; uniform int projectionType; uniform float projectionRadius; @@ -19,7 +20,7 @@ varying vec2 vProjectedXY; void main() { float v_value = texture(data, vUv).r; if ((edgeQuality > 0 && !isInsideProjectionDomain(vProjectedXY, projectionType, projectionRadius)) - || is_nan(v_value) || v_value <= hideBelowValue) { + || is_nan(v_value) || v_value <= hideBelowValue || v_value >= hideAboveValue) { discard; } gl_FragColor.a = 1.0; diff --git a/src/lib/shaders/gridShaders.ts b/src/lib/shaders/gridShaders.ts index 867d7e34..40897c1c 100644 --- a/src/lib/shaders/gridShaders.ts +++ b/src/lib/shaders/gridShaders.ts @@ -87,6 +87,7 @@ export function makeGpuProjectedTextureMaterial( colormap: { value: availableColormaps[colormap] }, posterizeLevels: { value: 0.0 }, hideBelowValue: { value: -1e38 }, + hideAboveValue: { value: 1e38 }, data: { value: texture }, // Projection uniforms projectionType: { @@ -129,6 +130,7 @@ export function makeGpuProjectedMeshMaterial( colormap: { value: availableColormaps[colormap] }, posterizeLevels: { value: 0.0 }, hideBelowValue: { value: -1e38 }, + hideAboveValue: { value: 1e38 }, // Projection uniforms projectionType: { value: PROJECTION_TYPE_BY_MODE[PROJECTION_TYPES.NEARSIDE_PERSPECTIVE], @@ -181,6 +183,7 @@ export function makeGpuProjectedPointMaterial( maxPointSize: { value: 10.0 }, posterizeLevels: { value: 0.0 }, hideBelowValue: { value: -1e38 }, + hideAboveValue: { value: 1e38 }, colormap: { value: availableColormaps[colormap] }, // Projection uniforms projectionType: { diff --git a/src/lib/types/GlobeTypes.ts b/src/lib/types/GlobeTypes.ts index cf9c6f53..7f369612 100644 --- a/src/lib/types/GlobeTypes.ts +++ b/src/lib/types/GlobeTypes.ts @@ -43,6 +43,12 @@ export type TVarInfo = { attrs: zarr.Attributes; }; +export type TZarrDggsMetadata = { + name: string; + refinement_level: number; + coordinate: string | null; +}; + export type TDataSource = { store: string; dataset: string; diff --git a/src/store/paramStore.ts b/src/store/paramStore.ts index 62a89636..b322d0f9 100644 --- a/src/store/paramStore.ts +++ b/src/store/paramStore.ts @@ -20,6 +20,7 @@ export const useUrlParameterStore = defineStore("urlParams", { paramInvertColormap: undefined as string | undefined, paramPosterizeLevels: undefined as string | undefined, paramHideLowerBound: undefined as string | undefined, + paramHideUpperBound: undefined as string | undefined, paramDistractionFree: undefined as string | undefined, paramMaskMode: undefined as string | undefined, paramMaskingUseTexture: undefined as string | undefined, @@ -64,6 +65,7 @@ export const STORE_PARAM_MAPPING = { invertcolormap: "paramInvertColormap", posterizelevels: "paramPosterizeLevels", hidelowerbound: "paramHideLowerBound", + hideupperbound: "paramHideUpperBound", distractionFree: "paramDistractionFree", maskmode: "paramMaskMode", maskusetexture: "paramMaskingUseTexture", diff --git a/src/store/store.ts b/src/store/store.ts index e382fbda..cb4b1325 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -52,6 +52,7 @@ export const useGlobeControlStore = defineStore("globeControl", { invertColormap: false, posterizeLevels: 0 as number, hideLowerBound: false, + hideUpperBound: false, userBoundsLow: undefined as number | undefined, userBoundsHigh: undefined as number | undefined, dimSlidersValues: [] as (number | null)[], diff --git a/src/store/useUrlSync.ts b/src/store/useUrlSync.ts index 9be3e248..38218456 100644 --- a/src/store/useUrlSync.ts +++ b/src/store/useUrlSync.ts @@ -41,6 +41,11 @@ const GLOBE_URL_SYNC_MAP: TUrlSyncEntry[] = [ param: URL_PARAMETERS.HIDE_LOWER_BOUND, transform: String, }, + { + key: "hideUpperBound", + param: URL_PARAMETERS.HIDE_UPPER_BOUND, + transform: String, + }, { key: "landSeaMaskChoice", param: URL_PARAMETERS.MASK_MODE }, { key: "landSeaMaskUseTexture", diff --git a/src/ui/grids/Curvilinear.vue b/src/ui/grids/Curvilinear.vue index 3fa650ef..848fbed4 100755 --- a/src/ui/grids/Curvilinear.vue +++ b/src/ui/grids/Curvilinear.vue @@ -11,7 +11,12 @@ import { import { useGridDataLoader } from "./composables/useGridDataLoader.ts"; import { useSharedGridLogic } from "./composables/useSharedGridLogic.ts"; -import { getLatLonData } from "@/lib/data/coordinateVariables.ts"; +import { + getLatLonData, + getProjectedXYLonLatData, + isProjectedXName, + isProjectedYName, +} from "@/lib/data/coordinateVariables.ts"; import { buildDimensionRangesAndIndices } from "@/lib/data/dimensionHandling.ts"; import { castDataVarToFloat32, @@ -106,19 +111,42 @@ const { datasourceUpdate } = useGridDataLoader({ const BATCH_SIZE = 30; +async function getCurvilinearCoordinates( + datavar: zarr.Array, + dimensionNames: string[] +) { + try { + return await getLatLonData( + varnameSelector.value, + datavar, + props.datasources + ); + } catch (error) { + if (hasTrailingProjectedXYDimensions(dimensionNames)) { + return await getProjectedXYLonLatData( + varnameSelector.value, + datavar, + props.datasources, + dimensionNames + ); + } + throw error; + } +} + async function getGrid( datavar: zarr.Array, - data: Float32Array + data: Float32Array, + dimensionNames: string[] ) { - const { latitudes, longitudes } = await getLatLonData( - varnameSelector.value, + const { latitudes, longitudes } = await getCurvilinearCoordinates( datavar, - props.datasources + dimensionNames ); const isMissingOrFill = createMissingOrFillPredicate(datavar); - const latitudesData = latitudes.data as Float64Array; - const longitudesData = longitudes!.data as Float64Array; + const latitudesData = latitudes.data as Float32Array; + const longitudesData = longitudes!.data as Float32Array; const [nj, ni] = latitudes.shape; // Detect cell orientation by analyzing the winding order of grid cells @@ -151,9 +179,18 @@ async function getGrid( }; } +function hasTrailingProjectedXYDimensions(dimensionNames: string[]) { + if (dimensionNames.length < 2) { + return false; + } + const lastDim = dimensionNames[dimensionNames.length - 1]; + const secondLastDim = dimensionNames[dimensionNames.length - 2]; + return isProjectedXName(lastDim) && isProjectedYName(secondLastDim); +} + function detectLongitudeFlip( - longitudes: Float64Array, - latitudes: Float64Array, + longitudes: Float32Array, + latitudes: Float32Array, isMissingOrFill: (value: number) => boolean, nj: number, ni: number @@ -207,7 +244,7 @@ function detectLongitudeFlip( } function detectColumnPeriodicity( - longitudes: Float64Array, + longitudes: Float32Array, nj: number, ni: number ): boolean { @@ -309,8 +346,8 @@ function getBoundaryPoint( fromColumn: number, toColumn: number, ni: number, - latitudes: Float64Array, - longitudes: Float64Array + latitudes: Float32Array, + longitudes: Float32Array ) { return getCellCenter( latitudes, @@ -327,8 +364,8 @@ function getRowMidpoint( fromColumn: number, toColumn: number, ni: number, - latitudes: Float64Array, - longitudes: Float64Array + latitudes: Float32Array, + longitudes: Float32Array ) { return getCellCenter( latitudes, @@ -425,8 +462,8 @@ function getCenteredCellCorners( i: number, ni: number, flipLongitude: boolean, - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, isPeriodicI: boolean ) { const iPrevious = getPreviousColumnIndex(i, ni, flipLongitude); @@ -586,8 +623,8 @@ function fillCellPositionAndData( } function buildBatchGeometryData( - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, data: Float32Array, jStart: number, jEnd: number, @@ -636,8 +673,8 @@ function buildBatchGeometryData( } function buildCurvilinearGeometry( - latitudes: Float64Array, // 2D array flattened: lat values at each (j,i) grid point - longitudes: Float64Array, // 2D array flattened: lon values at each (j,i) grid point + latitudes: Float32Array, // 2D array flattened: lat values at each (j,i) grid point + longitudes: Float32Array, // 2D array flattened: lon values at each (j,i) grid point data: Float32Array, // 2D array flattened: data values at each (j,i) grid point nj: number, // Number of rows in the grid (j dimension) ni: number, // Number of columns in the grid (i dimension) @@ -706,8 +743,8 @@ function getCircularMeanLongitude( } function getCellCenter( - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, idx00: number, idx01: number, idx10: number, @@ -730,8 +767,8 @@ function getCellCenter( function buildCurvilinearHoverSamples( rawData: Float32Array, - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, nj: number, ni: number, flipLongitude: boolean @@ -755,8 +792,8 @@ function buildCurvilinearHoverSamples( function setHoverData( rawData: Float32Array, - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, nj: number, ni: number, flipLongitude: boolean, @@ -782,11 +819,12 @@ function setHoverData( async function renderGridAndHover( datavar: zarr.Array, rawData: Float32Array, + dimensionNames: string[], fillValue: number, missingValue: number ) { const { latitudesData, longitudesData, nj, ni, shouldFlipLongitude } = - await getGrid(datavar, rawData); + await getGrid(datavar, rawData, dimensionNames); setHoverData( rawData, latitudesData, @@ -825,7 +863,13 @@ async function fetchAndRenderData( rawData ); - await renderGridAndHover(datavar, rawData, fillValue, missingValue); + await renderGridAndHover( + datavar, + rawData, + dimensionNames, + fillValue, + missingValue + ); const dimInfo = await getDimensionValues(dimensionRanges, indices); diff --git a/src/ui/grids/Healpix.vue b/src/ui/grids/Healpix.vue index aa6450a8..fa107721 100644 --- a/src/ui/grids/Healpix.vue +++ b/src/ui/grids/Healpix.vue @@ -33,7 +33,11 @@ import { makeGpuProjectedTextureMaterial, updateProjectionUniforms, } from "@/lib/shaders/gridShaders.ts"; -import type { TDimensionRange, TSources } from "@/lib/types/GlobeTypes.ts"; +import type { + TDimensionRange, + TSources, + TZarrDggsMetadata, +} from "@/lib/types/GlobeTypes.ts"; import { useUrlParameterStore } from "@/store/paramStore.ts"; import { HOVERED_GRID_POINT_STATUS, @@ -162,16 +166,46 @@ function fetchGrid() { } async function getNside() { - const crs = await ZarrDataManager.getCRSInfo( - props.datasources!, - varnameSelector.value - ); - // FIXME: could probably have other names - const nside = crs.attrs["healpix_nside"] as number; - return nside; + try { + const crs = await ZarrDataManager.getCRSInfo( + props.datasources!, + varnameSelector.value + ); + + return crs.attrs["healpix_nside"] as number; + // FIXME: could probably have other names + } catch (error) { + const group = await ZarrDataManager.getParentGroup( + props.datasources!, + varnameSelector.value + ); + const metadata = (group.attrs?.dggs as TZarrDggsMetadata) ?? {}; + if ("refinement_level" in metadata) { + const refinementLevel = (metadata.refinement_level ?? 0) as number; + return Math.pow(2, refinementLevel); + } + + throw error; + } } async function getCells() { + let cellCoord = "cell"; + try { + const group = await ZarrDataManager.getParentGroup( + props.datasources!, + varnameSelector.value + ); + const metadata = (group.attrs["dggs"] as TZarrDggsMetadata) ?? {}; + + const coordinate = metadata["coordinate"]; + if (coordinate) { + cellCoord = coordinate; + } + } catch { + // no dggs metadata found, continue with the default cell coordinate + } + try { const rawCells = ( await ZarrDataManager.getVariableData( @@ -179,7 +213,7 @@ async function getCells() { props.datasources!, varnameSelector.value ), - ZarrDataManager.resolveVariablePath(varnameSelector.value, "cell") + ZarrDataManager.resolveVariablePath(varnameSelector.value, cellCoord) ) ).data as ArrayLike; diff --git a/src/ui/grids/Regular.vue b/src/ui/grids/Regular.vue index 31bcd67f..a89a266a 100644 --- a/src/ui/grids/Regular.vue +++ b/src/ui/grids/Regular.vue @@ -18,8 +18,7 @@ import { isLongitudeName, isProjectedXName, isProjectedYName, - isWebMercatorCRS, - webMercatorToLonLat, + projectedAxisCoordinatesToLonLat, } from "@/lib/data/coordinateVariables.ts"; import { downsampleDataTexture } from "@/lib/data/dataTexture.ts"; import { buildDimensionRangesAndIndices } from "@/lib/data/dimensionHandling.ts"; @@ -83,8 +82,8 @@ const { const { setHoverLookupFromIndex, clearHoverLookup } = useGridHoverLookup(hoveredGeoPoint); -const longitudes = ref(new Float64Array()); -const latitudes = ref(new Float64Array()); +const longitudes = ref(new Float32Array()); +const latitudes = ref(new Float32Array()); const BATCH_SIZE = 60; const MAX_GEO_RESOLUTION = 512; @@ -135,17 +134,13 @@ async function fetchProjectedXYDims( ), ]); const crsWkt = await getCRSWkt(props.datasources!, varnameSelector.value); - if (crsWkt && isWebMercatorCRS(crsWkt)) { - const converted = webMercatorToLonLat( - new Float64Array(xData.data as Float64Array), - new Float64Array(yData.data as Float64Array) - ); - longitudes.value = converted.longitudes; - latitudes.value = converted.latitudes; - } else { - longitudes.value = new Float64Array(xData.data as Float64Array); - latitudes.value = new Float64Array(yData.data as Float64Array); - } + const converted = projectedAxisCoordinatesToLonLat( + xData.data as Float32Array, + yData.data as Float32Array, + crsWkt + ); + longitudes.value = Float32Array.from(converted.longitudes); + latitudes.value = Float32Array.from(converted.latitudes); } async function getDims() { @@ -174,8 +169,8 @@ async function getDims() { grid, ZarrDataManager.resolveVariablePath(varnameSelector.value, lastDim) ); - latitudes.value = new Float64Array(latitudesData.data as Float64Array); - longitudes.value = Float64Array.from({ length: 360 }, (_, i) => i - 179.5); + latitudes.value = latitudesData.data as Float32Array; + longitudes.value = Float32Array.from({ length: 360 }, (_, i) => i - 179.5); } else { const latName = secondLastDim; const lonName = lastDim; @@ -189,10 +184,10 @@ async function getDims() { ZarrDataManager.resolveVariablePath(varnameSelector.value, lonName) ), ]); - const myLongitudes = longitudesData.data as Float64Array; - const myLatitudes = latitudesData.data as Float64Array; - longitudes.value = new Float64Array(new Set(myLongitudes)); - latitudes.value = new Float64Array(new Set(myLatitudes)); + const myLongitudes = longitudesData.data as Float32Array; + const myLatitudes = latitudesData.data as Float32Array; + longitudes.value = new Float32Array(new Set(myLongitudes)); + latitudes.value = new Float32Array(new Set(myLatitudes)); } } @@ -231,7 +226,7 @@ function rotatedToGeographic( return { lat, lon }; } -function isLongitudeGlobal(longitudes: Float64Array): boolean { +function isLongitudeGlobal(longitudes: Float32Array): boolean { const n = longitudes.length; if (n < 2) { return false; @@ -248,8 +243,8 @@ function isLongitudeGlobal(longitudes: Float64Array): boolean { } function generateBatchVerticesAndUVs( - latitudes: Float64Array, - longitudes: Float64Array, + latitudes: Float32Array, + longitudes: Float32Array, latOrigIndices: Int32Array, lonOrigIndices: Int32Array, originalLatCount: number, @@ -330,15 +325,15 @@ function generateGridIndices(latCount: number, lonCount: number) { return indices; } -function normalizeLongitudes(longitudes: Float64Array): Float64Array { +function normalizeLongitudes(longitudes: Float32Array): Float32Array { // Normalize longitudes to [0, 360) - return Float64Array.from(longitudes, (lon) => ((lon % 360) + 360) % 360); + return Float32Array.from(longitudes, (lon) => ((lon % 360) + 360) % 360); } function subsampleCoords( - values: Float64Array, + values: Float32Array, maxCount: number -): { coords: Float64Array; origIndices: Int32Array } { +): { coords: Float32Array; origIndices: Int32Array } { if (values.length <= maxCount) { const origIndices = new Int32Array(values.length); for (let i = 0; i < values.length; i++) { @@ -347,7 +342,7 @@ function subsampleCoords( return { coords: values, origIndices }; } - const coords = new Float64Array(maxCount); + const coords = new Float32Array(maxCount); const origIndices = new Int32Array(maxCount); for (let i = 0; i < maxCount; i++) { const sourceIdx = Math.round((i * (values.length - 1)) / (maxCount - 1)); @@ -366,7 +361,7 @@ async function getRegularGridParameters() { const isLatReversed = latitudeValues[0] > latitudeValues[latitudeValues.length - 1]; if (isLatReversed) { - latitudeValues = Float64Array.from(latitudeValues).reverse(); + latitudeValues = Float32Array.from(latitudeValues).reverse(); } const isGlobal = isLongitudeGlobal(longitudes.value); @@ -383,7 +378,7 @@ async function getRegularGridParameters() { let geoLongitudes = geoLongitudesBase; let lonOrigIndices = lonOrigIndicesBase; if (isGlobal) { - geoLongitudes = new Float64Array([ + geoLongitudes = new Float32Array([ ...geoLongitudesBase, geoLongitudesBase[0] + 360, ]); @@ -685,7 +680,7 @@ async function buildHoverSamples( }; } -function nearestIndex(sorted: Float64Array, target: number): number { +function nearestIndex(sorted: Float32Array, target: number): number { let lo = 0; let hi = sorted.length - 1; // Handle both ascending and descending arrays @@ -708,7 +703,7 @@ function nearestIndex(sorted: Float64Array, target: number): number { return lo; } -function nearestLonIndex(lons: Float64Array, target: number): number { +function nearestLonIndex(lons: Float32Array, target: number): number { // The lons array is monotonically sorted in its native range (either // [-180,180] or [0,360]). Search the raw values directly and handle // wrap by checking target, target+360, and target-360. diff --git a/src/ui/grids/composables/useSharedGridLogic.ts b/src/ui/grids/composables/useSharedGridLogic.ts index 076dd241..a2f0cf87 100644 --- a/src/ui/grids/composables/useSharedGridLogic.ts +++ b/src/ui/grids/composables/useSharedGridLogic.ts @@ -36,6 +36,7 @@ export function useSharedGridLogic() { invertColormap, posterizeLevels, hideLowerBound, + hideUpperBound, controlPanelVisible, projectionMode, projectionCenter, @@ -183,6 +184,11 @@ export function useSharedGridLogic() { ? low : -1e38; } + if (material.uniforms.hideAboveValue) { + material.uniforms.hideAboveValue.value = hideUpperBound.value + ? high + : 1e38; + } material.needsUpdate = true; } redraw(); @@ -195,6 +201,7 @@ export function useSharedGridLogic() { () => colormap.value, () => posterizeLevels.value, () => hideLowerBound.value, + () => hideUpperBound.value, ], () => { for (const cb of colormapChangeCallbacks) { diff --git a/src/ui/overlays/Controls.vue b/src/ui/overlays/Controls.vue index db8c387d..54b5bba0 100644 --- a/src/ui/overlays/Controls.vue +++ b/src/ui/overlays/Controls.vue @@ -75,6 +75,7 @@ const { paramInvertColormap, paramPosterizeLevels, paramHideLowerBound, + paramHideUpperBound, paramMaskMode, paramMaskingUseTexture, paramProjection, @@ -252,6 +253,9 @@ function initFromParams() { if (paramHideLowerBound.value === "true") { store.hideLowerBound = true; } + if (paramHideUpperBound.value === "true") { + store.hideUpperBound = true; + } if (paramMaskingUseTexture.value) { if (paramMaskingUseTexture.value === "false") { landSeaMaskUseTexture.value = false; @@ -329,7 +333,7 @@ defineExpose({