Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 6-liste-deroulante-avec-barre-recherche
  • 7-radio-bouton
  • 72-import-d-images-trop-lourdes
  • 8-logo
  • WhiSp00n/RadioButton
  • WhiSp00n/ReglagesdeuxpointsZeros
  • achraf/ResultsPage
  • celeste/classif
  • celeste/imagelourde
  • celeste/inference
  • celeste/inference2
  • gh-pages
  • gwenn/dbschema
  • gwenn/deleteandsplit
  • gwenn/dropzone
  • gwenn/feur
  • gwenn/feur2
  • gwenn/fix-_components
  • gwenn/images2observations
  • gwenn/pglite
  • gwenn/previewsidepanel
  • gwenn/protocolexport
  • gwenn/select-observations
  • gwenn/settings
  • gwenn/setupdb
  • gwenn/toasts
  • gwenn/tooltips
  • ines/darkMode
  • infeurence
  • main
  • olivier/Classifeurcation
  • olivier/buttonPrimary
  • olivier/darkTheme
  • renovate/eslint-config-prettier-10.x-lockfile
34 results

Target

Select target project
  • cigale/cigale.pages.inpt.fr
1 result
Select Git revision
  • 6-liste-deroulante-avec-barre-recherche
  • 7-radio-bouton
  • 72-import-d-images-trop-lourdes
  • 8-logo
  • WhiSp00n/RadioButton
  • WhiSp00n/ReglagesdeuxpointsZeros
  • achraf/ResultsPage
  • celeste/classif
  • celeste/imagelourde
  • celeste/inference
  • celeste/inference2
  • gh-pages
  • gwenn/dbschema
  • gwenn/deleteandsplit
  • gwenn/dropzone
  • gwenn/feur
  • gwenn/feur2
  • gwenn/fix-_components
  • gwenn/images2observations
  • gwenn/pglite
  • gwenn/previewsidepanel
  • gwenn/protocolexport
  • gwenn/select-observations
  • gwenn/settings
  • gwenn/setupdb
  • gwenn/toasts
  • gwenn/tooltips
  • ines/darkMode
  • infeurence
  • main
  • olivier/Classifeurcation
  • olivier/buttonPrimary
  • olivier/darkTheme
  • renovate/eslint-config-prettier-10.x-lockfile
34 results
Show changes

Commits on Source 63

......@@ -16,6 +16,7 @@
"date-fns": "^4.1.0",
"dragselect": "^3.1.1",
"fuse.js": "^7.1.0",
"idb": "^8.0.2",
"sveltejs-tippy": "^3.0.0",
"tinykeys": "^3.0.0",
"unplugin-icons": "^22.0.0"
......@@ -85,13 +86,14 @@
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
"integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
......@@ -101,13 +103,14 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
"integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
......@@ -117,13 +120,14 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
"integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
......@@ -133,13 +137,14 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
"integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
......@@ -149,13 +154,14 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
"integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
......@@ -165,13 +171,14 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
"integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
......@@ -181,13 +188,14 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
"integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
......@@ -197,13 +205,14 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
"integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
......@@ -213,13 +222,14 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
"integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -229,13 +239,14 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
"integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -245,13 +256,14 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
"integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -261,13 +273,14 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
"integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -277,13 +290,14 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
"integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -293,13 +307,14 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
"integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -309,13 +324,14 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
"integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -325,13 +341,14 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
"integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -341,13 +358,14 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
"integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
......@@ -357,13 +375,14 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
"integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
......@@ -373,13 +392,14 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
"integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
......@@ -389,13 +409,14 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
"integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
......@@ -405,13 +426,14 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
"integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
......@@ -421,13 +443,14 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
"integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
......@@ -437,13 +460,14 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
"integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
......@@ -453,13 +477,14 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
"integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
......@@ -469,13 +494,14 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
"integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
......@@ -524,10 +550,11 @@
}
},
"node_modules/@eslint/compat": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.6.tgz",
"integrity": "sha512-k7HNCqApoDHM6XzT30zGoETj+D+uUcZUb+IVAJmar3u6bvHf7hhHJcWx09QHj4/a2qrKZMWU0E16tvkiAdv06Q==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.7.tgz",
"integrity": "sha512-xvv7hJE32yhegJ8xNAnb62ggiAwTYHBpUCWhRxEj/ksvgDJuSXfoDkBcRYaYNFiJ+jH0IE3K16hd+xXzhBgNbg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
......@@ -555,10 +582,11 @@
}
},
"node_modules/@eslint/core": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
"integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
......@@ -567,10 +595,11 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
"integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
"integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
......@@ -602,9 +631,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.20.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz",
"integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==",
"version": "9.21.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
"dev": true,
"license": "MIT",
"engines": {
......@@ -621,12 +650,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
"integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.10.0",
"@eslint/core": "^0.12.0",
"levn": "^0.4.1"
},
"engines": {
......@@ -682,10 +712,11 @@
}
},
"node_modules/@humanwhocodes/retry": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz",
"integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==",
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
"integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
......@@ -1112,6 +1143,16 @@
"win32"
]
},
"node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
"integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==",
"devOptional": true,
"license": "MIT",
"peerDependencies": {
"acorn": "^8.9.0"
}
},
"node_modules/@sveltejs/adapter-static": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.8.tgz",
......@@ -1122,9 +1163,9 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "2.17.2",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.17.2.tgz",
"integrity": "sha512-Vypk02baf7qd3SOB1uUwUC/3Oka+srPo2J0a8YN3EfJypRshDkNx9HzNKjSmhOnGWwT+SSO06+N0mAb8iVTmTQ==",
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.18.0.tgz",
"integrity": "sha512-4DGCGiwNzgnPJySlMe/Qi6rKMK3ntphJaV95BTW+aggaTIAVZ5x3Bp+LURVLMxAEAtWAI5U449NafVxTS+kXbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
......@@ -1461,15 +1502,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-typescript": {
"version": "1.4.13",
"resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
"integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
"devOptional": true,
"peerDependencies": {
"acorn": ">=8.9.0"
}
},
"node_modules/agent-base": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
......@@ -2482,11 +2514,12 @@
}
},
"node_modules/esbuild": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
"integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
......@@ -2494,31 +2527,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.24.2",
"@esbuild/android-arm": "0.24.2",
"@esbuild/android-arm64": "0.24.2",
"@esbuild/android-x64": "0.24.2",
"@esbuild/darwin-arm64": "0.24.2",
"@esbuild/darwin-x64": "0.24.2",
"@esbuild/freebsd-arm64": "0.24.2",
"@esbuild/freebsd-x64": "0.24.2",
"@esbuild/linux-arm": "0.24.2",
"@esbuild/linux-arm64": "0.24.2",
"@esbuild/linux-ia32": "0.24.2",
"@esbuild/linux-loong64": "0.24.2",
"@esbuild/linux-mips64el": "0.24.2",
"@esbuild/linux-ppc64": "0.24.2",
"@esbuild/linux-riscv64": "0.24.2",
"@esbuild/linux-s390x": "0.24.2",
"@esbuild/linux-x64": "0.24.2",
"@esbuild/netbsd-arm64": "0.24.2",
"@esbuild/netbsd-x64": "0.24.2",
"@esbuild/openbsd-arm64": "0.24.2",
"@esbuild/openbsd-x64": "0.24.2",
"@esbuild/sunos-x64": "0.24.2",
"@esbuild/win32-arm64": "0.24.2",
"@esbuild/win32-ia32": "0.24.2",
"@esbuild/win32-x64": "0.24.2"
"@esbuild/aix-ppc64": "0.25.0",
"@esbuild/android-arm": "0.25.0",
"@esbuild/android-arm64": "0.25.0",
"@esbuild/android-x64": "0.25.0",
"@esbuild/darwin-arm64": "0.25.0",
"@esbuild/darwin-x64": "0.25.0",
"@esbuild/freebsd-arm64": "0.25.0",
"@esbuild/freebsd-x64": "0.25.0",
"@esbuild/linux-arm": "0.25.0",
"@esbuild/linux-arm64": "0.25.0",
"@esbuild/linux-ia32": "0.25.0",
"@esbuild/linux-loong64": "0.25.0",
"@esbuild/linux-mips64el": "0.25.0",
"@esbuild/linux-ppc64": "0.25.0",
"@esbuild/linux-riscv64": "0.25.0",
"@esbuild/linux-s390x": "0.25.0",
"@esbuild/linux-x64": "0.25.0",
"@esbuild/netbsd-arm64": "0.25.0",
"@esbuild/netbsd-x64": "0.25.0",
"@esbuild/openbsd-arm64": "0.25.0",
"@esbuild/openbsd-x64": "0.25.0",
"@esbuild/sunos-x64": "0.25.0",
"@esbuild/win32-arm64": "0.25.0",
"@esbuild/win32-ia32": "0.25.0",
"@esbuild/win32-x64": "0.25.0"
}
},
"node_modules/escalade": {
......@@ -2578,22 +2611,22 @@
}
},
"node_modules/eslint": {
"version": "9.20.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
"integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
"version": "9.21.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.11.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.20.0",
"@eslint/plugin-kit": "^0.2.5",
"@eslint/config-array": "^0.19.2",
"@eslint/core": "^0.12.0",
"@eslint/eslintrc": "^3.3.0",
"@eslint/js": "9.21.0",
"@eslint/plugin-kit": "^0.2.7",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1",
"@humanwhocodes/retry": "^0.4.2",
"@types/estree": "^1.0.6",
"@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
......@@ -2654,10 +2687,11 @@
}
},
"node_modules/eslint-config-prettier": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz",
"integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==",
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.2.tgz",
"integrity": "sha512-1105/17ZIMjmCOJOPNfVdbXafLCLj3hPmkmB7dLgt7XsQ/zkxSuDerE/xgO3RxoHysR1N1whmquY0lSn2O0VLg==",
"dev": true,
"license": "MIT",
"bin": {
"eslint-config-prettier": "build/bin/cli.js"
},
......@@ -2727,19 +2761,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/@eslint/core": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz",
"integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/esm-env": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
......@@ -3340,6 +3361,12 @@
"node": ">=0.10.0"
}
},
"node_modules/idb": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/idb/-/idb-8.0.2.tgz",
"integrity": "sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==",
"license": "ISC"
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
......@@ -4332,9 +4359,9 @@
}
},
"node_modules/merge-drivers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/merge-drivers/-/merge-drivers-1.0.2.tgz",
"integrity": "sha512-4LWDWNHz00gnrJAnP1OD6BsetqEVPFJDzYZECLeakwc9ojQ0h+eMq5Jo838LWxJrKa/Ml7UhH1o5HUy6FqPkjw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-drivers/-/merge-drivers-1.0.3.tgz",
"integrity": "sha512-tbtyyEJyupcgtvGphM3MDdL30mjybI65z6bq31Wnm82Ums6BZdJN216MbwkbvAXPpC1CbmTNDeixVYgg9XaUVw==",
"dev": true,
"license": "MIT",
"dependencies": {
......@@ -5155,9 +5182,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
......@@ -5173,6 +5200,7 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
......@@ -5298,9 +5326,9 @@
}
},
"node_modules/prettier": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
"integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true,
"license": "MIT",
"bin": {
......@@ -5950,17 +5978,17 @@
}
},
"node_modules/svelte": {
"version": "5.20.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.20.2.tgz",
"integrity": "sha512-aYXJreNUiyTob0QOzRZeBXZMGeFZDch6SrSRV8QTncZb6zj0O3BEdUzPpojuHQ1pTvk+KX7I6rZCXPUf8pTPxA==",
"version": "5.22.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.22.1.tgz",
"integrity": "sha512-b9DQGnfrZc+km4u3j6qkEY87pYe23yfgBT03CkeBlYST+Wzij7ut1o0BSoQ+UmiyAO1nPh9DMJJCoGDdUOrunw==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0",
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/estree": "^1.0.5",
"acorn": "^8.12.1",
"acorn-typescript": "^1.4.13",
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"clsx": "^2.1.1",
......@@ -6131,10 +6159,11 @@
}
},
"node_modules/typescript": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"version": "5.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
......@@ -6315,14 +6344,14 @@
}
},
"node_modules/vite": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.1.0.tgz",
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.24.2",
"postcss": "^8.5.1",
"esbuild": "^0.25.0",
"postcss": "^8.5.3",
"rollup": "^4.30.1"
},
"bin": {
......
......@@ -54,6 +54,7 @@
"arktype": "^2.0.4",
"date-fns": "^4.1.0",
"fuse.js": "^7.1.0",
"idb": "^8.0.2",
"sveltejs-tippy": "^3.0.0",
"tinykeys": "^3.0.0",
"unplugin-icons": "^22.0.0"
......
......@@ -11,7 +11,10 @@ const ID = type(/[\w_]+/).pipe((id) => id.toLowerCase());
const Probability = type('0 <= number <= 1');
const MetadataValue = type({
value: 'string.json.parse',
value: type('string.json.parse').pipe(
(primitive) =>
/** @type {import('./metadata').RuntimeValue<typeof MetadataType.infer>} */ (primitive)
),
confidence: Probability.default(1),
alternatives: {
'[string.json]': Probability
......@@ -131,9 +134,9 @@ const Protocol = table(
);
const Settings = table(
'layer',
'id',
type({
layer: '"defaults" | "user"',
id: '"defaults" | "user"',
protocols: ID.array(),
theme: type.enumerated('dark', 'light', 'auto'),
gridSize: 'number',
......
import { openDB } from 'idb';
import { nanoid } from 'nanoid';
import { Tables } from './database';
/** @type {Array<keyof typeof Tables>} */
// @ts-ignore
const tableNames = Object.keys(Tables);
/** @type {{[Table in keyof typeof Tables]: Array<typeof Tables[Table]['infer']>}} */
const tableValues = $state({
Image: [],
Metadata: [],
Observation: [],
Protocol: [],
Settings: []
});
/**
*
* @type {{
* [Name in keyof typeof Tables]: ReturnType<typeof wrangler<Name>>
* } & {
* initialize: () => Promise<void>
* }}
*/
// @ts-ignore
export const tables = {
...Object.fromEntries(tableNames.map((name) => [name, wrangler(name)])),
async initialize() {
await Promise.allSettled(tableNames.map((name) => tables[name].list()));
}
};
/**
*
* @param {Table} table
* @template {keyof typeof Tables} Table
*/
function wrangler(table) {
return {
get state() {
return tableValues[table];
},
/** @param {string} key */
get: async (key) => get(table, key),
/** @param {typeof Tables[Table]['inferIn']} value */
async set(value) {
await set(table, value);
const output = Tables[table].assert(value);
const index = this.state.findIndex((item) => item.id === value.id);
if (index !== -1) tableValues[table][index] = output;
else tableValues[table].push(output);
},
/** @param {Omit<typeof Tables[Table]['inferIn'], 'id'>} value */
async add(value) {
return this.set(
// @ts-ignore
{ ...value, id: `${table}_${nanoid()}` }
);
},
list: async () => list(table),
all: () => iterator(table),
/** @param {string} index */
by: (index) => iterator(table, index),
/** Do not go through validation or type morphing, manipulate the underlying database values directly. Useful for performance reasons, when changing only a property inside of an object and leaving the others unchanged, for example */
raw: {
/** @param {typeof Tables[Table]['inferIn']} value */
async set(value) {
const db = await openDatabase();
return await db.put(table, value);
},
/** @param {string} key */
async get(key) {
const db = await openDatabase();
return await db.get(table, key);
}
}
};
}
/**
*
* @param {TableName} tableName
* @param {typeof Tables[TableName]['inferIn']} value
* @template {keyof typeof Tables} TableName
*/
export async function set(tableName, value) {
console.time(`set ${tableName} ${value.id}`);
const db = await openDatabase();
const validator = Tables[tableName];
validator.assert(value);
return await db.put(tableName, value).then((result) => {
console.timeEnd(`set ${tableName} ${value.id}`);
return result;
});
}
/**
*
* @param {TableName} tableName
* @param {string} key
* @returns {Promise<undefined | typeof Tables[TableName]['infer']>}
* @template {keyof typeof Tables} TableName
*/
export async function get(tableName, key) {
console.time(`get ${tableName} ${key}`);
const db = await openDatabase();
const validator = Tables[tableName];
return await db.get(tableName, key).then((value) => {
const out = value ? validator.assert(value) : undefined;
console.timeEnd(`get ${tableName} ${key}`);
return out;
});
}
/**
*
* @param {TableName} tableName
* @returns {Promise<Array<typeof Tables[TableName]['infer']>>}
* @template {keyof typeof Tables} TableName
*/
export async function list(tableName) {
const db = await openDatabase();
const validator = Tables[tableName];
// @ts-ignore
return await db.getAll(tableName).then((values) => values.map(validator.assert));
}
/**
*
* @param {TableName} tableName
* @param {string} [index]
* @returns {AsyncGenerator<typeof Tables[TableName]['infer'], void, unknown>}
* @template {keyof typeof Tables} TableName
*/
export async function* iterator(tableName, index = undefined) {
const db = await openDatabase();
const validator = Tables[tableName];
const store = db.transaction(tableName).store;
const iter = index ? store.index(index).iterate() : store.iterate();
for await (const cursor of iter) {
yield validator.assert(cursor.value);
}
}
export async function openDatabase() {
if (_database) return _database;
/** @type {Array<{[K in keyof typeof Tables]: [K, typeof Tables[K]]}[keyof typeof Tables]>} */
// @ts-ignore
const tablesByName = Object.entries(Tables);
_database = await openDB('database', 1, {
upgrade(db) {
for (const [tableName, schema] of tablesByName) {
if (!schema.meta.table) continue;
const keyPath = schema.meta.table.indexes[0];
const store = db.createObjectStore(tableName, { keyPath });
for (const index of schema.meta.table.indexes.slice(1)) {
store.createIndex(index, index);
}
}
}
});
return _database;
}
// Magie vodoo Typescript, pas besoin de comprendre
// Si t'es curieuxse, demande à Gwenn qui sera ravie
// de t'expliquer :3
/**
* @type {import('idb').IDBPDatabase<{
* [Name in keyof typeof Tables]: {
* value: (typeof Tables[Name])['inferIn']
* key: string,
* indexes: {
* [IndexName in string]: string;
* }
* }
* }> | undefined}
*/
let _database;
import { tables } from './idb';
/**
*
* @param {object} options
* @param {string} options.subjectId id de l'image ou l'observation
* @param {string} options.metadataId id de la métadonnée
* @param {RuntimeValue<import('./database').MetadataType>} options.value la valeur de la métadonnée
* @param {number} [options.confidence=1] la confiance dans la valeur (proba que ce soit la bonne valeur)
* @param {Array<{ value: RuntimeValue<import('./database').MetadataType>; confidence: number }>} [options.alternatives=[]] les autres valeurs possibles
*/
export async function storeMetadataValue({
subjectId,
metadataId,
value,
confidence,
alternatives
}) {
alternatives ??= [];
confidence ??= 1;
const newValue = {
value: JSON.stringify(value),
confidence,
alternatives: Object.fromEntries(
alternatives.map((alternative) => [JSON.stringify(alternative.value), alternative.confidence])
)
};
const image = await tables.Image.raw.get(subjectId);
const observation = await tables.Observation.raw.get(subjectId);
if (image) {
image.metadata[metadataId] = newValue;
await tables.Image.raw.set(image);
} else if (observation) {
observation.metadataOverrides[metadataId] = newValue;
await tables.Observation.raw.set(observation);
} else {
throw new Error(`Aucune image ou observation avec l'ID ${subjectId}`);
}
}
/**
* Gets all metadata for an observation, including metadata derived from merging the metadata values of the images that make up the observation.
* @param {import('./database').Observation} observation
* @returns {Promise<import('./database').MetadataValues>}
*/
export async function observationMetadata(observation) {
// TODO use a transaction instead
const images = await Promise.all(observation.images.map(tables.Image.get)).then(
/**
* @template V
* @param {V[]} images
* @returns {NonNullable<V>[]}
*/
// @ts-ignore
(images) => images.filter(Boolean)
);
const metadataFromImages = await mergeMetadataValues(images);
return {
...metadataFromImages,
...observation.metadataOverrides
};
}
/**
*
* @param {import("./database").Image[]} images
* @returns {Promise<import("./database").MetadataValues>}
*/
export async function mergeMetadataValues(images) {
/** @type {import("./database").MetadataValues} */
const output = {};
const keys = new Set(...images.map((image) => Object.keys(image.metadata)));
for (const key of keys) {
const definition = await tables.Metadata.get(key);
if (!definition) {
console.warn(`Cannot merge metadata values for unknown key ${key}`);
continue;
}
output[key] = mergeMetadata(
definition,
images.flatMap((img) =>
Object.entries(img.metadata)
.filter(([k]) => k === key)
.map(([, v]) => v)
)
);
}
return output;
}
/**
*
* @param {import("./database").Metadata} definition
* @param {import("./database").MetadataValue[]} values
*/
function mergeMetadata(definition, values) {
/**
* @param {(probabilities: number[]) => number} merger
* @param {import('./database').MetadataValue[]} values
* Run merger on array of confidences for every probability of each alternative of each values:
* example: [ { alternatives: { a: 0.8, b: 0.2 } }, { alternatives: { a: 0.6, b: 0.4 } } ]
* turns into: { a: merger([0.8, 0.6]), b: merger([0.2, 0.4]) }
*/
const mergeAlternatives = (merger, values) =>
Object.fromEntries(
values
.flatMap((v) => Object.keys(v.alternatives))
.map((valueAsString) => [
valueAsString,
merger(values.flatMap((v) => v.alternatives[valueAsString] ?? null).filter(Boolean))
])
);
switch (definition.mergeMethod) {
case 'average':
return {
value: mergeAverage(
definition.type,
// @ŧs-ignore
values.map((v) => v.value)
),
confidence: avg(values.map((v) => v.confidence)),
alternatives: mergeAlternatives(avg, values)
};
case 'max':
// return mergeMajority(definition, values);
throw new Error('Pas encore implémenté!');
case 'min':
// return mergeMinority(definition, values);
throw new Error('Pas encore implémenté!');
case 'median':
return {
value: mergeMedian(
definition.type,
values.map((v) => v.value)
),
confidence: median(values.map((v) => v.confidence)),
alternatives: mergeAlternatives(median, values)
};
case 'none':
return {
// TODO use null instead
value: '',
confidence: 0,
alternatives: {}
};
}
}
/** @param {number[]} values */
function avg(values) {
return values.reduce((acc, cur) => acc + cur, 0) / values.length;
}
/**
* Merge values by average.
* @param {Type} type
* @param {Value[]} values
* @returns {Value}
* @template {RuntimeValue<Type>} Value
* @template {import('./database').MetadataType} Type
*/
function mergeAverage(type, values) {
/**
* @param {typeof values} values
*/
const average = (values) => avg(toNumber(type, values));
// @ts-ignore
if (type === 'boolean') return average(values) > 0.5;
// @ts-ignore
if (type === 'integer') return Math.ceil(average(values));
// @ts-ignore
if (type === 'float') return average(values);
// @ts-ignore
if (type === 'date') return new Date(average(values));
if (type === 'location') {
// @ts-ignore
return {
latitude: average(
values.map(
(v) =>
// @ts-ignore
v.latitude
)
),
longitude: average(
values.map(
(
v //@ts-ignore
) => v.longitude
)
)
};
}
throw new Error(`Impossible de fusionner en mode moyenne des valeurs de type ${type}`);
}
/** @param {number[]} values */
const median = (values) => {
const sorted = values.sort((a, b) => a - b);
const middle = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[middle - 1] + sorted[middle]) / 2;
}
return sorted[middle];
};
/**
* Merge values by median.
* @param {Type} type
* @param {Value[]} values
* @returns {Value}
* @template {RuntimeValue<Type>} Value
* @template {import('./database').MetadataType} Type
*/
function mergeMedian(type, values) {
/** @param {typeof values} values */
const median_ = (values) => median(toNumber(type, values));
// @ts-ignore
if (type === 'boolean') return median_(values) > 0.5;
// @ts-ignore
if (type === 'integer') return Math.ceil(median_(values));
// @ts-ignore
if (type === 'float') return median_(values);
// @ts-ignore
if (type === 'date') return new Date(median_(values));
if (type === 'location') {
// @ts-ignore
return {
latitude: median(
values.map(
(v) =>
// @ts-ignore
v.latitude
)
),
longitude: median(
values.map(
(v) =>
// @ts-ignore
v.longitude
)
)
};
}
throw new Error(`Impossible de fusionner en mode médiane des valeurs de type ${type}`);
}
/**
* Convert series of values to an output number
* @param {Type} type
* @param {Value[]} values
* @template {RuntimeValue<Type>} Value
* @template {import('./database').MetadataType} Type
* @returns {number[]}
*/
function toNumber(type, values) {
// @ts-ignore
if (type === 'integer') return values;
// @ts-ignore
if (type === 'float') return values;
if (type === 'boolean') return values.map((v) => (v ? 1 : 0));
if (type === 'date') return values.map((v) => new Date(/** @type {Date|string} */ (v)).getTime());
throw new Error(`Impossible de convertir des valeurs de type ${type} en nombre`);
}
/**
* @template {import('./database').MetadataType} Type
* @typedef {Type extends 'boolean' ? boolean : Type extends 'integer' ? number : Type extends 'float' ? number : Type extends 'enum' ? string : Type extends 'date' ? Date : Type extends 'location' ? { latitude: number, longitude: number } : string} RuntimeValue
*/
import { tables } from './idb.svelte.js';
/** @type {import('./database.js').Settings} */
// @ts-expect-error could be undefined too, but not useful for us
const _settings = $derived(
tables.Settings.state.find((s) => s.id === 'user') ??
tables.Settings.state.find((s) => s.id === 'defaults')
);
/**
* Usage:
* ```svelte
* <script>
* // $derived is important, otherwise the value will not update
* const settings = $derived(getSettings());
* </script>
* ```
* @returns {import('./database.js').Settings} a reactive object that will update when the database changes. Read-only. Use `setSetting` to change values.
*/
export function getSettings() {
return _settings;
}
/**
*
* @param {Key} key
* @param {import("./database.js").Settings[Key]} value
* @template {keyof import("./database.js").Settings} Key
*/
export async function setSetting(key, value) {
const current = (await tables.Settings.get('user')) ?? (await tables.Settings.get('defaults'));
if (!current) {
throw new Error("Les réglages par défaut n'ont pas été initialisés. Rechargez la page.");
}
return tables.Settings.set({
...current,
id: 'user',
[key]: value
});
}
/**
*
* @param {Key} key
* @template {keyof import("./database.js").Settings} Key
*/
export async function getSetting(key) {
const out =
_settings[key] ??
(await tables.Settings.get('user')) ??
(await tables.Settings.get('defaults'));
if (!out) {
throw new Error("Les réglages par défaut n'ont pas été initialisés. Rechargez la page.");
}
return out;
}
import { tables } from './idb.svelte.js';
/**
*
* @param {string} id
*/
export async function defineSpeciesMetadata(id) {
const names = await fetch(
`https://git.inpt.fr/api/v4/projects/cigale%2Fapp/repository/files/models%2Fclass_mapping.txt/raw?lfs=true`
)
.then((res) => res.text())
.then((text) => text.split('\n'));
await tables.Metadata.set({
id,
description: "L'espèce de l'individu",
label: 'Espèce',
learnMore: null,
mergeMethod: 'max',
required: false,
type: 'enum',
options: names.filter(Boolean).map((name, i) => ({
key: i.toString(),
label: name,
description: '',
learnMore: null
}))
});
}
import { BUILTIN_METADATA } from '$lib/database.js';
import { tables } from '$lib/idb.svelte.js';
import { getSetting } from '$lib/settings.svelte.js';
import { defineSpeciesMetadata } from '$lib/species.js';
export async function load() {
await fillBuiltinData();
await defineSpeciesMetadata('species');
await tables.initialize();
return {
showInputHints: await getSetting('showInputHints')
};
}
async function fillBuiltinData() {
await Promise.allSettled([
...BUILTIN_METADATA.map(tables.Metadata.set),
tables.Settings.set({
id: 'defaults',
protocols: [],
theme: 'auto',
gridSize: 10,
language: 'fr',
showInputHints: true
})
]);
}
<script>
import { base } from '$app/paths';
import { setContext } from 'svelte';
import { toasts } from '$lib/toasts.svelte';
import Toast from '$lib/Toast.svelte';
import { toasts } from '$lib/toasts.svelte';
import { setContext } from 'svelte';
import './style.css';
import Navigation from './Navigation.svelte';
const { children } = $props();
const { children, data } = $props();
// TODO get value from DB
setContext('showSwitchHints', true);
setContext('showSwitchHints', data.showInputHints);
</script>
<Navigation hasImages={true}></Navigation>
<svelte:head>
<base href={base} />
<base href={base ? `${base}/index.html` : ''} />
</svelte:head>
<section class="toasts">
......