Live location tracking and playback for the game "manhunt"
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Change authority stuff, better tests

Ben C 07cfb7bb a8c0ea2f

+3143 -3057
+109 -90
backend/Cargo.lock
··· 13 13 14 14 [[package]] 15 15 name = "adler2" 16 - version = "2.0.0" 16 + version = "2.0.1" 17 17 source = "registry+https://github.com/rust-lang/crates.io-index" 18 - checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 18 + checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 19 20 20 [[package]] 21 21 name = "aho-corasick" ··· 157 157 dependencies = [ 158 158 "proc-macro2", 159 159 "quote", 160 - "syn 2.0.101", 160 + "syn 2.0.102", 161 161 ] 162 162 163 163 [[package]] ··· 192 192 dependencies = [ 193 193 "proc-macro2", 194 194 "quote", 195 - "syn 2.0.101", 195 + "syn 2.0.102", 196 196 ] 197 197 198 198 [[package]] ··· 335 335 336 336 [[package]] 337 337 name = "bumpalo" 338 - version = "3.17.0" 338 + version = "3.18.1" 339 339 source = "registry+https://github.com/rust-lang/crates.io-index" 340 - checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 340 + checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" 341 341 342 342 [[package]] 343 343 name = "bytemuck" 344 - version = "1.23.0" 344 + version = "1.23.1" 345 345 source = "registry+https://github.com/rust-lang/crates.io-index" 346 - checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" 346 + checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" 347 347 348 348 [[package]] 349 349 name = "byteorder" ··· 387 387 388 388 [[package]] 389 389 name = "camino" 390 - version = "1.1.9" 390 + version = "1.1.10" 391 391 source = "registry+https://github.com/rust-lang/crates.io-index" 392 - checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" 392 + checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" 393 393 dependencies = [ 394 394 "serde", 395 395 ] ··· 429 429 430 430 [[package]] 431 431 name = "cc" 432 - version = "1.2.25" 432 + version = "1.2.26" 433 433 source = "registry+https://github.com/rust-lang/crates.io-index" 434 - checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" 434 + checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" 435 435 dependencies = [ 436 436 "shlex", 437 437 ] ··· 465 465 466 466 [[package]] 467 467 name = "cfg-if" 468 - version = "1.0.0" 468 + version = "1.0.1" 469 469 source = "registry+https://github.com/rust-lang/crates.io-index" 470 - checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 470 + checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" 471 471 472 472 [[package]] 473 473 name = "cfg_aliases" ··· 632 632 checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" 633 633 dependencies = [ 634 634 "quote", 635 - "syn 2.0.101", 635 + "syn 2.0.102", 636 636 ] 637 637 638 638 [[package]] ··· 642 642 checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" 643 643 dependencies = [ 644 644 "quote", 645 - "syn 2.0.101", 645 + "syn 2.0.102", 646 646 ] 647 647 648 648 [[package]] ··· 666 666 "proc-macro2", 667 667 "quote", 668 668 "strsim", 669 - "syn 2.0.101", 669 + "syn 2.0.102", 670 670 ] 671 671 672 672 [[package]] ··· 677 677 dependencies = [ 678 678 "darling_core", 679 679 "quote", 680 - "syn 2.0.101", 680 + "syn 2.0.102", 681 681 ] 682 682 683 683 [[package]] ··· 700 700 "proc-macro2", 701 701 "quote", 702 702 "rustc_version", 703 - "syn 2.0.101", 703 + "syn 2.0.102", 704 704 ] 705 705 706 706 [[package]] ··· 758 758 dependencies = [ 759 759 "proc-macro2", 760 760 "quote", 761 - "syn 2.0.101", 761 + "syn 2.0.102", 762 762 ] 763 763 764 764 [[package]] ··· 781 781 dependencies = [ 782 782 "proc-macro2", 783 783 "quote", 784 - "syn 2.0.101", 784 + "syn 2.0.102", 785 785 ] 786 786 787 787 [[package]] ··· 848 848 849 849 [[package]] 850 850 name = "enumflags2" 851 - version = "0.7.11" 851 + version = "0.7.12" 852 852 source = "registry+https://github.com/rust-lang/crates.io-index" 853 - checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" 853 + checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" 854 854 dependencies = [ 855 855 "enumflags2_derive", 856 856 "serde", ··· 858 858 859 859 [[package]] 860 860 name = "enumflags2_derive" 861 - version = "0.7.11" 861 + version = "0.7.12" 862 862 source = "registry+https://github.com/rust-lang/crates.io-index" 863 - checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" 863 + checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" 864 864 dependencies = [ 865 865 "proc-macro2", 866 866 "quote", 867 - "syn 2.0.101", 867 + "syn 2.0.102", 868 868 ] 869 869 870 870 [[package]] ··· 941 941 942 942 [[package]] 943 943 name = "flate2" 944 - version = "1.1.1" 944 + version = "1.1.2" 945 945 source = "registry+https://github.com/rust-lang/crates.io-index" 946 - checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" 946 + checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" 947 947 dependencies = [ 948 948 "crc32fast", 949 949 "miniz_oxide", ··· 973 973 dependencies = [ 974 974 "proc-macro2", 975 975 "quote", 976 - "syn 2.0.101", 976 + "syn 2.0.102", 977 977 ] 978 978 979 979 [[package]] ··· 1002 1002 ] 1003 1003 1004 1004 [[package]] 1005 + name = "futures" 1006 + version = "0.3.31" 1007 + source = "registry+https://github.com/rust-lang/crates.io-index" 1008 + checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 1009 + dependencies = [ 1010 + "futures-channel", 1011 + "futures-core", 1012 + "futures-executor", 1013 + "futures-io", 1014 + "futures-sink", 1015 + "futures-task", 1016 + "futures-util", 1017 + ] 1018 + 1019 + [[package]] 1005 1020 name = "futures-channel" 1006 1021 version = "0.3.31" 1007 1022 source = "registry+https://github.com/rust-lang/crates.io-index" 1008 1023 checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 1009 1024 dependencies = [ 1010 1025 "futures-core", 1026 + "futures-sink", 1011 1027 ] 1012 1028 1013 1029 [[package]] ··· 1054 1070 dependencies = [ 1055 1071 "proc-macro2", 1056 1072 "quote", 1057 - "syn 2.0.101", 1073 + "syn 2.0.102", 1058 1074 ] 1059 1075 1060 1076 [[package]] ··· 1075 1091 source = "registry+https://github.com/rust-lang/crates.io-index" 1076 1092 checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 1077 1093 dependencies = [ 1094 + "futures-channel", 1078 1095 "futures-core", 1079 1096 "futures-io", 1080 1097 "futures-macro", ··· 1310 1327 "proc-macro-error", 1311 1328 "proc-macro2", 1312 1329 "quote", 1313 - "syn 2.0.101", 1330 + "syn 2.0.102", 1314 1331 ] 1315 1332 1316 1333 [[package]] ··· 1389 1406 "proc-macro-error", 1390 1407 "proc-macro2", 1391 1408 "quote", 1392 - "syn 2.0.101", 1409 + "syn 2.0.102", 1393 1410 ] 1394 1411 1395 1412 [[package]] ··· 1400 1417 1401 1418 [[package]] 1402 1419 name = "hashbrown" 1403 - version = "0.15.3" 1420 + version = "0.15.4" 1404 1421 source = "registry+https://github.com/rust-lang/crates.io-index" 1405 - checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 1422 + checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" 1406 1423 1407 1424 [[package]] 1408 1425 name = "heck" ··· 1503 1520 1504 1521 [[package]] 1505 1522 name = "hyper-util" 1506 - version = "0.1.13" 1523 + version = "0.1.14" 1507 1524 source = "registry+https://github.com/rust-lang/crates.io-index" 1508 - checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" 1525 + checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" 1509 1526 dependencies = [ 1510 1527 "base64 0.22.1", 1511 1528 "bytes", ··· 1690 1707 checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 1691 1708 dependencies = [ 1692 1709 "equivalent", 1693 - "hashbrown 0.15.3", 1710 + "hashbrown 0.15.4", 1694 1711 "serde", 1695 1712 ] 1696 1713 ··· 1946 1963 version = "0.1.0" 1947 1964 dependencies = [ 1948 1965 "chrono", 1966 + "futures", 1949 1967 "rand 0.9.1", 1968 + "rand_chacha 0.9.0", 1950 1969 "serde", 1951 1970 "serde_json", 1952 1971 "tauri", ··· 1999 2018 2000 2019 [[package]] 2001 2020 name = "miniz_oxide" 2002 - version = "0.8.8" 2021 + version = "0.8.9" 2003 2022 source = "registry+https://github.com/rust-lang/crates.io-index" 2004 - checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 2023 + checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 2005 2024 dependencies = [ 2006 2025 "adler2", 2007 2026 "simd-adler32", ··· 2127 2146 "proc-macro-crate 3.3.0", 2128 2147 "proc-macro2", 2129 2148 "quote", 2130 - "syn 2.0.101", 2149 + "syn 2.0.102", 2131 2150 ] 2132 2151 2133 2152 [[package]] ··· 2557 2576 "phf_shared 0.11.3", 2558 2577 "proc-macro2", 2559 2578 "quote", 2560 - "syn 2.0.101", 2579 + "syn 2.0.102", 2561 2580 ] 2562 2581 2563 2582 [[package]] ··· 2712 2731 source = "registry+https://github.com/rust-lang/crates.io-index" 2713 2732 checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" 2714 2733 dependencies = [ 2715 - "toml_edit 0.22.26", 2734 + "toml_edit 0.22.27", 2716 2735 ] 2717 2736 2718 2737 [[package]] ··· 2983 3002 2984 3003 [[package]] 2985 3004 name = "rustc-demangle" 2986 - version = "0.1.24" 3005 + version = "0.1.25" 2987 3006 source = "registry+https://github.com/rust-lang/crates.io-index" 2988 - checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 3007 + checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" 2989 3008 2990 3009 [[package]] 2991 3010 name = "rustc_version" ··· 3054 3073 "proc-macro2", 3055 3074 "quote", 3056 3075 "serde_derive_internals", 3057 - "syn 2.0.101", 3076 + "syn 2.0.102", 3058 3077 ] 3059 3078 3060 3079 [[package]] ··· 3120 3139 dependencies = [ 3121 3140 "proc-macro2", 3122 3141 "quote", 3123 - "syn 2.0.101", 3142 + "syn 2.0.102", 3124 3143 ] 3125 3144 3126 3145 [[package]] ··· 3131 3150 dependencies = [ 3132 3151 "proc-macro2", 3133 3152 "quote", 3134 - "syn 2.0.101", 3153 + "syn 2.0.102", 3135 3154 ] 3136 3155 3137 3156 [[package]] ··· 3154 3173 dependencies = [ 3155 3174 "proc-macro2", 3156 3175 "quote", 3157 - "syn 2.0.101", 3176 + "syn 2.0.102", 3158 3177 ] 3159 3178 3160 3179 [[package]] 3161 3180 name = "serde_spanned" 3162 - version = "0.6.8" 3181 + version = "0.6.9" 3163 3182 source = "registry+https://github.com/rust-lang/crates.io-index" 3164 - checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 3183 + checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" 3165 3184 dependencies = [ 3166 3185 "serde", 3167 3186 ] ··· 3205 3224 "darling", 3206 3225 "proc-macro2", 3207 3226 "quote", 3208 - "syn 2.0.101", 3227 + "syn 2.0.102", 3209 3228 ] 3210 3229 3211 3230 [[package]] ··· 3295 3314 3296 3315 [[package]] 3297 3316 name = "smallvec" 3298 - version = "1.15.0" 3317 + version = "1.15.1" 3299 3318 source = "registry+https://github.com/rust-lang/crates.io-index" 3300 - checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 3319 + checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 3301 3320 3302 3321 [[package]] 3303 3322 name = "socket2" ··· 3424 3443 3425 3444 [[package]] 3426 3445 name = "syn" 3427 - version = "2.0.101" 3446 + version = "2.0.102" 3428 3447 source = "registry+https://github.com/rust-lang/crates.io-index" 3429 - checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 3448 + checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" 3430 3449 dependencies = [ 3431 3450 "proc-macro2", 3432 3451 "quote", ··· 3450 3469 dependencies = [ 3451 3470 "proc-macro2", 3452 3471 "quote", 3453 - "syn 2.0.101", 3472 + "syn 2.0.102", 3454 3473 ] 3455 3474 3456 3475 [[package]] ··· 3513 3532 dependencies = [ 3514 3533 "proc-macro2", 3515 3534 "quote", 3516 - "syn 2.0.101", 3535 + "syn 2.0.102", 3517 3536 ] 3518 3537 3519 3538 [[package]] ··· 3613 3632 "serde", 3614 3633 "serde_json", 3615 3634 "sha2", 3616 - "syn 2.0.101", 3635 + "syn 2.0.102", 3617 3636 "tauri-utils", 3618 3637 "thiserror 2.0.12", 3619 3638 "time", ··· 3631 3650 "heck 0.5.0", 3632 3651 "proc-macro2", 3633 3652 "quote", 3634 - "syn 2.0.101", 3653 + "syn 2.0.102", 3635 3654 "tauri-codegen", 3636 3655 "tauri-utils", 3637 3656 ] ··· 3843 3862 dependencies = [ 3844 3863 "proc-macro2", 3845 3864 "quote", 3846 - "syn 2.0.101", 3865 + "syn 2.0.102", 3847 3866 ] 3848 3867 3849 3868 [[package]] ··· 3854 3873 dependencies = [ 3855 3874 "proc-macro2", 3856 3875 "quote", 3857 - "syn 2.0.101", 3876 + "syn 2.0.102", 3858 3877 ] 3859 3878 3860 3879 [[package]] ··· 3922 3941 dependencies = [ 3923 3942 "proc-macro2", 3924 3943 "quote", 3925 - "syn 2.0.101", 3944 + "syn 2.0.102", 3926 3945 ] 3927 3946 3928 3947 [[package]] ··· 3940 3959 3941 3960 [[package]] 3942 3961 name = "toml" 3943 - version = "0.8.22" 3962 + version = "0.8.23" 3944 3963 source = "registry+https://github.com/rust-lang/crates.io-index" 3945 - checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" 3964 + checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" 3946 3965 dependencies = [ 3947 3966 "serde", 3948 3967 "serde_spanned", 3949 3968 "toml_datetime", 3950 - "toml_edit 0.22.26", 3969 + "toml_edit 0.22.27", 3951 3970 ] 3952 3971 3953 3972 [[package]] 3954 3973 name = "toml_datetime" 3955 - version = "0.6.9" 3974 + version = "0.6.11" 3956 3975 source = "registry+https://github.com/rust-lang/crates.io-index" 3957 - checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" 3976 + checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 3958 3977 dependencies = [ 3959 3978 "serde", 3960 3979 ] ··· 3983 4002 3984 4003 [[package]] 3985 4004 name = "toml_edit" 3986 - version = "0.22.26" 4005 + version = "0.22.27" 3987 4006 source = "registry+https://github.com/rust-lang/crates.io-index" 3988 - checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" 4007 + checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 3989 4008 dependencies = [ 3990 4009 "indexmap 2.9.0", 3991 4010 "serde", ··· 3997 4016 3998 4017 [[package]] 3999 4018 name = "toml_write" 4000 - version = "0.1.1" 4019 + version = "0.1.2" 4001 4020 source = "registry+https://github.com/rust-lang/crates.io-index" 4002 - checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" 4021 + checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" 4003 4022 4004 4023 [[package]] 4005 4024 name = "tower" ··· 4018 4037 4019 4038 [[package]] 4020 4039 name = "tower-http" 4021 - version = "0.6.5" 4040 + version = "0.6.6" 4022 4041 source = "registry+https://github.com/rust-lang/crates.io-index" 4023 - checksum = "5cc2d9e086a412a451384326f521c8123a99a466b329941a9403696bff9b0da2" 4042 + checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" 4024 4043 dependencies = [ 4025 4044 "bitflags 2.9.1", 4026 4045 "bytes", ··· 4059 4078 4060 4079 [[package]] 4061 4080 name = "tracing-attributes" 4062 - version = "0.1.28" 4081 + version = "0.1.29" 4063 4082 source = "registry+https://github.com/rust-lang/crates.io-index" 4064 - checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 4083 + checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" 4065 4084 dependencies = [ 4066 4085 "proc-macro2", 4067 4086 "quote", 4068 - "syn 2.0.101", 4087 + "syn 2.0.102", 4069 4088 ] 4070 4089 4071 4090 [[package]] 4072 4091 name = "tracing-core" 4073 - version = "0.1.33" 4092 + version = "0.1.34" 4074 4093 source = "registry+https://github.com/rust-lang/crates.io-index" 4075 - checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 4094 + checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" 4076 4095 dependencies = [ 4077 4096 "once_cell", 4078 4097 ] ··· 4323 4342 "log", 4324 4343 "proc-macro2", 4325 4344 "quote", 4326 - "syn 2.0.101", 4345 + "syn 2.0.102", 4327 4346 "wasm-bindgen-shared", 4328 4347 ] 4329 4348 ··· 4358 4377 dependencies = [ 4359 4378 "proc-macro2", 4360 4379 "quote", 4361 - "syn 2.0.101", 4380 + "syn 2.0.102", 4362 4381 "wasm-bindgen-backend", 4363 4382 "wasm-bindgen-shared", 4364 4383 ] ··· 4461 4480 dependencies = [ 4462 4481 "proc-macro2", 4463 4482 "quote", 4464 - "syn 2.0.101", 4483 + "syn 2.0.102", 4465 4484 ] 4466 4485 4467 4486 [[package]] ··· 4575 4594 dependencies = [ 4576 4595 "proc-macro2", 4577 4596 "quote", 4578 - "syn 2.0.101", 4597 + "syn 2.0.102", 4579 4598 ] 4580 4599 4581 4600 [[package]] ··· 4586 4605 dependencies = [ 4587 4606 "proc-macro2", 4588 4607 "quote", 4589 - "syn 2.0.101", 4608 + "syn 2.0.102", 4590 4609 ] 4591 4610 4592 4611 [[package]] ··· 4917 4936 dependencies = [ 4918 4937 "proc-macro2", 4919 4938 "quote", 4920 - "syn 2.0.101", 4939 + "syn 2.0.102", 4921 4940 "synstructure", 4922 4941 ] 4923 4942 ··· 4963 4982 "proc-macro-crate 3.3.0", 4964 4983 "proc-macro2", 4965 4984 "quote", 4966 - "syn 2.0.101", 4985 + "syn 2.0.102", 4967 4986 "zbus_names", 4968 4987 "zvariant", 4969 4988 "zvariant_utils", ··· 4998 5017 dependencies = [ 4999 5018 "proc-macro2", 5000 5019 "quote", 5001 - "syn 2.0.101", 5020 + "syn 2.0.102", 5002 5021 ] 5003 5022 5004 5023 [[package]] ··· 5018 5037 dependencies = [ 5019 5038 "proc-macro2", 5020 5039 "quote", 5021 - "syn 2.0.101", 5040 + "syn 2.0.102", 5022 5041 "synstructure", 5023 5042 ] 5024 5043 ··· 5052 5071 dependencies = [ 5053 5072 "proc-macro2", 5054 5073 "quote", 5055 - "syn 2.0.101", 5074 + "syn 2.0.102", 5056 5075 ] 5057 5076 5058 5077 [[package]] ··· 5078 5097 "proc-macro-crate 3.3.0", 5079 5098 "proc-macro2", 5080 5099 "quote", 5081 - "syn 2.0.101", 5100 + "syn 2.0.102", 5082 5101 "zvariant_utils", 5083 5102 ] 5084 5103 ··· 5092 5111 "quote", 5093 5112 "serde", 5094 5113 "static_assertions", 5095 - "syn 2.0.101", 5114 + "syn 2.0.102", 5096 5115 "winnow 0.7.10", 5097 5116 ]
+6 -4
backend/Cargo.toml
··· 17 17 tauri-plugin-opener = "2" 18 18 serde = { version = "1", features = ["derive"] } 19 19 serde_json = "1" 20 - chrono = { version = "0.4.41", features = ["serde", "now"] } 21 - tokio = { version = "1.45.1", features = ["sync", "macros", "time"] } 22 - rand = { version = "0.9.1", features = ["thread_rng"] } 23 - tauri-plugin-geolocation = "2.2.4" 20 + chrono = { version = "0.4", features = ["serde", "now"] } 21 + tokio = { version = "1.45", features = ["sync", "macros", "time"] } 22 + rand = { version = "0.9", features = ["thread_rng"] } 23 + tauri-plugin-geolocation = "2.2" 24 + rand_chacha = "0.9.0" 25 + futures = "0.3.31"
-447
backend/src/game.rs
··· 1 - use std::{collections::HashMap, time::Duration}; 2 - use tauri::Runtime; 3 - use tokio::sync::RwLock; 4 - 5 - use crate::{ 6 - powerup::{PowerUpType, PowerUpUsage}, 7 - state::{GameEvent, GameState, Location, PlayerId, DT}, 8 - }; 9 - 10 - type EventMessage = (PlayerId, DT, GameEvent); 11 - 12 - /// Struct representing an ongoing game, handles communication with 13 - /// other clients via [Transport] and provides high-level methods for 14 - /// taking actions in the game. 15 - struct Game<L: LocationService, T: Transport> { 16 - id: PlayerId, 17 - is_host: bool, 18 - state: RwLock<GameState<L>>, 19 - transport: T, 20 - interval: Duration, 21 - } 22 - 23 - pub trait Transport { 24 - async fn receive_message(&self) -> Option<EventMessage>; 25 - async fn send_event_to(&self, id: PlayerId, event: GameEvent); 26 - async fn send_event_host(&self, event: GameEvent); 27 - async fn send_event_multiple(&self, ids: Vec<PlayerId>, event: GameEvent); 28 - async fn send_event_all(&self, event: GameEvent); 29 - } 30 - 31 - pub trait LocationService { 32 - fn get_loc(&self) -> Location; 33 - } 34 - 35 - impl<L: LocationService, T: Transport> Game<L, T> { 36 - pub fn new(id: PlayerId, game_state: GameState<L>, transport: T, interval: Duration) -> Self { 37 - Self { 38 - id, 39 - is_host: game_state.host.is_some(), 40 - state: RwLock::new(game_state), 41 - transport, 42 - interval, 43 - } 44 - } 45 - 46 - /// Mark yourself as caught, sends out a message to all other players 47 - async fn mark_caught(&self) { 48 - self.transport 49 - .send_event_all(GameEvent::HiderCaught(self.id)) 50 - .await; 51 - } 52 - 53 - /// Get the active powerup, to be called when the user is in range of the powerup 54 - async fn get_powerup(&self) { 55 - let mut state = self.state.write().await; 56 - if let Some(powerup) = state.public.available_powerup.take() { 57 - state.player.held_powerup = Some(powerup.typ); 58 - drop(state); 59 - self.transport 60 - .send_event_all(GameEvent::PowerUpDespawn) 61 - .await; 62 - } 63 - } 64 - 65 - async fn use_powerup(&self) { 66 - let mut state = self.state.write().await; 67 - if let Some(powerup) = state.player.held_powerup.take() { 68 - drop(state); 69 - match powerup { 70 - PowerUpType::PingSeeker => { 71 - let e = GameEvent::PowerUpActivate(PowerUpUsage::PingSeeker); 72 - self.transport.send_event_host(e).await; 73 - } 74 - PowerUpType::PingAllSeekers => { 75 - let e = GameEvent::PingReq(None); 76 - let state = self.state.read().await; 77 - let seekers = state.public.iter_seekers().collect::<Vec<_>>(); 78 - drop(state); 79 - let host_log = GameEvent::PowerUpActivate(PowerUpUsage::PingAllSeekers); 80 - self.transport.send_event_host(host_log).await; 81 - self.transport.send_event_multiple(seekers, e).await; 82 - } 83 - PowerUpType::ForcePingOther => { 84 - let e = GameEvent::PingReq(None); 85 - let mut state = self.state.write().await; 86 - if let Some(target) = state.random_other_hider() { 87 - let host_log = 88 - GameEvent::PowerUpActivate(PowerUpUsage::ForcePingOther(target)); 89 - self.transport.send_event_host(host_log).await; 90 - self.transport.send_event_to(target, e).await; 91 - } 92 - } 93 - } 94 - } 95 - } 96 - 97 - /// Start main loop of the game, this should ideally be put into its own thread via 98 - /// [tokio::spawn]. 99 - async fn main_loop( 100 - &self, 101 - ) -> ( 102 - HashMap<PlayerId, Vec<Location>>, 103 - Vec<(PlayerId, DT, GameEvent)>, 104 - ) { 105 - let interval = tokio::time::interval(self.interval); 106 - tokio::pin!(interval); 107 - 108 - let mut ended = false; 109 - 110 - while !ended { 111 - tokio::select! { 112 - _ = interval.tick() => { 113 - let mut state = self.state.write().await; 114 - let messages = state.tick(); 115 - drop(state); 116 - for (player, event) in messages { 117 - if let Some(player) = player { 118 - self.transport.send_event_to(player, event).await; 119 - } else { 120 - self.transport.send_event_all(event).await; 121 - } 122 - } 123 - } 124 - 125 - Some((player, time_sent, event)) = self.transport.receive_message() => { 126 - if let GameEvent::GameEnd(dt) = event { 127 - ended = true; 128 - 129 - } else { 130 - let mut state = self.state.write().await; 131 - let new_event = state.consume_event(time_sent, event, player); 132 - drop(state); 133 - if let Some(event) = new_event { 134 - self.transport.send_event_all(event).await; 135 - } 136 - } 137 - } 138 - } 139 - } 140 - 141 - let state = self.state.read().await; 142 - let locations = state.player.locations.clone(); 143 - 144 - if self.is_host { 145 - let player_count = state.public.caught_state.len(); 146 - let mut player_location_history = 147 - HashMap::<PlayerId, Vec<Location>>::with_capacity(player_count); 148 - player_location_history.insert(self.id, locations); 149 - while player_location_history.len() != player_count { 150 - // TODO: Join with a timeout, etc 151 - if let Some((id, _, GameEvent::PostGameSync(player_locations))) = 152 - self.transport.receive_message().await 153 - { 154 - player_location_history.insert(id, player_locations); 155 - } 156 - } 157 - let history = ( 158 - player_location_history, 159 - state.host.as_ref().unwrap().event_history.clone(), 160 - ); 161 - let ev = GameEvent::HostHistorySync(history.clone()); 162 - self.transport.send_event_all(ev).await; 163 - history 164 - } else { 165 - self.transport 166 - .send_event_host(GameEvent::PostGameSync(locations)) 167 - .await; 168 - loop { 169 - if let Some((_, _, GameEvent::HostHistorySync(history))) = 170 - self.transport.receive_message().await 171 - { 172 - break history; 173 - } 174 - } 175 - } 176 - } 177 - } 178 - 179 - #[cfg(test)] 180 - mod tests { 181 - use std::collections::HashMap; 182 - use std::sync::Arc; 183 - 184 - use crate::state::{GameSettings, HostState, PingStartCondition}; 185 - 186 - use super::*; 187 - use tokio::sync::mpsc::{Receiver, Sender}; 188 - use tokio::sync::Mutex; 189 - use tokio::task::yield_now; 190 - use tokio::test; 191 - 192 - type EventRx = Receiver<EventMessage>; 193 - type EventTx = Sender<EventMessage>; 194 - 195 - struct MockTransport { 196 - player_id: PlayerId, 197 - rx: Mutex<EventRx>, 198 - txs: HashMap<PlayerId, EventTx>, 199 - } 200 - 201 - impl MockTransport { 202 - fn new(player_id: PlayerId) -> (Self, EventTx) { 203 - let (tx, rx) = tokio::sync::mpsc::channel(5); 204 - let trans = Self { 205 - player_id, 206 - rx: Mutex::new(rx), 207 - txs: HashMap::new(), 208 - }; 209 - (trans, tx) 210 - } 211 - 212 - fn set_txs(&mut self, txs: HashMap<PlayerId, EventTx>) { 213 - self.txs = txs; 214 - } 215 - 216 - fn make_msg(&self, e: GameEvent) -> EventMessage { 217 - (self.player_id, chrono::Utc::now(), e) 218 - } 219 - } 220 - 221 - impl Transport for MockTransport { 222 - async fn receive_message(&self) -> Option<EventMessage> { 223 - let mut rx = self.rx.lock().await; 224 - rx.recv().await 225 - } 226 - 227 - async fn send_event_to(&self, id: PlayerId, event: GameEvent) { 228 - if let Some(tx) = self.txs.get(&id) { 229 - if let Err(why) = tx.send(self.make_msg(event)).await { 230 - eprintln!("Error sending msg to {id}: {why}"); 231 - } 232 - } 233 - } 234 - 235 - async fn send_event_host(&self, event: GameEvent) { 236 - // While testing, host is always player 0 237 - self.send_event_to(0, event).await; 238 - } 239 - 240 - async fn send_event_multiple(&self, ids: Vec<PlayerId>, event: GameEvent) { 241 - for id in ids { 242 - self.send_event_to(id, event.clone()).await; 243 - } 244 - } 245 - 246 - async fn send_event_all(&self, event: GameEvent) { 247 - for id in self.txs.keys() { 248 - self.send_event_to(*id, event.clone()).await; 249 - } 250 - } 251 - } 252 - 253 - struct MockLocation; 254 - 255 - impl LocationService for MockLocation { 256 - fn get_loc(&self) -> Location { 257 - Location { 258 - lat: 0.0, 259 - long: 0.0, 260 - heading: None, 261 - } 262 - } 263 - } 264 - 265 - type MockGame = Game<MockLocation, MockTransport>; 266 - 267 - struct TestMatch { 268 - games: HashMap<PlayerId, Arc<MockGame>>, 269 - } 270 - 271 - impl TestMatch { 272 - /// New test match 273 - /// player_count: number of players 274 - /// num_seekers: number of seekers 275 - /// host_seeker: whether to mark the host as a seeker 276 - pub fn new( 277 - player_count: u32, 278 - num_seekers: u32, 279 - host_seeker: bool, 280 - settings: GameSettings, 281 - ) -> Self { 282 - let caught_state = 283 - HashMap::<PlayerId, bool>::from_iter((0..player_count).into_iter().map(|id| { 284 - let should_seeker = 285 - (if id == 0 || host_seeker { id } else { id - 1 }) < num_seekers; 286 - (id, should_seeker && (host_seeker || id != 0)) 287 - })); 288 - 289 - let mut txs = HashMap::<PlayerId, EventTx>::with_capacity(player_count as usize); 290 - let mut games = HashMap::<PlayerId, MockGame>::with_capacity(player_count as usize); 291 - 292 - for id in 0..player_count { 293 - let (transport, tx) = MockTransport::new(id); 294 - let state = GameState::new( 295 - id == 0, 296 - id, 297 - caught_state.clone(), 298 - settings.clone(), 299 - MockLocation, 300 - ); 301 - txs.insert(id, tx); 302 - let game = MockGame::new(id, state, transport, Duration::from_secs(1)); 303 - games.insert(id, game); 304 - } 305 - 306 - for game in games.values_mut() { 307 - game.transport.set_txs(txs.clone()); 308 - } 309 - 310 - Self { 311 - games: games.into_iter().map(|(k, v)| (k, Arc::new(v))).collect(), 312 - } 313 - } 314 - 315 - pub fn start(&self) { 316 - for game in self.games.values() { 317 - let game = game.clone(); 318 - tokio::spawn(async move { game.main_loop().await }); 319 - } 320 - } 321 - 322 - pub fn host(&self) -> Arc<MockGame> { 323 - self.game(0) 324 - } 325 - 326 - pub fn game(&self, id: PlayerId) -> Arc<MockGame> { 327 - self.games.get(&id).unwrap().clone() 328 - } 329 - 330 - pub async fn wait_tick(&self) { 331 - tokio::time::sleep(Duration::from_secs(1)).await; 332 - yield_now().await; 333 - } 334 - 335 - pub async fn wait_assert_seekers_released(&self) { 336 - tokio::time::sleep(Duration::from_secs(1)).await; 337 - yield_now().await; 338 - 339 - self.assert_all_player_states(|state| { 340 - assert!(state.public.seekers_started.is_some()); 341 - }); 342 - } 343 - 344 - /// Assert a condition on the host state 345 - pub async fn assert_host_state<F: Fn(&HostState)>(&self, f: F) { 346 - let host = self.host(); 347 - let state = host.state.read().await; 348 - f(state.host.as_ref().unwrap()); 349 - } 350 - 351 - /// Assert a condition on all player states 352 - pub async fn assert_all_player_states<F: Fn(&GameState<MockLocation>)>(&self, f: F) { 353 - for game in self.games.values() { 354 - let state = game.state.read().await; 355 - f(&state); 356 - } 357 - } 358 - } 359 - 360 - const TEST_LOC: Location = Location { 361 - lat: 0.0, 362 - long: 0.0, 363 - heading: None, 364 - }; 365 - 366 - #[test] 367 - async fn test_game() { 368 - let settings = GameSettings { 369 - hiding_time_seconds: 1, 370 - ping_start: PingStartCondition::Players(3), 371 - ping_minutes_interval: 0, 372 - powerup_start: PingStartCondition::Players(3), 373 - powerup_chance: 0, 374 - powerup_minutes_cooldown: 1, 375 - powerup_locations: vec![TEST_LOC.clone()], 376 - }; 377 - 378 - // A test match with 5 players, player 0 (host) is a hider, players 1 and 2 are seekers. 379 - let test_match = TestMatch::new(5, 2, false, settings); 380 - 381 - let correct_caught_state = HashMap::<PlayerId, bool>::from_iter([ 382 - (0, false), 383 - (1, true), 384 - (2, true), 385 - (3, false), 386 - (4, false), 387 - ]); 388 - 389 - // Let's make sure our initial `caught_state` is correct 390 - test_match 391 - .assert_all_player_states(|s| assert_eq!(s.public.caught_state, correct_caught_state)) 392 - .await; 393 - 394 - test_match.start(); 395 - 396 - // Wait for seekers to be released, and then assert all player states properly reflect this 397 - test_match.wait_assert_seekers_released().await; 398 - 399 - test_match.wait_tick().await; 400 - 401 - // After a tick, all players should have at least one location in [PlayerState::locations] 402 - test_match 403 - .assert_all_player_states(|s| assert!(!s.player.locations.is_empty())) 404 - .await; 405 - 406 - // Now, let's see if we can mark player 3 as caught 407 - let player_3 = test_match.game(3); 408 - player_3.mark_caught().await; 409 - yield_now().await; 410 - 411 - // All states should be updated to reflect this 412 - test_match 413 - .assert_all_player_states(|s| { 414 - assert_eq!(s.public.caught_state.get(&3).copied(), Some(true)) 415 - }) 416 - .await; 417 - 418 - test_match.wait_tick().await; 419 - 420 - // And now, 3 players have been caught, meaning our [PingStartCondition] has been met, 421 - // let's check the host state to make sure it's starting to perform pings 422 - test_match 423 - .assert_host_state(|h| assert!(h.last_ping.is_some())) 424 - .await; 425 - 426 - test_match.wait_tick().await; 427 - 428 - // Value represents if the [Option] should be [Option::Some] 429 - let correct_pings = HashMap::<u32, bool>::from_iter([ 430 - (0, true), 431 - (1, false), 432 - (2, false), 433 - (3, false), 434 - (4, true), 435 - ]); 436 - 437 - // Now let's make sure the hiders are being pinged (3 was just caught, triggering pings. 438 - // Therefore, 3 should not be pinged) 439 - test_match 440 - .assert_all_player_states(|s| { 441 - for (k, v) in s.public.pings.iter() { 442 - assert_eq!(v.is_some(), correct_pings[k]); 443 - } 444 - }) 445 - .await; 446 - } 447 - }
+20
backend/src/game/events.rs
··· 1 + use serde::{Deserialize, Serialize}; 2 + 3 + use super::{location::Location, state::PlayerPing, PlayerId}; 4 + 5 + /// An event used between players to update state 6 + #[derive(Debug, Clone, Serialize, Deserialize)] 7 + pub enum GameEvent<Id: PlayerId> { 8 + /// A player has been caught and is now a seeker, contains the ID of the caught player 9 + PlayerCaught(Id), 10 + /// Public ping from a player revealing location 11 + Ping(PlayerPing<Id>), 12 + /// Force the player specified in `0` to ping, optionally display the ping as from the user 13 + /// specified in `1`. 14 + ForcePing(Id, Option<Id>), 15 + /// Force a powerup to despawn because a player got it, contains the player that got it. 16 + PowerupDespawn(Id), 17 + /// Contains location history of the given player, used after the game to sync location 18 + /// histories 19 + PostGameSync(Id, Vec<Location>), 20 + }
+19
backend/src/game/location.rs
··· 1 + use serde::{Deserialize, Serialize}; 2 + 3 + /// A "part" of a location 4 + pub type LocationComponent = f64; 5 + 6 + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] 7 + /// Some location in the world as gotten from a Geolocation API 8 + pub struct Location { 9 + /// Latitude 10 + pub lat: LocationComponent, 11 + /// Longitude 12 + pub long: LocationComponent, 13 + /// The bearing (float normalized from 0 to 1) optional as GPS can't always determine 14 + pub heading: Option<LocationComponent>, 15 + } 16 + 17 + pub trait LocationService { 18 + fn get_loc(&self) -> Location; 19 + }
+594
backend/src/game/mod.rs
··· 1 + use chrono::{DateTime, Utc}; 2 + use events::GameEvent; 3 + use powerups::PowerUpType; 4 + use settings::GameSettings; 5 + use std::{collections::HashMap, fmt::Debug, hash::Hash, time::Duration}; 6 + 7 + use tokio::{sync::RwLock, time::MissedTickBehavior}; 8 + 9 + mod events; 10 + mod location; 11 + mod powerups; 12 + mod settings; 13 + mod state; 14 + mod transport; 15 + 16 + use location::LocationService; 17 + use state::GameState; 18 + use transport::Transport; 19 + 20 + /// Type used to uniquely identify players in the game 21 + pub trait PlayerId: 22 + Debug + Hash + Ord + Eq + PartialEq + Send + Sync + Sized + Copy + Clone 23 + { 24 + } 25 + 26 + /// Convenence alias for UTC DT 27 + pub type UtcDT = DateTime<Utc>; 28 + 29 + /// Struct representing an ongoing game, handles communication with 30 + /// other clients via [Transport], gets location with [LocationService], and provides high-level methods for 31 + /// taking actions in the game. 32 + struct Game<Id: PlayerId, L: LocationService, T: Transport<Id>> { 33 + state: RwLock<GameState<Id>>, 34 + transport: T, 35 + location: L, 36 + interval: Duration, 37 + } 38 + 39 + impl<Id: PlayerId, L: LocationService, T: Transport<Id>> Game<Id, L, T> { 40 + pub fn new( 41 + my_id: Id, 42 + interval: Duration, 43 + random_seed: u64, 44 + initial_caught_state: HashMap<Id, bool>, 45 + settings: GameSettings, 46 + transport: T, 47 + location: L, 48 + ) -> Self { 49 + let state = GameState::<Id>::new(settings, my_id, random_seed, initial_caught_state); 50 + 51 + Self { 52 + transport, 53 + location, 54 + interval, 55 + state: RwLock::new(state), 56 + } 57 + } 58 + 59 + pub async fn mark_caught(&self) { 60 + let mut state = self.state.write().await; 61 + let id = state.id; 62 + state.mark_caught(id); 63 + state.remove_ping(id); 64 + // TODO: Maybe reroll for new powerups instead of just erasing it 65 + state.use_powerup(); 66 + 67 + self.transport 68 + .send_message(GameEvent::PlayerCaught(state.id)) 69 + .await; 70 + } 71 + 72 + pub async fn get_powerup(&self) { 73 + let mut state = self.state.write().await; 74 + state.get_powerup(); 75 + self.transport 76 + .send_message(GameEvent::PowerupDespawn(state.id)) 77 + .await; 78 + } 79 + 80 + pub async fn use_powerup(&self) { 81 + let mut state = self.state.write().await; 82 + 83 + if let Some(powerup) = state.use_powerup() { 84 + match powerup { 85 + PowerUpType::PingSeeker => {} 86 + PowerUpType::PingAllSeekers => { 87 + for seeker in state.iter_seekers() { 88 + self.transport 89 + .send_message(GameEvent::ForcePing(seeker, None)) 90 + .await; 91 + } 92 + } 93 + PowerUpType::ForcePingOther => { 94 + // Fallback to a seeker if there are no other hiders 95 + let target = state.random_other_hider().or_else(|| state.random_seeker()); 96 + 97 + if let Some(target) = target { 98 + self.transport 99 + .send_message(GameEvent::ForcePing(target, None)) 100 + .await; 101 + } 102 + } 103 + } 104 + } 105 + } 106 + 107 + async fn consume_event(&self, event: GameEvent<Id>) { 108 + let mut state = self.state.write().await; 109 + 110 + match event { 111 + GameEvent::Ping(player_ping) => state.add_ping(player_ping), 112 + GameEvent::ForcePing(target, display) => { 113 + if target != state.id { 114 + return; 115 + } 116 + 117 + let ping = if let Some(display) = display { 118 + state.create_ping(display) 119 + } else { 120 + state.create_self_ping() 121 + }; 122 + 123 + if let Some(ping) = ping { 124 + state.add_ping(ping.clone()); 125 + self.transport.send_message(GameEvent::Ping(ping)).await; 126 + } 127 + } 128 + GameEvent::PowerupDespawn(_) => state.despawn_powerup(), 129 + GameEvent::PlayerCaught(player) => { 130 + state.mark_caught(player); 131 + state.remove_ping(player); 132 + } 133 + GameEvent::PostGameSync(_, _locations) => {} 134 + } 135 + } 136 + 137 + /// Perform a tick for a specific moment in time 138 + async fn tick(&self, now: UtcDT) { 139 + let mut state = self.state.write().await; 140 + 141 + // Push to location history 142 + let location = self.location.get_loc(); 143 + state.push_loc(location); 144 + 145 + // Release Seekers? 146 + if !state.seekers_released() && state.should_release_seekers(now) { 147 + state.release_seekers(now); 148 + } 149 + 150 + // Start Pings? 151 + if !state.pings_started() && state.should_start_pings(now) { 152 + state.start_pings(now); 153 + } 154 + 155 + // Do a Ping? 156 + if state.should_ping(&now) { 157 + if let Some(&PowerUpType::PingSeeker) = state.peek_powerup() { 158 + // We have a powerup that lets us ping a seeker as us, use it. 159 + if let Some(seeker) = state.random_seeker() { 160 + state.use_powerup(); 161 + self.transport 162 + .send_message(GameEvent::ForcePing(seeker, Some(state.id))) 163 + .await; 164 + state.start_pings(now); 165 + } 166 + } else { 167 + // No powerup, normal ping 168 + if let Some(ping) = state.create_self_ping() { 169 + self.transport.send_message(GameEvent::Ping(ping)).await; 170 + state.start_pings(now); 171 + } 172 + } 173 + } 174 + 175 + // Start Powerup Rolls? 176 + if !state.powerups_started() && state.should_start_powerups(now) { 177 + state.start_powerups(now); 178 + } 179 + 180 + // Should roll for a powerup? 181 + if state.should_spawn_powerup(&now) { 182 + state.try_spawn_powerup(now); 183 + } 184 + } 185 + 186 + #[cfg(test)] 187 + pub async fn force_tick(&self, now: UtcDT) { 188 + self.tick(now).await; 189 + } 190 + 191 + /// Main loop of the game, handles ticking and receiving messages from [Transport]. 192 + pub async fn main_loop(&self) { 193 + let mut interval = tokio::time::interval(self.interval); 194 + 195 + interval.set_missed_tick_behavior(MissedTickBehavior::Delay); 196 + 197 + loop { 198 + tokio::select! { 199 + 200 + biased; 201 + 202 + Some(msg) = self.transport.receive_message() => { 203 + self.consume_event(msg).await; 204 + // TODO: Check all caught, end game 205 + } 206 + 207 + _ = interval.tick() => { 208 + let now = Utc::now(); 209 + self.tick(now).await; 210 + } 211 + }; 212 + } 213 + } 214 + } 215 + 216 + #[cfg(test)] 217 + mod tests { 218 + use std::{sync::Arc, u64}; 219 + 220 + use crate::game::{location::Location, settings::PingStartCondition}; 221 + 222 + use super::*; 223 + use tokio::{sync::Mutex, task::yield_now, test}; 224 + 225 + type GameEventRx = tokio::sync::mpsc::Receiver<GameEvent<u32>>; 226 + type GameEventTx = tokio::sync::mpsc::Sender<GameEvent<u32>>; 227 + 228 + impl PlayerId for u32 {} 229 + 230 + struct MockTransport { 231 + rx: Mutex<GameEventRx>, 232 + txs: Vec<GameEventTx>, 233 + } 234 + 235 + impl Transport<u32> for MockTransport { 236 + async fn receive_message(&self) -> Option<GameEvent<u32>> { 237 + let mut rx = self.rx.lock().await; 238 + rx.recv().await 239 + } 240 + 241 + async fn send_message(&self, msg: GameEvent<u32>) { 242 + for (id, tx) in self.txs.iter().enumerate() { 243 + tx.send(msg.clone()).await.expect("Failed to send msg"); 244 + } 245 + } 246 + } 247 + 248 + struct MockLocation; 249 + 250 + impl LocationService for MockLocation { 251 + fn get_loc(&self) -> location::Location { 252 + location::Location { 253 + lat: 0.0, 254 + long: 0.0, 255 + heading: None, 256 + } 257 + } 258 + } 259 + 260 + type TestGame = Game<u32, MockLocation, MockTransport>; 261 + 262 + struct MockMatch { 263 + games: HashMap<u32, Arc<TestGame>>, 264 + settings: GameSettings, 265 + mock_now: UtcDT, 266 + } 267 + 268 + const INTERVAL: Duration = Duration::from_secs(u64::MAX); 269 + 270 + impl MockMatch { 271 + pub fn new(settings: GameSettings, players: u32, seekers: u32) -> Self { 272 + let channels = (0..players) 273 + .into_iter() 274 + .map(|_| tokio::sync::mpsc::channel(10)) 275 + .collect::<Vec<_>>(); 276 + 277 + let initial_caught_state = (0..players) 278 + .into_iter() 279 + .map(|id| (id, id < seekers)) 280 + .collect::<HashMap<_, _>>(); 281 + let txs = channels 282 + .iter() 283 + .map(|(tx, _)| tx.clone()) 284 + .collect::<Vec<_>>(); 285 + 286 + let games = channels 287 + .into_iter() 288 + .enumerate() 289 + .map(|(id, (_, rx))| { 290 + let transport = MockTransport { 291 + rx: Mutex::new(rx), 292 + txs: txs.clone(), 293 + }; 294 + let location = MockLocation; 295 + let game = TestGame::new( 296 + id as u32, 297 + INTERVAL, 298 + 0, 299 + initial_caught_state.clone(), 300 + settings.clone(), 301 + transport, 302 + location, 303 + ); 304 + 305 + (id as u32, Arc::new(game)) 306 + }) 307 + .collect::<HashMap<_, _>>(); 308 + 309 + Self { 310 + settings, 311 + games, 312 + mock_now: Utc::now(), 313 + } 314 + } 315 + 316 + pub async fn start(&self) { 317 + for (id, game) in &self.games { 318 + let game = game.clone(); 319 + let id = *id; 320 + tokio::spawn(async move { 321 + game.main_loop().await; 322 + }); 323 + yield_now().await; 324 + } 325 + } 326 + 327 + pub async fn pass_time(&mut self, d: Duration) { 328 + self.mock_now += d; 329 + } 330 + 331 + pub async fn assert_all_states(&self, f: impl Fn(&GameState<u32>)) { 332 + for (_, game) in &self.games { 333 + let state = game.state.read().await; 334 + f(&state); 335 + } 336 + } 337 + 338 + pub fn game(&self, id: u32) -> &TestGame { 339 + self.games.get(&id).as_ref().unwrap() 340 + } 341 + 342 + pub async fn wait_for_seekers(&mut self) { 343 + let hiding_time = Duration::from_secs(self.settings.hiding_time_seconds as u64 + 1); 344 + self.mock_now += hiding_time; 345 + 346 + self.tick().await; 347 + 348 + self.assert_all_states(|s| { 349 + assert!(s.seekers_released()); 350 + }) 351 + .await; 352 + } 353 + 354 + async fn tick_all(&self, now: UtcDT) { 355 + for (_, game) in &self.games { 356 + game.force_tick(now).await; 357 + } 358 + } 359 + 360 + pub async fn tick(&self) { 361 + self.tick_all(self.mock_now).await; 362 + yield_now().await; 363 + } 364 + } 365 + 366 + fn mk_settings() -> GameSettings { 367 + GameSettings { 368 + hiding_time_seconds: 1, 369 + ping_start: PingStartCondition::Instant, 370 + ping_minutes_interval: 1, 371 + powerup_start: PingStartCondition::Instant, 372 + powerup_chance: 0, 373 + powerup_minutes_cooldown: 1, 374 + powerup_locations: vec![Location { 375 + lat: 0.0, 376 + long: 0.0, 377 + heading: None, 378 + }], 379 + } 380 + } 381 + 382 + #[test] 383 + async fn test_minimal_game() { 384 + let settings = mk_settings(); 385 + 386 + // 2 players, one is a seeker 387 + let mut mat = MockMatch::new(settings, 2, 1); 388 + 389 + mat.start().await; 390 + 391 + mat.wait_for_seekers().await; 392 + 393 + mat.game(1).mark_caught().await; 394 + 395 + mat.tick().await; 396 + 397 + mat.assert_all_states(|s| { 398 + assert_eq!( 399 + s.get_caught(1), 400 + Some(true), 401 + "Game {} sees player 1 as not caught", 402 + s.id 403 + ); 404 + }) 405 + .await; 406 + 407 + // Game over, See TODO in main_loop for more assertions 408 + } 409 + 410 + #[test] 411 + async fn test_basic_pinging() { 412 + let mut settings = mk_settings(); 413 + settings.ping_minutes_interval = 0; 414 + 415 + let mut mat = MockMatch::new(settings, 4, 1); 416 + 417 + mat.start().await; 418 + 419 + mat.wait_for_seekers().await; 420 + 421 + mat.assert_all_states(|s| { 422 + for id in 0..4 { 423 + let ping = s.get_ping(id); 424 + if id == 0 { 425 + assert!( 426 + ping.is_none(), 427 + "Game 0 is a seeker and shouldn't be pinged (in {})", 428 + s.id 429 + ); 430 + } else { 431 + assert!( 432 + ping.is_some(), 433 + "Game {} is a hider and should be pinged (in {})", 434 + id, 435 + s.id 436 + ); 437 + } 438 + } 439 + }) 440 + .await; 441 + 442 + mat.game(1).mark_caught().await; 443 + 444 + mat.tick().await; 445 + 446 + mat.assert_all_states(|s| { 447 + for id in 0..4 { 448 + let ping = s.get_ping(id); 449 + if id <= 1 { 450 + assert!( 451 + ping.is_none(), 452 + "Game {} is a seeker and shouldn't be pinged (in {})", 453 + id, 454 + s.id 455 + ); 456 + } else { 457 + assert!( 458 + ping.is_some(), 459 + "Game {} is a hider and should be pinged (in {})", 460 + id, 461 + s.id 462 + ); 463 + } 464 + } 465 + }) 466 + .await; 467 + } 468 + 469 + #[test] 470 + async fn test_rng_sync() { 471 + let mut settings = mk_settings(); 472 + settings.powerup_chance = 100; 473 + settings.powerup_minutes_cooldown = 1; 474 + settings.powerup_start = PingStartCondition::Instant; 475 + settings.powerup_locations = (1..1000) 476 + .into_iter() 477 + .map(|x| Location { 478 + lat: x as f64, 479 + long: 1.0, 480 + heading: None, 481 + }) 482 + .collect(); 483 + 484 + let mut mat = MockMatch::new(settings, 10, 2); 485 + 486 + mat.start().await; 487 + mat.tick().await; 488 + mat.wait_for_seekers().await; 489 + mat.pass_time(Duration::from_secs(60)).await; 490 + mat.tick().await; 491 + 492 + let game = mat.game(0); 493 + let state = game.state.read().await; 494 + let location = state.powerup_location().expect("Powerup didn't spawn"); 495 + 496 + drop(state); 497 + 498 + mat.assert_all_states(|s| { 499 + assert_eq!( 500 + s.powerup_location(), 501 + Some(location), 502 + "Game {} has a different location than 0", 503 + s.id 504 + ); 505 + }) 506 + .await; 507 + } 508 + 509 + #[test] 510 + async fn test_powerup_ping_seeker_as_you() { 511 + let mut settings = mk_settings(); 512 + settings.ping_minutes_interval = 0; 513 + let mut mat = MockMatch::new(settings, 2, 1); 514 + 515 + mat.start().await; 516 + mat.wait_for_seekers().await; 517 + 518 + let game = mat.game(1); 519 + let mut state = game.state.write().await; 520 + state.force_set_powerup(PowerUpType::PingSeeker); 521 + drop(state); 522 + 523 + mat.tick().await; 524 + 525 + mat.assert_all_states(|s| { 526 + if let Some(ping) = s.get_ping(1) { 527 + assert_eq!( 528 + ping.real_player, 0, 529 + "Ping for 1 is not truly 0 (in {})", 530 + s.id 531 + ); 532 + } else { 533 + panic!("No ping for 1 (in {})", s.id); 534 + } 535 + }) 536 + .await; 537 + } 538 + 539 + #[test] 540 + async fn test_powerup_ping_random_hider() { 541 + let settings = mk_settings(); 542 + 543 + let mut mat = MockMatch::new(settings, 3, 1); 544 + 545 + mat.start().await; 546 + mat.wait_for_seekers().await; 547 + 548 + let game = mat.game(1); 549 + let mut state = game.state.write().await; 550 + state.force_set_powerup(PowerUpType::ForcePingOther); 551 + drop(state); 552 + 553 + game.use_powerup().await; 554 + mat.tick().await; 555 + 556 + mat.assert_all_states(|s| { 557 + // Player 0 is a seeker, player 1 user the powerup, so 2 is the only one that should 558 + // could have pinged 559 + assert!(s.get_ping(2).is_some()); 560 + assert!(s.get_ping(0).is_none()); 561 + assert!(s.get_ping(1).is_none()); 562 + }) 563 + .await; 564 + } 565 + 566 + #[test] 567 + async fn test_powerup_ping_seekers() { 568 + let settings = mk_settings(); 569 + 570 + let mut mat = MockMatch::new(settings, 5, 3); 571 + 572 + mat.start().await; 573 + 574 + let game = mat.game(3); 575 + let mut state = game.state.write().await; 576 + state.force_set_powerup(PowerUpType::PingAllSeekers); 577 + drop(state); 578 + 579 + game.use_powerup().await; 580 + mat.tick().await; 581 + 582 + mat.assert_all_states(|s| { 583 + for id in 0..3 { 584 + assert!( 585 + s.get_caught(id).is_some(), 586 + "Player {} should be pinged due to the powerup (in {})", 587 + id, 588 + s.id 589 + ); 590 + } 591 + }) 592 + .await; 593 + } 594 + }
+24
backend/src/game/powerups.rs
··· 1 + use serde::{Deserialize, Serialize}; 2 + 3 + use super::{location::Location, PlayerId}; 4 + 5 + #[derive(Debug, Clone, Copy, Serialize, Deserialize)] 6 + /// Type of powerup 7 + pub enum PowerUpType { 8 + /// Ping a random seeker instead of a hider 9 + PingSeeker, 10 + 11 + /// Pings all seekers locations on the map for hiders 12 + PingAllSeekers, 13 + 14 + /// Ping another random hider instantly 15 + ForcePingOther, 16 + } 17 + 18 + impl PowerUpType { 19 + pub const ALL_TYPES: [Self; 3] = [ 20 + PowerUpType::ForcePingOther, 21 + PowerUpType::PingAllSeekers, 22 + PowerUpType::PingSeeker, 23 + ]; 24 + }
+41
backend/src/game/settings.rs
··· 1 + use rand::distr::Bernoulli; 2 + use serde::{Deserialize, Serialize}; 3 + 4 + use super::location::Location; 5 + 6 + #[derive(Debug, Clone, Serialize, Deserialize)] 7 + /// The starting condition for global pings to begin 8 + pub enum PingStartCondition { 9 + /// Wait For X players to be caught before beginning global pings 10 + Players(u32), 11 + /// Wait for X minutes after game start to begin global pings 12 + Minutes(u32), 13 + /// Don't wait at all, ping location after seekers are released 14 + Instant, 15 + } 16 + 17 + #[derive(Debug, Clone, Serialize, Deserialize)] 18 + /// Settings for the game, host is the only person able to change these 19 + pub struct GameSettings { 20 + /// The number of seconds to wait before seekers are allowed to go 21 + pub hiding_time_seconds: u32, 22 + /// Condition to wait for global pings to begin 23 + pub ping_start: PingStartCondition, 24 + /// Time between pings after the condition is met (first ping is either after the interval or 25 + /// instantly after the condition is met depending on the condition) 26 + pub ping_minutes_interval: u64, 27 + /// Condition for powerups to start spawning 28 + pub powerup_start: PingStartCondition, 29 + /// Chance every minute of a powerup spawning, out of 100 30 + pub powerup_chance: u32, 31 + /// Hard cooldown between powerups spawning 32 + pub powerup_minutes_cooldown: u64, 33 + /// Locations that powerups may spawn at 34 + pub powerup_locations: Vec<Location>, 35 + } 36 + 37 + impl GameSettings { 38 + pub fn get_powerup_bernoulli(&self) -> Bernoulli { 39 + Bernoulli::from_ratio(self.powerup_chance, 100).unwrap() 40 + } 41 + }
+338
backend/src/game/state.rs
··· 1 + use std::collections::HashMap; 2 + use std::sync::Arc; 3 + 4 + use chrono::{DateTime, Utc}; 5 + use rand::{ 6 + distr::{Bernoulli, Distribution}, 7 + rngs::ThreadRng, 8 + seq::{IndexedRandom, IteratorRandom}, 9 + Rng, SeedableRng, 10 + }; 11 + use rand_chacha::ChaCha20Rng; 12 + use serde::{Deserialize, Serialize}; 13 + 14 + use super::{ 15 + location::Location, 16 + powerups::PowerUpType, 17 + settings::{GameSettings, PingStartCondition}, 18 + PlayerId, UtcDT, 19 + }; 20 + 21 + #[derive(Debug, Clone, Serialize, Deserialize)] 22 + /// An on-map ping of a player 23 + pub struct PlayerPing<Id: PlayerId> { 24 + /// Location of the ping 25 + loc: Location, 26 + /// Time the ping happened 27 + timestamp: UtcDT, 28 + /// The player to display as 29 + pub display_player: Id, 30 + /// The actual player that initialized this ping 31 + pub real_player: Id, 32 + } 33 + 34 + impl<Id: PlayerId> PlayerPing<Id> { 35 + pub fn new(loc: Location, display_player: Id, real_player: Id) -> Self { 36 + Self { 37 + loc, 38 + display_player, 39 + real_player, 40 + timestamp: Utc::now(), 41 + } 42 + } 43 + } 44 + 45 + #[derive(Debug, Clone, Serialize)] 46 + /// Represents the game's state as a whole, seamlessly connects public and player state. 47 + /// This struct handles all logic regarding state updates 48 + pub struct GameState<Id: PlayerId> { 49 + /// The id of this player in this game 50 + pub id: Id, 51 + 52 + /// The powerup the player is currently holding 53 + held_powerup: Option<PowerUpType>, 54 + 55 + /// When the game started 56 + game_started: UtcDT, 57 + 58 + /// When seekers were allowed to begin 59 + seekers_started: Option<UtcDT>, 60 + 61 + /// Last time we pinged all players 62 + last_global_ping: Option<UtcDT>, 63 + 64 + /// Last time a powerup was spawned 65 + last_powerup_spawn: Option<UtcDT>, 66 + 67 + /// Hashmap tracking if a player is a seeker (true) or a hider (false) 68 + caught_state: HashMap<Id, bool>, 69 + 70 + /// A map of the latest global ping results for each player 71 + pings: HashMap<Id, PlayerPing<Id>>, 72 + 73 + /// Powerup on the map that players can grab. Only one at a time 74 + available_powerup: Option<Location>, 75 + 76 + /// The game's current settings 77 + settings: GameSettings, 78 + 79 + #[serde(skip)] 80 + /// The player's location history 81 + location_history: Vec<Location>, 82 + 83 + /// Cached bernoulli distribution for powerups, faster sampling 84 + #[serde(skip)] 85 + powerup_bernoulli: Bernoulli, 86 + 87 + /// A seed with a shared value between all players, should be reproducible 88 + /// RNG for use in stuff like powerup location selection. 89 + #[serde(skip)] 90 + shared_random_increment: i64, 91 + 92 + /// State for [ChaCha20Rng] to be used and added to when performing shared RNG operations 93 + #[serde(skip)] 94 + shared_random_state: u64, 95 + } 96 + 97 + impl<Id: PlayerId> GameState<Id> { 98 + pub fn new( 99 + settings: GameSettings, 100 + my_id: Id, 101 + random_seed: u64, 102 + initial_caught_state: HashMap<Id, bool>, 103 + ) -> Self { 104 + let mut rand = ChaCha20Rng::seed_from_u64(random_seed); 105 + let increment = rand.random_range(-100..100); 106 + 107 + Self { 108 + id: my_id, 109 + game_started: Utc::now(), 110 + seekers_started: None, 111 + pings: HashMap::with_capacity(initial_caught_state.len()), 112 + caught_state: initial_caught_state, 113 + available_powerup: None, 114 + powerup_bernoulli: settings.get_powerup_bernoulli(), 115 + settings, 116 + last_global_ping: None, 117 + last_powerup_spawn: None, 118 + location_history: Vec::with_capacity(30), 119 + held_powerup: None, 120 + shared_random_increment: increment, 121 + shared_random_state: random_seed, 122 + } 123 + } 124 + 125 + fn create_rand_from_shared_seed(&mut self) -> ChaCha20Rng { 126 + let rand = ChaCha20Rng::seed_from_u64(self.shared_random_state); 127 + 128 + self.shared_random_state = self 129 + .shared_random_state 130 + .wrapping_add_signed(self.shared_random_increment); 131 + 132 + rand 133 + } 134 + 135 + /// Spawn a powerup on the map, this **MUST** be called on all players at about the same time. 136 + /// First rolls to see if we will spawn one with `chance` (chance is percent chance out of 100). 137 + /// If the roll succeeds, spawn a powerup at one of the given locations. 138 + pub fn try_spawn_powerup(&mut self, now: UtcDT) { 139 + let mut shared_rand = self.create_rand_from_shared_seed(); 140 + let roll = self.powerup_bernoulli.sample(&mut shared_rand); 141 + if roll { 142 + let choice = self 143 + .settings 144 + .powerup_locations 145 + .choose(&mut shared_rand) 146 + .cloned(); 147 + self.available_powerup = choice; 148 + self.last_powerup_spawn = Some(now); 149 + } 150 + } 151 + 152 + fn minutes_since_seekers_released(&self, now: UtcDT) -> Option<u32> { 153 + self.seekers_started 154 + .as_ref() 155 + .map(|released| (now - *released).num_minutes().unsigned_abs() as u32) 156 + } 157 + 158 + pub fn pings_started(&self) -> bool { 159 + self.last_global_ping.is_some() 160 + } 161 + 162 + pub fn should_start_pings(&self, now: UtcDT) -> bool { 163 + match self.settings.ping_start { 164 + PingStartCondition::Players(num) => (self.iter_seekers().count() as u32) >= num, 165 + PingStartCondition::Minutes(minutes) => self 166 + .minutes_since_seekers_released(now) 167 + .is_some_and(|seekers_released| seekers_released >= minutes), 168 + PingStartCondition::Instant => true, 169 + } 170 + } 171 + 172 + /// Whether enough time has passed that we should perform a ping 173 + pub fn should_ping(&self, now: &UtcDT) -> bool { 174 + !self.is_seeker() 175 + && self.last_global_ping.as_ref().is_some_and(|last_ping| { 176 + let minutes = (*now - *last_ping).num_minutes().unsigned_abs(); 177 + minutes >= self.settings.ping_minutes_interval 178 + }) 179 + } 180 + 181 + /// Begin pinging, will start the countdown for global pings. Also refreshes the timeout 182 + pub fn start_pings(&mut self, now: UtcDT) { 183 + self.last_global_ping = Some(now); 184 + } 185 + 186 + /// Begin spawning powerups 187 + pub fn start_powerups(&mut self, now: UtcDT) { 188 + self.last_powerup_spawn = Some(now); 189 + } 190 + 191 + /// Whether to start spawning powerups 192 + pub fn should_start_powerups(&self, now: UtcDT) -> bool { 193 + match self.settings.powerup_start { 194 + PingStartCondition::Players(num) => (self.iter_seekers().count() as u32) >= num, 195 + PingStartCondition::Minutes(mins) => self 196 + .minutes_since_seekers_released(now) 197 + .is_some_and(|seekers_released| seekers_released >= mins), 198 + PingStartCondition::Instant => true, 199 + } 200 + } 201 + 202 + pub fn powerups_started(&self) -> bool { 203 + self.last_powerup_spawn.is_some() 204 + } 205 + 206 + /// Whether enough time has passed that we should roll for powerup spawns 207 + pub fn should_spawn_powerup(&self, now: &UtcDT) -> bool { 208 + self.last_powerup_spawn.as_ref().is_some_and(|last_spawn| { 209 + let minutes = (*now - *last_spawn).num_minutes().unsigned_abs(); 210 + minutes >= self.settings.powerup_minutes_cooldown 211 + }) 212 + } 213 + 214 + pub fn powerup_location(&self) -> Option<Location> { 215 + self.available_powerup 216 + } 217 + 218 + /// Despawn a powerup (due to timeout, other person getting it) 219 + pub fn despawn_powerup(&mut self) { 220 + self.available_powerup = None; 221 + } 222 + 223 + pub fn should_release_seekers(&self, now: UtcDT) -> bool { 224 + let seconds = (now - self.game_started).num_seconds().unsigned_abs(); 225 + seconds >= (self.settings.hiding_time_seconds as u64) 226 + } 227 + 228 + /// Mark seekers as released 229 + pub fn release_seekers(&mut self, now: UtcDT) { 230 + self.seekers_started = Some(now); 231 + } 232 + 233 + /// If seekers are released 234 + pub fn seekers_released(&self) -> bool { 235 + self.seekers_started.is_some() 236 + } 237 + 238 + /// Add a ping for a specific player 239 + pub fn add_ping(&mut self, ping: PlayerPing<Id>) { 240 + self.pings.insert(ping.display_player, ping); 241 + } 242 + 243 + /// Get a ping for a player 244 + pub fn get_ping(&self, player: Id) -> Option<&PlayerPing<Id>> { 245 + self.pings.get(&player) 246 + } 247 + 248 + /// Remove a ping from the map 249 + pub fn remove_ping(&mut self, player: Id) -> Option<PlayerPing<Id>> { 250 + self.pings.remove(&player) 251 + } 252 + 253 + /// Iterate over all seekers in the game 254 + pub fn iter_seekers(&self) -> impl Iterator<Item = Id> + use<'_, Id> { 255 + self.caught_state 256 + .iter() 257 + .filter_map(|(k, v)| if *v { Some(*k) } else { None }) 258 + } 259 + 260 + /// Pick a random seeker 261 + pub fn random_seeker(&mut self) -> Option<Id> { 262 + let seekers = self.iter_seekers().collect::<Vec<_>>(); 263 + let mut rand = rand::rng(); 264 + seekers.choose(&mut rand).copied() 265 + } 266 + 267 + /// Iterate over all hiders in the game 268 + fn iter_hiders(&self) -> impl Iterator<Item = Id> + use<'_, Id> { 269 + self.caught_state 270 + .iter() 271 + .filter_map(|(k, v)| if !*v { Some(*k) } else { None }) 272 + } 273 + 274 + pub fn random_other_hider(&self) -> Option<Id> { 275 + let mut rand = rand::rng(); 276 + self.iter_hiders() 277 + .filter(|id| *id != self.id) 278 + .choose(&mut rand) 279 + } 280 + 281 + /// Create a [PlayerPing] with the latest location saved for the player 282 + pub fn create_self_ping(&self) -> Option<PlayerPing<Id>> { 283 + self.create_ping(self.id) 284 + } 285 + 286 + /// Create a [PlayerPing] with the latest location as another player 287 + pub fn create_ping(&self, id: Id) -> Option<PlayerPing<Id>> { 288 + self.get_loc() 289 + .map(|loc| PlayerPing::new(loc.clone(), id, self.id)) 290 + } 291 + 292 + /// Player has gotten a powerup, rolls to see which powerup and stores it 293 + pub fn get_powerup(&mut self) { 294 + let mut rand = rand::rng(); 295 + // TODO: Seekers vs Hiders, Weights? 296 + let choice = PowerUpType::ALL_TYPES.choose(&mut rand).copied(); 297 + self.held_powerup = choice; 298 + } 299 + 300 + pub fn force_set_powerup(&mut self, typ: PowerUpType) { 301 + self.held_powerup = Some(typ); 302 + } 303 + 304 + pub fn peek_powerup(&self) -> Option<&PowerUpType> { 305 + self.held_powerup.as_ref() 306 + } 307 + 308 + /// "Use" a powerup, takes it out of [held_powerup] and returns the type for use in game logic 309 + pub fn use_powerup(&mut self) -> Option<PowerUpType> { 310 + self.held_powerup.take() 311 + } 312 + 313 + /// Push a new player location 314 + pub fn push_loc(&mut self, loc: Location) { 315 + self.location_history.push(loc); 316 + } 317 + 318 + /// Get the latest player location 319 + fn get_loc(&self) -> Option<&Location> { 320 + self.location_history.last() 321 + } 322 + 323 + /// Mark a player as caught 324 + pub fn mark_caught(&mut self, player: Id) { 325 + if let Some(caught) = self.caught_state.get_mut(&player) { 326 + *caught = true; 327 + } 328 + } 329 + 330 + /// Gets if a player was caught or not 331 + pub fn get_caught(&self, player: Id) -> Option<bool> { 332 + self.caught_state.get(&player).copied() 333 + } 334 + 335 + pub fn is_seeker(&self) -> bool { 336 + self.caught_state.get(&self.id).copied().unwrap_or_default() 337 + } 338 + }
+10
backend/src/game/transport.rs
··· 1 + use futures::{stream::FuturesUnordered, StreamExt}; 2 + 3 + use super::{events::GameEvent, PlayerId, UtcDT}; 4 + 5 + pub trait Transport<Id: PlayerId> { 6 + /// Receive an event 7 + async fn receive_message(&self) -> Option<GameEvent<Id>>; 8 + /// Send an event 9 + async fn send_message(&self, msg: GameEvent<Id>); 10 + }
-2
backend/src/lib.rs
··· 1 1 #[allow(unused)] 2 2 mod game; 3 - mod powerup; 4 - mod state; 5 3 6 4 #[cfg_attr(mobile, tauri::mobile_entry_point)] 7 5 pub fn run() {
-65
backend/src/powerup.rs
··· 1 - use crate::state::{Location, PlayerId}; 2 - 3 - #[derive(Clone, Copy)] 4 - /// Type of powerup 5 - pub enum PowerUpType { 6 - /// Ping a random seeker instead of a hider 7 - PingSeeker, 8 - 9 - /// Pings all seekers locations on the map for hiders 10 - PingAllSeekers, 11 - 12 - /// Ping another random hider instantly 13 - ForcePingOther, 14 - } 15 - 16 - impl PowerUpType { 17 - pub const ALL_TYPES: [Self; 3] = [ 18 - PowerUpType::ForcePingOther, 19 - PowerUpType::PingAllSeekers, 20 - PowerUpType::PingSeeker, 21 - ]; 22 - } 23 - 24 - #[derive(Clone)] 25 - /// Usage of a powerup as reported to the host 26 - pub enum PowerUpUsage { 27 - /// The hider will have their location replaced with a random seeker's 28 - PingSeeker, 29 - /// No additional args 30 - PingAllSeekers, 31 - /// Instantly ping another random hider, contains the unlucky person that is being pinged 32 - ForcePingOther(PlayerId), 33 - } 34 - 35 - #[derive(Clone, PartialEq, Eq)] 36 - /// When a plugin is used 37 - pub enum PowerUpTiming { 38 - /// Used the second it's activated 39 - Instant, 40 - /// Used during the next global ping 41 - NextPing, 42 - } 43 - 44 - impl PowerUpUsage { 45 - pub fn timing(&self) -> PowerUpTiming { 46 - match self { 47 - PowerUpUsage::PingSeeker => PowerUpTiming::NextPing, 48 - PowerUpUsage::ForcePingOther(_) => PowerUpTiming::Instant, 49 - PowerUpUsage::PingAllSeekers => PowerUpTiming::Instant, 50 - } 51 - } 52 - } 53 - 54 - #[derive(Clone)] 55 - /// An on-map powerup that can be picked up by hiders 56 - pub struct PowerUp { 57 - loc: Location, 58 - pub typ: PowerUpType, 59 - } 60 - 61 - impl PowerUp { 62 - pub fn new(loc: Location, typ: PowerUpType) -> Self { 63 - Self { loc, typ } 64 - } 65 - }
-475
backend/src/state.rs
··· 1 - use std::collections::HashMap; 2 - 3 - use chrono::{DateTime, Utc}; 4 - 5 - use crate::{ 6 - game::LocationService, 7 - powerup::{PowerUp, PowerUpTiming, PowerUpType, PowerUpUsage}, 8 - }; 9 - 10 - /// UTC DateTime; 11 - pub type DT = DateTime<Utc>; 12 - 13 - /// Type used to uniquely identify players in the game 14 - pub type PlayerId = u32; 15 - 16 - /// Type used for latitude and longitude 17 - pub type LocationComponent = f64; 18 - 19 - #[derive(Debug, Clone)] 20 - /// The starting condition for global pings to begin 21 - pub enum PingStartCondition { 22 - /// Wait For X players to be caught before beginning global pings 23 - Players(u32), 24 - /// Wait for X minutes after game start to begin global pings 25 - Minutes(u32), 26 - /// Don't wait at all, ping location after seekers are released 27 - Instant, 28 - } 29 - 30 - #[derive(Debug, Clone)] 31 - /// Settings for the game, host is the only person able to change these 32 - pub struct GameSettings { 33 - /// The number of seconds to wait before seekers are allowed to go 34 - pub hiding_time_seconds: u64, 35 - /// Condition to wait for global pings to begin 36 - pub ping_start: PingStartCondition, 37 - /// Time between pings after the condition is met (first ping is either after the interval or 38 - /// instantly after the condition is met depending on the condition) 39 - pub ping_minutes_interval: u64, 40 - /// Condition for powerups to start spawning 41 - pub powerup_start: PingStartCondition, 42 - /// Chance (after cooldown) each minute of a powerup spawning, out of 100 43 - pub powerup_chance: u32, 44 - /// Hard cooldown between powerups spawning 45 - pub powerup_minutes_cooldown: u32, 46 - /// Locations that powerups may spawn at 47 - pub powerup_locations: Vec<Location>, 48 - } 49 - 50 - #[derive(Debug, Clone, Copy)] 51 - /// Some location in the world as gotten from the Geolocation API 52 - pub struct Location { 53 - /// Latitude 54 - pub lat: LocationComponent, 55 - /// Longitude 56 - pub long: LocationComponent, 57 - /// The bearing (float normalized from 0 to 1) optional as GPS can't always determine 58 - pub heading: Option<LocationComponent>, 59 - } 60 - 61 - /// State for each player during the game, the host also has this 62 - pub struct PlayerState { 63 - /// The id of this player in this game 64 - pub id: PlayerId, 65 - /// All previous locations of this player, used in replay screen and when a ping happens 66 - pub locations: Vec<Location>, 67 - /// Whether the local player is a seeker 68 - pub seeker: bool, 69 - /// The powerup the player is currently holding 70 - pub held_powerup: Option<PowerUpType>, 71 - } 72 - 73 - /// Host state that determines when "privileged" events happen 74 - pub struct HostState { 75 - /// The last time a location global ping occurred. If this is [Option::None] it means we're not 76 - /// pinging yet 77 - pub last_ping: Option<DT>, 78 - 79 - /// The last time a power-up has spawned. 80 - pub last_powerup: Option<DT>, 81 - 82 - /// Last time a roll was done for a powerup to spawn, if this is [Option::None] it means we're 83 - /// not spawning powerups yet. 84 - pub last_powerup_proc: Option<DT>, 85 - 86 - /// Set of users that will not be pinged / ping someone else next ping 87 - pub ping_power_usages: HashMap<PlayerId, PowerUpUsage>, 88 - 89 - /// A list of all events that happened in this game, and their times 90 - pub event_history: Vec<(PlayerId, DT, GameEvent)>, 91 - } 92 - 93 - impl HostState { 94 - pub fn new() -> Self { 95 - Self { 96 - last_ping: None, 97 - last_powerup: None, 98 - last_powerup_proc: None, 99 - ping_power_usages: HashMap::with_capacity(4), 100 - event_history: Vec::with_capacity(50), 101 - } 102 - } 103 - } 104 - 105 - #[derive(Clone)] 106 - /// An on-map ping of a player 107 - pub struct PlayerPing { 108 - /// Location of the ping 109 - loc: Location, 110 - /// Time the ping happened 111 - time: DT, 112 - /// The player to display who initialized this ping 113 - player: PlayerId, 114 - /// The actual player that initialized this ping 115 - real_player: PlayerId, 116 - } 117 - 118 - impl PlayerPing { 119 - pub fn new(loc: Location, player: PlayerId, real_player: PlayerId) -> Self { 120 - Self { 121 - loc, 122 - player, 123 - real_player, 124 - time: Utc::now(), 125 - } 126 - } 127 - } 128 - 129 - /// State meant to be updated and synced 130 - pub struct PublicState { 131 - /// When the game started 132 - pub game_started: DT, 133 - 134 - /// When seekers were allowed to begin 135 - pub seekers_started: Option<DT>, 136 - 137 - /// Hashmap tracking if a player is a seeker (true) or a hider (false) 138 - pub caught_state: HashMap<PlayerId, bool>, 139 - 140 - /// A map of the latest global ping results for each player 141 - pub pings: HashMap<PlayerId, Option<PlayerPing>>, 142 - 143 - /// Powerup on the map that players can grab. Only one at a time 144 - pub available_powerup: Option<PowerUp>, 145 - } 146 - 147 - impl PublicState { 148 - pub fn new(players: HashMap<PlayerId, bool>) -> Self { 149 - Self { 150 - game_started: Utc::now(), 151 - seekers_started: None, 152 - pings: HashMap::from_iter(players.keys().map(|id| (*id, None))), 153 - caught_state: players, 154 - available_powerup: None, 155 - } 156 - } 157 - 158 - pub fn iter_seekers(&self) -> impl Iterator<Item = PlayerId> + use<'_> { 159 - self.caught_state 160 - .iter() 161 - .filter_map(|(k, v)| if *v { Some(*k) } else { None }) 162 - } 163 - 164 - pub fn iter_hiders(&self) -> impl Iterator<Item = PlayerId> + use<'_> { 165 - self.caught_state 166 - .iter() 167 - .filter_map(|(k, v)| if !*v { Some(*k) } else { None }) 168 - } 169 - } 170 - 171 - impl PlayerState { 172 - pub fn new(id: PlayerId, seeker: bool) -> Self { 173 - Self { 174 - id, 175 - locations: Vec::with_capacity(20), 176 - seeker, 177 - held_powerup: None, 178 - } 179 - } 180 - 181 - /// Create a [PlayerPing] with the latest location saved for the player 182 - pub fn create_self_ping(&self) -> Option<PlayerPing> { 183 - self.create_ping(self.id) 184 - } 185 - 186 - /// Create a [PlayerPing] with the latest location as another player, used when powerups are 187 - /// active 188 - pub fn create_ping(&self, id: PlayerId) -> Option<PlayerPing> { 189 - self.get_loc() 190 - .map(|loc| PlayerPing::new(loc.clone(), id, self.id)) 191 - } 192 - 193 - /// Push a new player location 194 - pub fn push_loc(&mut self, loc: Location) { 195 - self.locations.push(loc); 196 - } 197 - 198 - /// Get the latest player location 199 - pub fn get_loc(&self) -> Option<&Location> { 200 - self.locations.last() 201 - } 202 - } 203 - 204 - /// Central struct for managing the entire game's state 205 - pub struct GameState<L: LocationService> { 206 - /// Player state, different for each player 207 - pub player: PlayerState, 208 - /// Public state, kept in sync via events 209 - pub public: PublicState, 210 - /// Host state, only for host, this being [Option::None] implies not being host 211 - pub host: Option<HostState>, 212 - /// The settings for the current game, read only 213 - pub settings: GameSettings, 214 - loc: L, 215 - } 216 - 217 - #[derive(Clone)] 218 - /// Enum representing all events that can be published, some are host only although 219 - /// implicit trust is given to all players because uh who cares. 220 - pub enum GameEvent { 221 - /// Seekers are now active and can see the map 222 - SeekersReleased(DT), 223 - /// (Host) A request for a given player to ping, optionally includes another player to ping 224 - /// *as* (e.g. when [PowerUpType::PingSeeker] is used) 225 - PingReq(Option<PlayerId>), 226 - /// A [PlayerPing] was published to [PublicState] 227 - Ping(PlayerPing), 228 - /// The given hider has been caught 229 - HiderCaught(PlayerId), 230 - /// (Host) The powerup has spawned and is available to grab 231 - PowerUpSpawn(PowerUp), 232 - /// The powerup has despawned (Was grabbed or timed out) 233 - PowerUpDespawn, 234 - /// A player has activated a powerup, some powerups will be published globally and some will be 235 - /// handled only by the host (such as [PowerUpType::PingSeeker]) 236 - PowerUpActivate(PowerUpUsage), 237 - /// (Host) The game has ended (all players were caught or the host cancelled the game) 238 - GameEnd(DT), 239 - /// (Players) After the game has ended, players send this as the final game message 240 - /// to the host with their entire location history 241 - PostGameSync(Vec<Location>), 242 - /// (Host) After the game has ended and all players have sent their location histories to the 243 - /// host, the host will send this back to all players. Contains the entire history of the game 244 - /// to be saved and replayed. 245 - HostHistorySync( 246 - ( 247 - HashMap<PlayerId, Vec<Location>>, 248 - Vec<(PlayerId, DT, GameEvent)>, 249 - ), 250 - ), 251 - } 252 - 253 - impl<L: LocationService> GameState<L> { 254 - /// Create a new game state (starting a game). Needs the ID of the current player and a HashMap 255 - /// of other player ids to their caught state (whether they start out as seeker). 256 - pub fn new( 257 - host: bool, 258 - id: PlayerId, 259 - players: HashMap<PlayerId, bool>, 260 - settings: GameSettings, 261 - loc: L, 262 - ) -> Self { 263 - let is_seeker = players.get(&id).copied().unwrap_or_default(); 264 - Self { 265 - player: PlayerState::new(id, is_seeker), 266 - public: PublicState::new(players), 267 - host: if host { Some(HostState::new()) } else { None }, 268 - settings, 269 - loc, 270 - } 271 - } 272 - 273 - pub fn random_other_hider(&mut self) -> Option<PlayerId> { 274 - let hiders = self 275 - .public 276 - .iter_hiders() 277 - .filter(|i| *i != self.player.id) 278 - .collect::<Vec<_>>(); 279 - let choice = rand::random_range(0..hiders.len()); 280 - hiders.get(choice).copied() 281 - } 282 - 283 - fn host_tick(&mut self, events: &mut Vec<(Option<PlayerId>, GameEvent)>) { 284 - if let Some(host) = self.host.as_mut() { 285 - let now = Utc::now(); 286 - 287 - // Do seekers need to be released? 288 - if self.public.seekers_started.is_none() 289 - && (now - self.public.game_started) 290 - .num_seconds() 291 - .unsigned_abs() 292 - >= self.settings.hiding_time_seconds 293 - { 294 - events.push((None, GameEvent::SeekersReleased(now))); 295 - } 296 - 297 - // Do we need to start doing global pings? 298 - if host.last_ping.is_none() { 299 - let should_start = match self.settings.ping_start { 300 - PingStartCondition::Players(players) => { 301 - self.public.caught_state.values().filter(|v| **v).count() 302 - >= (players as usize) 303 - } 304 - PingStartCondition::Minutes(min) => { 305 - let delta = now - self.public.game_started; 306 - delta.num_minutes() >= (min as i64) 307 - } 308 - PingStartCondition::Instant => true, 309 - }; 310 - if should_start { 311 - host.last_ping = Some(now); 312 - } 313 - } 314 - 315 - // Do we need to do a global ping? 316 - if let Some(last_ping) = host.last_ping.as_mut() { 317 - if (now - *last_ping).num_minutes().unsigned_abs() 318 - >= self.settings.ping_minutes_interval 319 - { 320 - events.extend(self.public.caught_state.iter().filter_map( 321 - |(player, caught)| { 322 - // If caught, don't send a ping request 323 - if *caught { 324 - None 325 - } else { 326 - // If the player is pinging as someone else, do that here. 327 - if let Some(PowerUpUsage::PingSeeker) = 328 - host.ping_power_usages.get(player) 329 - { 330 - host.ping_power_usages.remove(player); 331 - let seekers = self.public.iter_seekers().collect::<Vec<_>>(); 332 - let choice = rand::random_range(0..seekers.len()); 333 - let seeker = seekers[choice]; 334 - return Some((Some(seeker), GameEvent::PingReq(Some(*player)))); 335 - } 336 - Some((Some(*player), GameEvent::PingReq(None))) 337 - } 338 - }, 339 - )); 340 - 341 - *last_ping = now; 342 - } 343 - } 344 - 345 - // Do we need to start rolling for powerups? 346 - if host.last_powerup_proc.is_none() { 347 - let should_start = match self.settings.ping_start { 348 - PingStartCondition::Players(players) => { 349 - self.public.caught_state.values().filter(|v| **v).count() 350 - >= (players as usize) 351 - } 352 - PingStartCondition::Minutes(min) => { 353 - let delta = now - self.public.game_started; 354 - delta.num_minutes() >= (min as i64) 355 - } 356 - PingStartCondition::Instant => true, 357 - }; 358 - if should_start { 359 - host.last_powerup_proc = Some(now); 360 - } 361 - } 362 - 363 - // Should we roll for a powerup? 364 - if let Some(last_powerup_proc) = host.last_powerup_proc.as_mut() { 365 - if (now - *last_powerup_proc).num_minutes() >= 1 { 366 - // A minute has passed, roll to see if we should spawn a powerup 367 - let cooldown_over = host.last_powerup.is_none_or(|d| { 368 - (now - d).num_minutes() >= (self.settings.powerup_minutes_cooldown as i64) 369 - }); 370 - let roll = rand::random_ratio(self.settings.powerup_chance, 100); 371 - 372 - if cooldown_over && roll { 373 - // Cooldown is over and we rolled positive, choose and send out a powerup. 374 - let typ_choice = rand::random_range(0..PowerUpType::ALL_TYPES.len()); 375 - let loc_choice = 376 - rand::random_range(0..self.settings.powerup_locations.len()); 377 - let powerup = PowerUp::new( 378 - self.settings.powerup_locations[loc_choice], 379 - PowerUpType::ALL_TYPES[typ_choice], 380 - ); 381 - 382 - events.push((None, GameEvent::PowerUpSpawn(powerup))); 383 - 384 - host.last_powerup = Some(now); 385 - } 386 - 387 - *last_powerup_proc = now; 388 - } 389 - } 390 - } 391 - } 392 - 393 - fn update_loc(&mut self) { 394 - let loc = self.loc.get_loc(); 395 - self.player.push_loc(loc); 396 - } 397 - 398 - /// Run a single game tick, returns any messages that need to be sent 399 - pub fn tick(&mut self) -> Vec<(Option<PlayerId>, GameEvent)> { 400 - let mut events = Vec::with_capacity(5); 401 - 402 - self.host_tick(&mut events); 403 - self.update_loc(); 404 - 405 - events 406 - } 407 - 408 - /// Consume an event, optionally returns events to re-broadcast 409 - pub fn consume_event( 410 - &mut self, 411 - time_sent: DT, 412 - event: GameEvent, 413 - player_id: PlayerId, 414 - ) -> Option<GameEvent> { 415 - if let Some(host) = self.host.as_mut() { 416 - host.event_history 417 - .push((player_id, time_sent, event.clone())); 418 - } 419 - 420 - match event { 421 - GameEvent::SeekersReleased(time) => { 422 - self.public.seekers_started = Some(time); 423 - } 424 - GameEvent::PingReq(fake_player) => { 425 - let ping = if let Some(fake_player) = fake_player { 426 - self.player.create_ping(fake_player) 427 - } else { 428 - self.player.create_self_ping() 429 - }; 430 - 431 - return ping.map(|p| GameEvent::Ping(p)); 432 - } 433 - GameEvent::Ping(ping) => { 434 - if let Some(current) = self.public.pings.get_mut(&ping.player) { 435 - *current = Some(ping); 436 - } 437 - } 438 - GameEvent::HiderCaught(id) => { 439 - if id == self.player.id { 440 - self.player.seeker = true; 441 - } 442 - if let Some(state) = self.public.caught_state.get_mut(&id) { 443 - *state = true; 444 - } 445 - if self.host.is_some() && self.public.caught_state.iter().all(|(_, k)| *k) { 446 - return Some(GameEvent::GameEnd(Utc::now())); 447 - } 448 - } 449 - GameEvent::GameEnd(_dt) => { 450 - // [Game] handles this case, do nothing if we get here. 451 - } 452 - GameEvent::PowerUpSpawn(power_up) => { 453 - self.public.available_powerup = Some(power_up); 454 - } 455 - GameEvent::PowerUpDespawn => { 456 - self.public.available_powerup = None; 457 - } 458 - GameEvent::PowerUpActivate(usage) => { 459 - if usage.timing() == PowerUpTiming::NextPing { 460 - if let Some(host) = self.host.as_mut() { 461 - if let Some(old_usage) = host.ping_power_usages.get_mut(&player_id) { 462 - *old_usage = usage; 463 - } else { 464 - host.ping_power_usages.insert(player_id, usage); 465 - } 466 - } 467 - } 468 - } 469 - GameEvent::PostGameSync(_) | GameEvent::HostHistorySync(_) => { 470 - // Handled by [Game] 471 - } 472 - } 473 - None 474 - } 475 - }
+12 -12
flake.lock
··· 5 5 "nixpkgs": "nixpkgs" 6 6 }, 7 7 "locked": { 8 - "lastModified": 1748868585, 9 - "narHash": "sha256-DrrbahOQAwvNM8l5EuGxxkVS7X5/S59zcG0N9ZWQFhk=", 8 + "lastModified": 1749473391, 9 + "narHash": "sha256-NkkS2d7OvXL9VJS1pae+txd43vUIMWtxlIBdsKCRtYg=", 10 10 "owner": "nix-community", 11 11 "repo": "flakelight", 12 - "rev": "dfbecd12d99c1bf82906521a6a7d5b75d2aa1ca2", 12 + "rev": "22c8488d41c4e4678d32538f855bc05b3ba5142e", 13 13 "type": "github" 14 14 }, 15 15 "original": { ··· 20 20 }, 21 21 "nixpkgs": { 22 22 "locked": { 23 - "lastModified": 1748693115, 24 - "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", 23 + "lastModified": 1749285348, 24 + "narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=", 25 25 "owner": "NixOS", 26 26 "repo": "nixpkgs", 27 - "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", 27 + "rev": "3e3afe5174c561dee0df6f2c2b2236990146329f", 28 28 "type": "github" 29 29 }, 30 30 "original": { ··· 36 36 }, 37 37 "nixpkgs_2": { 38 38 "locked": { 39 - "lastModified": 1748792178, 40 - "narHash": "sha256-BHmgfHlCJVNisJShVaEmfDIr/Ip58i/4oFGlD1iK6lk=", 39 + "lastModified": 1749523198, 40 + "narHash": "sha256-How2kQw0psKmCdXgojc95Sf3K5maHB3qfINxTZFCAPM=", 41 41 "owner": "NixOS", 42 42 "repo": "nixpkgs", 43 - "rev": "5929de975bcf4c7c8d8b5ca65c8cd9ef9e44523e", 43 + "rev": "cdc68935eba9f86d155585fdf6f17af6824f38ac", 44 44 "type": "github" 45 45 }, 46 46 "original": { ··· 64 64 ] 65 65 }, 66 66 "locked": { 67 - "lastModified": 1748832016, 68 - "narHash": "sha256-TQSaFa1wWJr6GOs+K8lecK4AKKr8k6mwxHIPCOmVkgs=", 67 + "lastModified": 1749523120, 68 + "narHash": "sha256-lEhEK8qE8xto2Wnj4f7R+VRSg7M6tgTTkJVTZ2QxXOI=", 69 69 "owner": "oxalica", 70 70 "repo": "rust-overlay", 71 - "rev": "7ec2ea005b600dac9436a7c5c6b66d960cbfcea2", 71 + "rev": "d0727dbab79c5a28289f3c03e4fac7d5b95bafb3", 72 72 "type": "github" 73 73 }, 74 74 "original": {
+1970 -1962
frontend/package-lock.json
··· 1 1 { 2 - "name": "manhunt-app", 3 - "version": "0.1.0", 4 - "lockfileVersion": 3, 5 - "requires": true, 6 - "packages": { 7 - "": { 8 - "name": "manhunt-app", 9 - "version": "0.1.0", 10 - "dependencies": { 11 - "@tauri-apps/api": "^2", 12 - "@tauri-apps/plugin-opener": "^2", 13 - "react": "^18.3.1", 14 - "react-dom": "^18.3.1" 15 - }, 16 - "devDependencies": { 17 - "@tauri-apps/cli": "^2", 18 - "@types/react": "^18.3.1", 19 - "@types/react-dom": "^18.3.1", 20 - "@vitejs/plugin-react": "^4.3.4", 21 - "typescript": "~5.6.2", 22 - "vite": "^6.0.3" 23 - } 24 - }, 25 - "node_modules/@ampproject/remapping": { 26 - "version": "2.3.0", 27 - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", 28 - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 29 - "dev": true, 30 - "license": "Apache-2.0", 31 - "dependencies": { 32 - "@jridgewell/gen-mapping": "^0.3.5", 33 - "@jridgewell/trace-mapping": "^0.3.24" 34 - }, 35 - "engines": { 36 - "node": ">=6.0.0" 37 - } 38 - }, 39 - "node_modules/@babel/code-frame": { 40 - "version": "7.27.1", 41 - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", 42 - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", 43 - "dev": true, 44 - "license": "MIT", 45 - "dependencies": { 46 - "@babel/helper-validator-identifier": "^7.27.1", 47 - "js-tokens": "^4.0.0", 48 - "picocolors": "^1.1.1" 49 - }, 50 - "engines": { 51 - "node": ">=6.9.0" 52 - } 53 - }, 54 - "node_modules/@babel/compat-data": { 55 - "version": "7.27.1", 56 - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz", 57 - "integrity": "sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A==", 58 - "dev": true, 59 - "license": "MIT", 60 - "engines": { 61 - "node": ">=6.9.0" 62 - } 63 - }, 64 - "node_modules/@babel/core": { 65 - "version": "7.27.1", 66 - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz", 67 - "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", 68 - "dev": true, 69 - "license": "MIT", 70 - "dependencies": { 71 - "@ampproject/remapping": "^2.2.0", 72 - "@babel/code-frame": "^7.27.1", 73 - "@babel/generator": "^7.27.1", 74 - "@babel/helper-compilation-targets": "^7.27.1", 75 - "@babel/helper-module-transforms": "^7.27.1", 76 - "@babel/helpers": "^7.27.1", 77 - "@babel/parser": "^7.27.1", 78 - "@babel/template": "^7.27.1", 79 - "@babel/traverse": "^7.27.1", 80 - "@babel/types": "^7.27.1", 81 - "convert-source-map": "^2.0.0", 82 - "debug": "^4.1.0", 83 - "gensync": "^1.0.0-beta.2", 84 - "json5": "^2.2.3", 85 - "semver": "^6.3.1" 86 - }, 87 - "engines": { 88 - "node": ">=6.9.0" 89 - }, 90 - "funding": { 91 - "type": "opencollective", 92 - "url": "https://opencollective.com/babel" 93 - } 94 - }, 95 - "node_modules/@babel/generator": { 96 - "version": "7.27.1", 97 - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz", 98 - "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==", 99 - "dev": true, 100 - "license": "MIT", 101 - "dependencies": { 102 - "@babel/parser": "^7.27.1", 103 - "@babel/types": "^7.27.1", 104 - "@jridgewell/gen-mapping": "^0.3.5", 105 - "@jridgewell/trace-mapping": "^0.3.25", 106 - "jsesc": "^3.0.2" 107 - }, 108 - "engines": { 109 - "node": ">=6.9.0" 110 - } 111 - }, 112 - "node_modules/@babel/helper-compilation-targets": { 113 - "version": "7.27.1", 114 - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.1.tgz", 115 - "integrity": "sha512-2YaDd/Rd9E598B5+WIc8wJPmWETiiJXFYVE60oX8FDohv7rAUU3CQj+A1MgeEmcsk2+dQuEjIe/GDvig0SqL4g==", 116 - "dev": true, 117 - "license": "MIT", 118 - "dependencies": { 119 - "@babel/compat-data": "^7.27.1", 120 - "@babel/helper-validator-option": "^7.27.1", 121 - "browserslist": "^4.24.0", 122 - "lru-cache": "^5.1.1", 123 - "semver": "^6.3.1" 124 - }, 125 - "engines": { 126 - "node": ">=6.9.0" 127 - } 128 - }, 129 - "node_modules/@babel/helper-module-imports": { 130 - "version": "7.27.1", 131 - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", 132 - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", 133 - "dev": true, 134 - "license": "MIT", 135 - "dependencies": { 136 - "@babel/traverse": "^7.27.1", 137 - "@babel/types": "^7.27.1" 138 - }, 139 - "engines": { 140 - "node": ">=6.9.0" 141 - } 142 - }, 143 - "node_modules/@babel/helper-module-transforms": { 144 - "version": "7.27.1", 145 - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz", 146 - "integrity": "sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==", 147 - "dev": true, 148 - "license": "MIT", 149 - "dependencies": { 150 - "@babel/helper-module-imports": "^7.27.1", 151 - "@babel/helper-validator-identifier": "^7.27.1", 152 - "@babel/traverse": "^7.27.1" 153 - }, 154 - "engines": { 155 - "node": ">=6.9.0" 156 - }, 157 - "peerDependencies": { 158 - "@babel/core": "^7.0.0" 159 - } 160 - }, 161 - "node_modules/@babel/helper-plugin-utils": { 162 - "version": "7.27.1", 163 - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", 164 - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", 165 - "dev": true, 166 - "license": "MIT", 167 - "engines": { 168 - "node": ">=6.9.0" 169 - } 170 - }, 171 - "node_modules/@babel/helper-string-parser": { 172 - "version": "7.27.1", 173 - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", 174 - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", 175 - "dev": true, 176 - "license": "MIT", 177 - "engines": { 178 - "node": ">=6.9.0" 179 - } 180 - }, 181 - "node_modules/@babel/helper-validator-identifier": { 182 - "version": "7.27.1", 183 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", 184 - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", 185 - "dev": true, 186 - "license": "MIT", 187 - "engines": { 188 - "node": ">=6.9.0" 189 - } 190 - }, 191 - "node_modules/@babel/helper-validator-option": { 192 - "version": "7.27.1", 193 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", 194 - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", 195 - "dev": true, 196 - "license": "MIT", 197 - "engines": { 198 - "node": ">=6.9.0" 199 - } 200 - }, 201 - "node_modules/@babel/helpers": { 202 - "version": "7.27.1", 203 - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", 204 - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", 205 - "dev": true, 206 - "license": "MIT", 207 - "dependencies": { 208 - "@babel/template": "^7.27.1", 209 - "@babel/types": "^7.27.1" 210 - }, 211 - "engines": { 212 - "node": ">=6.9.0" 213 - } 214 - }, 215 - "node_modules/@babel/parser": { 216 - "version": "7.27.1", 217 - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz", 218 - "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==", 219 - "dev": true, 220 - "license": "MIT", 221 - "dependencies": { 222 - "@babel/types": "^7.27.1" 223 - }, 224 - "bin": { 225 - "parser": "bin/babel-parser.js" 226 - }, 227 - "engines": { 228 - "node": ">=6.0.0" 229 - } 230 - }, 231 - "node_modules/@babel/plugin-transform-react-jsx-self": { 232 - "version": "7.27.1", 233 - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", 234 - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", 235 - "dev": true, 236 - "license": "MIT", 237 - "dependencies": { 238 - "@babel/helper-plugin-utils": "^7.27.1" 239 - }, 240 - "engines": { 241 - "node": ">=6.9.0" 242 - }, 243 - "peerDependencies": { 244 - "@babel/core": "^7.0.0-0" 245 - } 246 - }, 247 - "node_modules/@babel/plugin-transform-react-jsx-source": { 248 - "version": "7.27.1", 249 - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", 250 - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", 251 - "dev": true, 252 - "license": "MIT", 253 - "dependencies": { 254 - "@babel/helper-plugin-utils": "^7.27.1" 255 - }, 256 - "engines": { 257 - "node": ">=6.9.0" 258 - }, 259 - "peerDependencies": { 260 - "@babel/core": "^7.0.0-0" 261 - } 262 - }, 263 - "node_modules/@babel/template": { 264 - "version": "7.27.1", 265 - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz", 266 - "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==", 267 - "dev": true, 268 - "license": "MIT", 269 - "dependencies": { 270 - "@babel/code-frame": "^7.27.1", 271 - "@babel/parser": "^7.27.1", 272 - "@babel/types": "^7.27.1" 273 - }, 274 - "engines": { 275 - "node": ">=6.9.0" 276 - } 277 - }, 278 - "node_modules/@babel/traverse": { 279 - "version": "7.27.1", 280 - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.1.tgz", 281 - "integrity": "sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==", 282 - "dev": true, 283 - "license": "MIT", 284 - "dependencies": { 285 - "@babel/code-frame": "^7.27.1", 286 - "@babel/generator": "^7.27.1", 287 - "@babel/parser": "^7.27.1", 288 - "@babel/template": "^7.27.1", 289 - "@babel/types": "^7.27.1", 290 - "debug": "^4.3.1", 291 - "globals": "^11.1.0" 292 - }, 293 - "engines": { 294 - "node": ">=6.9.0" 295 - } 296 - }, 297 - "node_modules/@babel/types": { 298 - "version": "7.27.1", 299 - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", 300 - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", 301 - "dev": true, 302 - "license": "MIT", 303 - "dependencies": { 304 - "@babel/helper-string-parser": "^7.27.1", 305 - "@babel/helper-validator-identifier": "^7.27.1" 306 - }, 307 - "engines": { 308 - "node": ">=6.9.0" 309 - } 310 - }, 311 - "node_modules/@esbuild/aix-ppc64": { 312 - "version": "0.25.4", 313 - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", 314 - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", 315 - "cpu": [ 316 - "ppc64" 317 - ], 318 - "dev": true, 319 - "license": "MIT", 320 - "optional": true, 321 - "os": [ 322 - "aix" 323 - ], 324 - "engines": { 325 - "node": ">=18" 326 - } 327 - }, 328 - "node_modules/@esbuild/android-arm": { 329 - "version": "0.25.4", 330 - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", 331 - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", 332 - "cpu": [ 333 - "arm" 334 - ], 335 - "dev": true, 336 - "license": "MIT", 337 - "optional": true, 338 - "os": [ 339 - "android" 340 - ], 341 - "engines": { 342 - "node": ">=18" 343 - } 344 - }, 345 - "node_modules/@esbuild/android-arm64": { 346 - "version": "0.25.4", 347 - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", 348 - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", 349 - "cpu": [ 350 - "arm64" 351 - ], 352 - "dev": true, 353 - "license": "MIT", 354 - "optional": true, 355 - "os": [ 356 - "android" 357 - ], 358 - "engines": { 359 - "node": ">=18" 360 - } 361 - }, 362 - "node_modules/@esbuild/android-x64": { 363 - "version": "0.25.4", 364 - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", 365 - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", 366 - "cpu": [ 367 - "x64" 368 - ], 369 - "dev": true, 370 - "license": "MIT", 371 - "optional": true, 372 - "os": [ 373 - "android" 374 - ], 375 - "engines": { 376 - "node": ">=18" 377 - } 378 - }, 379 - "node_modules/@esbuild/darwin-arm64": { 380 - "version": "0.25.4", 381 - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", 382 - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", 383 - "cpu": [ 384 - "arm64" 385 - ], 386 - "dev": true, 387 - "license": "MIT", 388 - "optional": true, 389 - "os": [ 390 - "darwin" 391 - ], 392 - "engines": { 393 - "node": ">=18" 394 - } 395 - }, 396 - "node_modules/@esbuild/darwin-x64": { 397 - "version": "0.25.4", 398 - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", 399 - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", 400 - "cpu": [ 401 - "x64" 402 - ], 403 - "dev": true, 404 - "license": "MIT", 405 - "optional": true, 406 - "os": [ 407 - "darwin" 408 - ], 409 - "engines": { 410 - "node": ">=18" 411 - } 412 - }, 413 - "node_modules/@esbuild/freebsd-arm64": { 414 - "version": "0.25.4", 415 - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", 416 - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", 417 - "cpu": [ 418 - "arm64" 419 - ], 420 - "dev": true, 421 - "license": "MIT", 422 - "optional": true, 423 - "os": [ 424 - "freebsd" 425 - ], 426 - "engines": { 427 - "node": ">=18" 428 - } 429 - }, 430 - "node_modules/@esbuild/freebsd-x64": { 431 - "version": "0.25.4", 432 - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", 433 - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", 434 - "cpu": [ 435 - "x64" 436 - ], 437 - "dev": true, 438 - "license": "MIT", 439 - "optional": true, 440 - "os": [ 441 - "freebsd" 442 - ], 443 - "engines": { 444 - "node": ">=18" 445 - } 446 - }, 447 - "node_modules/@esbuild/linux-arm": { 448 - "version": "0.25.4", 449 - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", 450 - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", 451 - "cpu": [ 452 - "arm" 453 - ], 454 - "dev": true, 455 - "license": "MIT", 456 - "optional": true, 457 - "os": [ 458 - "linux" 459 - ], 460 - "engines": { 461 - "node": ">=18" 462 - } 463 - }, 464 - "node_modules/@esbuild/linux-arm64": { 465 - "version": "0.25.4", 466 - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", 467 - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", 468 - "cpu": [ 469 - "arm64" 470 - ], 471 - "dev": true, 472 - "license": "MIT", 473 - "optional": true, 474 - "os": [ 475 - "linux" 476 - ], 477 - "engines": { 478 - "node": ">=18" 479 - } 480 - }, 481 - "node_modules/@esbuild/linux-ia32": { 482 - "version": "0.25.4", 483 - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", 484 - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", 485 - "cpu": [ 486 - "ia32" 487 - ], 488 - "dev": true, 489 - "license": "MIT", 490 - "optional": true, 491 - "os": [ 492 - "linux" 493 - ], 494 - "engines": { 495 - "node": ">=18" 496 - } 497 - }, 498 - "node_modules/@esbuild/linux-loong64": { 499 - "version": "0.25.4", 500 - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", 501 - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", 502 - "cpu": [ 503 - "loong64" 504 - ], 505 - "dev": true, 506 - "license": "MIT", 507 - "optional": true, 508 - "os": [ 509 - "linux" 510 - ], 511 - "engines": { 512 - "node": ">=18" 513 - } 514 - }, 515 - "node_modules/@esbuild/linux-mips64el": { 516 - "version": "0.25.4", 517 - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", 518 - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", 519 - "cpu": [ 520 - "mips64el" 521 - ], 522 - "dev": true, 523 - "license": "MIT", 524 - "optional": true, 525 - "os": [ 526 - "linux" 527 - ], 528 - "engines": { 529 - "node": ">=18" 530 - } 531 - }, 532 - "node_modules/@esbuild/linux-ppc64": { 533 - "version": "0.25.4", 534 - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", 535 - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", 536 - "cpu": [ 537 - "ppc64" 538 - ], 539 - "dev": true, 540 - "license": "MIT", 541 - "optional": true, 542 - "os": [ 543 - "linux" 544 - ], 545 - "engines": { 546 - "node": ">=18" 547 - } 548 - }, 549 - "node_modules/@esbuild/linux-riscv64": { 550 - "version": "0.25.4", 551 - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", 552 - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", 553 - "cpu": [ 554 - "riscv64" 555 - ], 556 - "dev": true, 557 - "license": "MIT", 558 - "optional": true, 559 - "os": [ 560 - "linux" 561 - ], 562 - "engines": { 563 - "node": ">=18" 564 - } 565 - }, 566 - "node_modules/@esbuild/linux-s390x": { 567 - "version": "0.25.4", 568 - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", 569 - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", 570 - "cpu": [ 571 - "s390x" 572 - ], 573 - "dev": true, 574 - "license": "MIT", 575 - "optional": true, 576 - "os": [ 577 - "linux" 578 - ], 579 - "engines": { 580 - "node": ">=18" 581 - } 582 - }, 583 - "node_modules/@esbuild/linux-x64": { 584 - "version": "0.25.4", 585 - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", 586 - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", 587 - "cpu": [ 588 - "x64" 589 - ], 590 - "dev": true, 591 - "license": "MIT", 592 - "optional": true, 593 - "os": [ 594 - "linux" 595 - ], 596 - "engines": { 597 - "node": ">=18" 598 - } 599 - }, 600 - "node_modules/@esbuild/netbsd-arm64": { 601 - "version": "0.25.4", 602 - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", 603 - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", 604 - "cpu": [ 605 - "arm64" 606 - ], 607 - "dev": true, 608 - "license": "MIT", 609 - "optional": true, 610 - "os": [ 611 - "netbsd" 612 - ], 613 - "engines": { 614 - "node": ">=18" 615 - } 616 - }, 617 - "node_modules/@esbuild/netbsd-x64": { 618 - "version": "0.25.4", 619 - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", 620 - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", 621 - "cpu": [ 622 - "x64" 623 - ], 624 - "dev": true, 625 - "license": "MIT", 626 - "optional": true, 627 - "os": [ 628 - "netbsd" 629 - ], 630 - "engines": { 631 - "node": ">=18" 632 - } 633 - }, 634 - "node_modules/@esbuild/openbsd-arm64": { 635 - "version": "0.25.4", 636 - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", 637 - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", 638 - "cpu": [ 639 - "arm64" 640 - ], 641 - "dev": true, 642 - "license": "MIT", 643 - "optional": true, 644 - "os": [ 645 - "openbsd" 646 - ], 647 - "engines": { 648 - "node": ">=18" 649 - } 650 - }, 651 - "node_modules/@esbuild/openbsd-x64": { 652 - "version": "0.25.4", 653 - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", 654 - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", 655 - "cpu": [ 656 - "x64" 657 - ], 658 - "dev": true, 659 - "license": "MIT", 660 - "optional": true, 661 - "os": [ 662 - "openbsd" 663 - ], 664 - "engines": { 665 - "node": ">=18" 666 - } 667 - }, 668 - "node_modules/@esbuild/sunos-x64": { 669 - "version": "0.25.4", 670 - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", 671 - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", 672 - "cpu": [ 673 - "x64" 674 - ], 675 - "dev": true, 676 - "license": "MIT", 677 - "optional": true, 678 - "os": [ 679 - "sunos" 680 - ], 681 - "engines": { 682 - "node": ">=18" 683 - } 684 - }, 685 - "node_modules/@esbuild/win32-arm64": { 686 - "version": "0.25.4", 687 - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", 688 - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", 689 - "cpu": [ 690 - "arm64" 691 - ], 692 - "dev": true, 693 - "license": "MIT", 694 - "optional": true, 695 - "os": [ 696 - "win32" 697 - ], 698 - "engines": { 699 - "node": ">=18" 700 - } 701 - }, 702 - "node_modules/@esbuild/win32-ia32": { 703 - "version": "0.25.4", 704 - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", 705 - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", 706 - "cpu": [ 707 - "ia32" 708 - ], 709 - "dev": true, 710 - "license": "MIT", 711 - "optional": true, 712 - "os": [ 713 - "win32" 714 - ], 715 - "engines": { 716 - "node": ">=18" 717 - } 718 - }, 719 - "node_modules/@esbuild/win32-x64": { 720 - "version": "0.25.4", 721 - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", 722 - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", 723 - "cpu": [ 724 - "x64" 725 - ], 726 - "dev": true, 727 - "license": "MIT", 728 - "optional": true, 729 - "os": [ 730 - "win32" 731 - ], 732 - "engines": { 733 - "node": ">=18" 734 - } 735 - }, 736 - "node_modules/@jridgewell/gen-mapping": { 737 - "version": "0.3.8", 738 - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", 739 - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 740 - "dev": true, 741 - "license": "MIT", 742 - "dependencies": { 743 - "@jridgewell/set-array": "^1.2.1", 744 - "@jridgewell/sourcemap-codec": "^1.4.10", 745 - "@jridgewell/trace-mapping": "^0.3.24" 746 - }, 747 - "engines": { 748 - "node": ">=6.0.0" 749 - } 750 - }, 751 - "node_modules/@jridgewell/resolve-uri": { 752 - "version": "3.1.2", 753 - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 754 - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 755 - "dev": true, 756 - "license": "MIT", 757 - "engines": { 758 - "node": ">=6.0.0" 759 - } 760 - }, 761 - "node_modules/@jridgewell/set-array": { 762 - "version": "1.2.1", 763 - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 764 - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 765 - "dev": true, 766 - "license": "MIT", 767 - "engines": { 768 - "node": ">=6.0.0" 769 - } 770 - }, 771 - "node_modules/@jridgewell/sourcemap-codec": { 772 - "version": "1.5.0", 773 - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 774 - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 775 - "dev": true, 776 - "license": "MIT" 777 - }, 778 - "node_modules/@jridgewell/trace-mapping": { 779 - "version": "0.3.25", 780 - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 781 - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 782 - "dev": true, 783 - "license": "MIT", 784 - "dependencies": { 785 - "@jridgewell/resolve-uri": "^3.1.0", 786 - "@jridgewell/sourcemap-codec": "^1.4.14" 787 - } 788 - }, 789 - "node_modules/@rollup/rollup-android-arm-eabi": { 790 - "version": "4.40.2", 791 - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.2.tgz", 792 - "integrity": "sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==", 793 - "cpu": [ 794 - "arm" 795 - ], 796 - "dev": true, 797 - "license": "MIT", 798 - "optional": true, 799 - "os": [ 800 - "android" 801 - ] 802 - }, 803 - "node_modules/@rollup/rollup-android-arm64": { 804 - "version": "4.40.2", 805 - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.2.tgz", 806 - "integrity": "sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==", 807 - "cpu": [ 808 - "arm64" 809 - ], 810 - "dev": true, 811 - "license": "MIT", 812 - "optional": true, 813 - "os": [ 814 - "android" 815 - ] 816 - }, 817 - "node_modules/@rollup/rollup-darwin-arm64": { 818 - "version": "4.40.2", 819 - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.2.tgz", 820 - "integrity": "sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==", 821 - "cpu": [ 822 - "arm64" 823 - ], 824 - "dev": true, 825 - "license": "MIT", 826 - "optional": true, 827 - "os": [ 828 - "darwin" 829 - ] 830 - }, 831 - "node_modules/@rollup/rollup-darwin-x64": { 832 - "version": "4.40.2", 833 - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.2.tgz", 834 - "integrity": "sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==", 835 - "cpu": [ 836 - "x64" 837 - ], 838 - "dev": true, 839 - "license": "MIT", 840 - "optional": true, 841 - "os": [ 842 - "darwin" 843 - ] 844 - }, 845 - "node_modules/@rollup/rollup-freebsd-arm64": { 846 - "version": "4.40.2", 847 - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.2.tgz", 848 - "integrity": "sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==", 849 - "cpu": [ 850 - "arm64" 851 - ], 852 - "dev": true, 853 - "license": "MIT", 854 - "optional": true, 855 - "os": [ 856 - "freebsd" 857 - ] 858 - }, 859 - "node_modules/@rollup/rollup-freebsd-x64": { 860 - "version": "4.40.2", 861 - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.2.tgz", 862 - "integrity": "sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==", 863 - "cpu": [ 864 - "x64" 865 - ], 866 - "dev": true, 867 - "license": "MIT", 868 - "optional": true, 869 - "os": [ 870 - "freebsd" 871 - ] 872 - }, 873 - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 874 - "version": "4.40.2", 875 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.2.tgz", 876 - "integrity": "sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==", 877 - "cpu": [ 878 - "arm" 879 - ], 880 - "dev": true, 881 - "license": "MIT", 882 - "optional": true, 883 - "os": [ 884 - "linux" 885 - ] 886 - }, 887 - "node_modules/@rollup/rollup-linux-arm-musleabihf": { 888 - "version": "4.40.2", 889 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.2.tgz", 890 - "integrity": "sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==", 891 - "cpu": [ 892 - "arm" 893 - ], 894 - "dev": true, 895 - "license": "MIT", 896 - "optional": true, 897 - "os": [ 898 - "linux" 899 - ] 900 - }, 901 - "node_modules/@rollup/rollup-linux-arm64-gnu": { 902 - "version": "4.40.2", 903 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.2.tgz", 904 - "integrity": "sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==", 905 - "cpu": [ 906 - "arm64" 907 - ], 908 - "dev": true, 909 - "license": "MIT", 910 - "optional": true, 911 - "os": [ 912 - "linux" 913 - ] 914 - }, 915 - "node_modules/@rollup/rollup-linux-arm64-musl": { 916 - "version": "4.40.2", 917 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.2.tgz", 918 - "integrity": "sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==", 919 - "cpu": [ 920 - "arm64" 921 - ], 922 - "dev": true, 923 - "license": "MIT", 924 - "optional": true, 925 - "os": [ 926 - "linux" 927 - ] 928 - }, 929 - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 930 - "version": "4.40.2", 931 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.2.tgz", 932 - "integrity": "sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==", 933 - "cpu": [ 934 - "loong64" 935 - ], 936 - "dev": true, 937 - "license": "MIT", 938 - "optional": true, 939 - "os": [ 940 - "linux" 941 - ] 942 - }, 943 - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 944 - "version": "4.40.2", 945 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.2.tgz", 946 - "integrity": "sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==", 947 - "cpu": [ 948 - "ppc64" 949 - ], 950 - "dev": true, 951 - "license": "MIT", 952 - "optional": true, 953 - "os": [ 954 - "linux" 955 - ] 956 - }, 957 - "node_modules/@rollup/rollup-linux-riscv64-gnu": { 958 - "version": "4.40.2", 959 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.2.tgz", 960 - "integrity": "sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==", 961 - "cpu": [ 962 - "riscv64" 963 - ], 964 - "dev": true, 965 - "license": "MIT", 966 - "optional": true, 967 - "os": [ 968 - "linux" 969 - ] 970 - }, 971 - "node_modules/@rollup/rollup-linux-riscv64-musl": { 972 - "version": "4.40.2", 973 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.2.tgz", 974 - "integrity": "sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==", 975 - "cpu": [ 976 - "riscv64" 977 - ], 978 - "dev": true, 979 - "license": "MIT", 980 - "optional": true, 981 - "os": [ 982 - "linux" 983 - ] 984 - }, 985 - "node_modules/@rollup/rollup-linux-s390x-gnu": { 986 - "version": "4.40.2", 987 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.2.tgz", 988 - "integrity": "sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==", 989 - "cpu": [ 990 - "s390x" 991 - ], 992 - "dev": true, 993 - "license": "MIT", 994 - "optional": true, 995 - "os": [ 996 - "linux" 997 - ] 998 - }, 999 - "node_modules/@rollup/rollup-linux-x64-gnu": { 1000 - "version": "4.40.2", 1001 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.2.tgz", 1002 - "integrity": "sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==", 1003 - "cpu": [ 1004 - "x64" 1005 - ], 1006 - "dev": true, 1007 - "license": "MIT", 1008 - "optional": true, 1009 - "os": [ 1010 - "linux" 1011 - ] 1012 - }, 1013 - "node_modules/@rollup/rollup-linux-x64-musl": { 1014 - "version": "4.40.2", 1015 - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.2.tgz", 1016 - "integrity": "sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==", 1017 - "cpu": [ 1018 - "x64" 1019 - ], 1020 - "dev": true, 1021 - "license": "MIT", 1022 - "optional": true, 1023 - "os": [ 1024 - "linux" 1025 - ] 1026 - }, 1027 - "node_modules/@rollup/rollup-win32-arm64-msvc": { 1028 - "version": "4.40.2", 1029 - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.2.tgz", 1030 - "integrity": "sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==", 1031 - "cpu": [ 1032 - "arm64" 1033 - ], 1034 - "dev": true, 1035 - "license": "MIT", 1036 - "optional": true, 1037 - "os": [ 1038 - "win32" 1039 - ] 1040 - }, 1041 - "node_modules/@rollup/rollup-win32-ia32-msvc": { 1042 - "version": "4.40.2", 1043 - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.2.tgz", 1044 - "integrity": "sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==", 1045 - "cpu": [ 1046 - "ia32" 1047 - ], 1048 - "dev": true, 1049 - "license": "MIT", 1050 - "optional": true, 1051 - "os": [ 1052 - "win32" 1053 - ] 1054 - }, 1055 - "node_modules/@rollup/rollup-win32-x64-msvc": { 1056 - "version": "4.40.2", 1057 - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.2.tgz", 1058 - "integrity": "sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==", 1059 - "cpu": [ 1060 - "x64" 1061 - ], 1062 - "dev": true, 1063 - "license": "MIT", 1064 - "optional": true, 1065 - "os": [ 1066 - "win32" 1067 - ] 1068 - }, 1069 - "node_modules/@tauri-apps/api": { 1070 - "version": "2.5.0", 1071 - "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.5.0.tgz", 1072 - "integrity": "sha512-Ldux4ip+HGAcPUmuLT8EIkk6yafl5vK0P0c0byzAKzxJh7vxelVtdPONjfgTm96PbN24yjZNESY8CKo8qniluA==", 1073 - "license": "Apache-2.0 OR MIT", 1074 - "funding": { 1075 - "type": "opencollective", 1076 - "url": "https://opencollective.com/tauri" 1077 - } 1078 - }, 1079 - "node_modules/@tauri-apps/cli": { 1080 - "version": "2.5.0", 1081 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.5.0.tgz", 1082 - "integrity": "sha512-rAtHqG0Gh/IWLjN2zTf3nZqYqbo81oMbqop56rGTjrlWk9pTTAjkqOjSL9XQLIMZ3RbeVjveCqqCA0s8RnLdMg==", 1083 - "dev": true, 1084 - "license": "Apache-2.0 OR MIT", 1085 - "bin": { 1086 - "tauri": "tauri.js" 1087 - }, 1088 - "engines": { 1089 - "node": ">= 10" 1090 - }, 1091 - "funding": { 1092 - "type": "opencollective", 1093 - "url": "https://opencollective.com/tauri" 1094 - }, 1095 - "optionalDependencies": { 1096 - "@tauri-apps/cli-darwin-arm64": "2.5.0", 1097 - "@tauri-apps/cli-darwin-x64": "2.5.0", 1098 - "@tauri-apps/cli-linux-arm-gnueabihf": "2.5.0", 1099 - "@tauri-apps/cli-linux-arm64-gnu": "2.5.0", 1100 - "@tauri-apps/cli-linux-arm64-musl": "2.5.0", 1101 - "@tauri-apps/cli-linux-riscv64-gnu": "2.5.0", 1102 - "@tauri-apps/cli-linux-x64-gnu": "2.5.0", 1103 - "@tauri-apps/cli-linux-x64-musl": "2.5.0", 1104 - "@tauri-apps/cli-win32-arm64-msvc": "2.5.0", 1105 - "@tauri-apps/cli-win32-ia32-msvc": "2.5.0", 1106 - "@tauri-apps/cli-win32-x64-msvc": "2.5.0" 1107 - } 1108 - }, 1109 - "node_modules/@tauri-apps/cli-darwin-arm64": { 1110 - "version": "2.5.0", 1111 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.5.0.tgz", 1112 - "integrity": "sha512-VuVAeTFq86dfpoBDNYAdtQVLbP0+2EKCHIIhkaxjeoPARR0sLpFHz2zs0PcFU76e+KAaxtEtAJAXGNUc8E1PzQ==", 1113 - "cpu": [ 1114 - "arm64" 1115 - ], 1116 - "dev": true, 1117 - "license": "Apache-2.0 OR MIT", 1118 - "optional": true, 1119 - "os": [ 1120 - "darwin" 1121 - ], 1122 - "engines": { 1123 - "node": ">= 10" 1124 - } 1125 - }, 1126 - "node_modules/@tauri-apps/cli-darwin-x64": { 1127 - "version": "2.5.0", 1128 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.5.0.tgz", 1129 - "integrity": "sha512-hUF01sC06cZVa8+I0/VtsHOk9BbO75rd+YdtHJ48xTdcYaQ5QIwL4yZz9OR1AKBTaUYhBam8UX9Pvd5V2/4Dpw==", 1130 - "cpu": [ 1131 - "x64" 1132 - ], 1133 - "dev": true, 1134 - "license": "Apache-2.0 OR MIT", 1135 - "optional": true, 1136 - "os": [ 1137 - "darwin" 1138 - ], 1139 - "engines": { 1140 - "node": ">= 10" 1141 - } 1142 - }, 1143 - "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { 1144 - "version": "2.5.0", 1145 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.5.0.tgz", 1146 - "integrity": "sha512-LQKqttsK252LlqYyX8R02MinUsfFcy3+NZiJwHFgi5Y3+ZUIAED9cSxJkyNtuY5KMnR4RlpgWyLv4P6akN1xhg==", 1147 - "cpu": [ 1148 - "arm" 1149 - ], 1150 - "dev": true, 1151 - "license": "Apache-2.0 OR MIT", 1152 - "optional": true, 1153 - "os": [ 1154 - "linux" 1155 - ], 1156 - "engines": { 1157 - "node": ">= 10" 1158 - } 1159 - }, 1160 - "node_modules/@tauri-apps/cli-linux-arm64-gnu": { 1161 - "version": "2.5.0", 1162 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.5.0.tgz", 1163 - "integrity": "sha512-mTQufsPcpdHg5RW0zypazMo4L55EfeE5snTzrPqbLX4yCK2qalN7+rnP8O8GT06xhp6ElSP/Ku1M2MR297SByQ==", 1164 - "cpu": [ 1165 - "arm64" 1166 - ], 1167 - "dev": true, 1168 - "license": "Apache-2.0 OR MIT", 1169 - "optional": true, 1170 - "os": [ 1171 - "linux" 1172 - ], 1173 - "engines": { 1174 - "node": ">= 10" 1175 - } 1176 - }, 1177 - "node_modules/@tauri-apps/cli-linux-arm64-musl": { 1178 - "version": "2.5.0", 1179 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.0.tgz", 1180 - "integrity": "sha512-rQO1HhRUQqyEaal5dUVOQruTRda/TD36s9kv1hTxZiFuSq3558lsTjAcUEnMAtBcBkps20sbyTJNMT0AwYIk8Q==", 1181 - "cpu": [ 1182 - "arm64" 1183 - ], 1184 - "dev": true, 1185 - "license": "Apache-2.0 OR MIT", 1186 - "optional": true, 1187 - "os": [ 1188 - "linux" 1189 - ], 1190 - "engines": { 1191 - "node": ">= 10" 1192 - } 1193 - }, 1194 - "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { 1195 - "version": "2.5.0", 1196 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.5.0.tgz", 1197 - "integrity": "sha512-7oS18FN46yDxyw1zX/AxhLAd7T3GrLj3Ai6s8hZKd9qFVzrAn36ESL7d3G05s8wEtsJf26qjXnVF4qleS3dYsA==", 1198 - "cpu": [ 1199 - "riscv64" 1200 - ], 1201 - "dev": true, 1202 - "license": "Apache-2.0 OR MIT", 1203 - "optional": true, 1204 - "os": [ 1205 - "linux" 1206 - ], 1207 - "engines": { 1208 - "node": ">= 10" 1209 - } 1210 - }, 1211 - "node_modules/@tauri-apps/cli-linux-x64-gnu": { 1212 - "version": "2.5.0", 1213 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.5.0.tgz", 1214 - "integrity": "sha512-SG5sFNL7VMmDBdIg3nO3EzNRT306HsiEQ0N90ILe3ZABYAVoPDO/ttpCO37ApLInTzrq/DLN+gOlC/mgZvLw1w==", 1215 - "cpu": [ 1216 - "x64" 1217 - ], 1218 - "dev": true, 1219 - "license": "Apache-2.0 OR MIT", 1220 - "optional": true, 1221 - "os": [ 1222 - "linux" 1223 - ], 1224 - "engines": { 1225 - "node": ">= 10" 1226 - } 1227 - }, 1228 - "node_modules/@tauri-apps/cli-linux-x64-musl": { 1229 - "version": "2.5.0", 1230 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.0.tgz", 1231 - "integrity": "sha512-QXDM8zp/6v05PNWju5ELsVwF0VH1n6b5pk2E6W/jFbbiwz80Vs1lACl9pv5kEHkrxBj+aWU/03JzGuIj2g3SkQ==", 1232 - "cpu": [ 1233 - "x64" 1234 - ], 1235 - "dev": true, 1236 - "license": "Apache-2.0 OR MIT", 1237 - "optional": true, 1238 - "os": [ 1239 - "linux" 1240 - ], 1241 - "engines": { 1242 - "node": ">= 10" 1243 - } 1244 - }, 1245 - "node_modules/@tauri-apps/cli-win32-arm64-msvc": { 1246 - "version": "2.5.0", 1247 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.5.0.tgz", 1248 - "integrity": "sha512-pFSHFK6b+o9y4Un8w0gGLwVyFTZaC3P0kQ7umRt/BLDkzD5RnQ4vBM7CF8BCU5nkwmEBUCZd7Wt3TWZxe41o6Q==", 1249 - "cpu": [ 1250 - "arm64" 1251 - ], 1252 - "dev": true, 1253 - "license": "Apache-2.0 OR MIT", 1254 - "optional": true, 1255 - "os": [ 1256 - "win32" 1257 - ], 1258 - "engines": { 1259 - "node": ">= 10" 1260 - } 1261 - }, 1262 - "node_modules/@tauri-apps/cli-win32-ia32-msvc": { 1263 - "version": "2.5.0", 1264 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.5.0.tgz", 1265 - "integrity": "sha512-EArv1IaRlogdLAQyGlKmEqZqm5RfHCUMhJoedWu7GtdbOMUfSAz6FMX2boE1PtEmNO4An+g188flLeVErrxEKg==", 1266 - "cpu": [ 1267 - "ia32" 1268 - ], 1269 - "dev": true, 1270 - "license": "Apache-2.0 OR MIT", 1271 - "optional": true, 1272 - "os": [ 1273 - "win32" 1274 - ], 1275 - "engines": { 1276 - "node": ">= 10" 1277 - } 1278 - }, 1279 - "node_modules/@tauri-apps/cli-win32-x64-msvc": { 1280 - "version": "2.5.0", 1281 - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.5.0.tgz", 1282 - "integrity": "sha512-lj43EFYbnAta8pd9JnUq87o+xRUR0odz+4rixBtTUwUgdRdwQ2V9CzFtsMu6FQKpFQ6mujRK6P1IEwhL6ADRsQ==", 1283 - "cpu": [ 1284 - "x64" 1285 - ], 1286 - "dev": true, 1287 - "license": "Apache-2.0 OR MIT", 1288 - "optional": true, 1289 - "os": [ 1290 - "win32" 1291 - ], 1292 - "engines": { 1293 - "node": ">= 10" 1294 - } 1295 - }, 1296 - "node_modules/@tauri-apps/plugin-opener": { 1297 - "version": "2.2.6", 1298 - "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.2.6.tgz", 1299 - "integrity": "sha512-bSdkuP71ZQRepPOn8BOEdBKYJQvl6+jb160QtJX/i2H9BF6ZySY/kYljh76N2Ne5fJMQRge7rlKoStYQY5Jq1w==", 1300 - "license": "MIT OR Apache-2.0", 1301 - "dependencies": { 1302 - "@tauri-apps/api": "^2.0.0" 1303 - } 1304 - }, 1305 - "node_modules/@types/babel__core": { 1306 - "version": "7.20.5", 1307 - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", 1308 - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", 1309 - "dev": true, 1310 - "license": "MIT", 1311 - "dependencies": { 1312 - "@babel/parser": "^7.20.7", 1313 - "@babel/types": "^7.20.7", 1314 - "@types/babel__generator": "*", 1315 - "@types/babel__template": "*", 1316 - "@types/babel__traverse": "*" 1317 - } 1318 - }, 1319 - "node_modules/@types/babel__generator": { 1320 - "version": "7.27.0", 1321 - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", 1322 - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", 1323 - "dev": true, 1324 - "license": "MIT", 1325 - "dependencies": { 1326 - "@babel/types": "^7.0.0" 1327 - } 1328 - }, 1329 - "node_modules/@types/babel__template": { 1330 - "version": "7.4.4", 1331 - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", 1332 - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", 1333 - "dev": true, 1334 - "license": "MIT", 1335 - "dependencies": { 1336 - "@babel/parser": "^7.1.0", 1337 - "@babel/types": "^7.0.0" 1338 - } 1339 - }, 1340 - "node_modules/@types/babel__traverse": { 1341 - "version": "7.20.7", 1342 - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", 1343 - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", 1344 - "dev": true, 1345 - "license": "MIT", 1346 - "dependencies": { 1347 - "@babel/types": "^7.20.7" 1348 - } 1349 - }, 1350 - "node_modules/@types/estree": { 1351 - "version": "1.0.7", 1352 - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", 1353 - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", 1354 - "dev": true, 1355 - "license": "MIT" 1356 - }, 1357 - "node_modules/@types/prop-types": { 1358 - "version": "15.7.14", 1359 - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", 1360 - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", 1361 - "dev": true, 1362 - "license": "MIT" 1363 - }, 1364 - "node_modules/@types/react": { 1365 - "version": "18.3.21", 1366 - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.21.tgz", 1367 - "integrity": "sha512-gXLBtmlcRJeT09/sI4PxVwyrku6SaNUj/6cMubjE6T6XdY1fDmBL7r0nX0jbSZPU/Xr0KuwLLZh6aOYY5d91Xw==", 1368 - "dev": true, 1369 - "license": "MIT", 1370 - "dependencies": { 1371 - "@types/prop-types": "*", 1372 - "csstype": "^3.0.2" 1373 - } 1374 - }, 1375 - "node_modules/@types/react-dom": { 1376 - "version": "18.3.7", 1377 - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", 1378 - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", 1379 - "dev": true, 1380 - "license": "MIT", 1381 - "peerDependencies": { 1382 - "@types/react": "^18.0.0" 1383 - } 1384 - }, 1385 - "node_modules/@vitejs/plugin-react": { 1386 - "version": "4.4.1", 1387 - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.1.tgz", 1388 - "integrity": "sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==", 1389 - "dev": true, 1390 - "license": "MIT", 1391 - "dependencies": { 1392 - "@babel/core": "^7.26.10", 1393 - "@babel/plugin-transform-react-jsx-self": "^7.25.9", 1394 - "@babel/plugin-transform-react-jsx-source": "^7.25.9", 1395 - "@types/babel__core": "^7.20.5", 1396 - "react-refresh": "^0.17.0" 1397 - }, 1398 - "engines": { 1399 - "node": "^14.18.0 || >=16.0.0" 1400 - }, 1401 - "peerDependencies": { 1402 - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" 1403 - } 1404 - }, 1405 - "node_modules/browserslist": { 1406 - "version": "4.24.5", 1407 - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz", 1408 - "integrity": "sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==", 1409 - "dev": true, 1410 - "funding": [ 1411 - { 1412 - "type": "opencollective", 1413 - "url": "https://opencollective.com/browserslist" 2 + "name": "manhunt-app", 3 + "version": "0.1.0", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "manhunt-app", 9 + "version": "0.1.0", 10 + "dependencies": { 11 + "@tauri-apps/api": "^2", 12 + "@tauri-apps/plugin-opener": "^2", 13 + "react": "^18.3.1", 14 + "react-dom": "^18.3.1" 15 + }, 16 + "devDependencies": { 17 + "@tauri-apps/cli": "^2", 18 + "@types/react": "^18.3.1", 19 + "@types/react-dom": "^18.3.1", 20 + "@vitejs/plugin-react": "^4.3.4", 21 + "typescript": "~5.6.2", 22 + "vite": "^6.0.3" 23 + } 1414 24 }, 1415 - { 1416 - "type": "tidelift", 1417 - "url": "https://tidelift.com/funding/github/npm/browserslist" 25 + "node_modules/@ampproject/remapping": { 26 + "version": "2.3.0", 27 + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", 28 + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", 29 + "dev": true, 30 + "license": "Apache-2.0", 31 + "dependencies": { 32 + "@jridgewell/gen-mapping": "^0.3.5", 33 + "@jridgewell/trace-mapping": "^0.3.24" 34 + }, 35 + "engines": { 36 + "node": ">=6.0.0" 37 + } 1418 38 }, 1419 - { 1420 - "type": "github", 1421 - "url": "https://github.com/sponsors/ai" 1422 - } 1423 - ], 1424 - "license": "MIT", 1425 - "dependencies": { 1426 - "caniuse-lite": "^1.0.30001716", 1427 - "electron-to-chromium": "^1.5.149", 1428 - "node-releases": "^2.0.19", 1429 - "update-browserslist-db": "^1.1.3" 1430 - }, 1431 - "bin": { 1432 - "browserslist": "cli.js" 1433 - }, 1434 - "engines": { 1435 - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1436 - } 1437 - }, 1438 - "node_modules/caniuse-lite": { 1439 - "version": "1.0.30001717", 1440 - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz", 1441 - "integrity": "sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==", 1442 - "dev": true, 1443 - "funding": [ 1444 - { 1445 - "type": "opencollective", 1446 - "url": "https://opencollective.com/browserslist" 39 + "node_modules/@babel/code-frame": { 40 + "version": "7.27.1", 41 + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", 42 + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", 43 + "dev": true, 44 + "license": "MIT", 45 + "dependencies": { 46 + "@babel/helper-validator-identifier": "^7.27.1", 47 + "js-tokens": "^4.0.0", 48 + "picocolors": "^1.1.1" 49 + }, 50 + "engines": { 51 + "node": ">=6.9.0" 52 + } 1447 53 }, 1448 - { 1449 - "type": "tidelift", 1450 - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 54 + "node_modules/@babel/compat-data": { 55 + "version": "7.27.5", 56 + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", 57 + "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", 58 + "dev": true, 59 + "license": "MIT", 60 + "engines": { 61 + "node": ">=6.9.0" 62 + } 1451 63 }, 1452 - { 1453 - "type": "github", 1454 - "url": "https://github.com/sponsors/ai" 1455 - } 1456 - ], 1457 - "license": "CC-BY-4.0" 1458 - }, 1459 - "node_modules/convert-source-map": { 1460 - "version": "2.0.0", 1461 - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", 1462 - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", 1463 - "dev": true, 1464 - "license": "MIT" 1465 - }, 1466 - "node_modules/csstype": { 1467 - "version": "3.1.3", 1468 - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1469 - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1470 - "dev": true, 1471 - "license": "MIT" 1472 - }, 1473 - "node_modules/debug": { 1474 - "version": "4.4.0", 1475 - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 1476 - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 1477 - "dev": true, 1478 - "license": "MIT", 1479 - "dependencies": { 1480 - "ms": "^2.1.3" 1481 - }, 1482 - "engines": { 1483 - "node": ">=6.0" 1484 - }, 1485 - "peerDependenciesMeta": { 1486 - "supports-color": { 1487 - "optional": true 1488 - } 1489 - } 1490 - }, 1491 - "node_modules/electron-to-chromium": { 1492 - "version": "1.5.150", 1493 - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.150.tgz", 1494 - "integrity": "sha512-rOOkP2ZUMx1yL4fCxXQKDHQ8ZXwisb2OycOQVKHgvB3ZI4CvehOd4y2tfnnLDieJ3Zs1RL1Dlp3cMkyIn7nnXA==", 1495 - "dev": true, 1496 - "license": "ISC" 1497 - }, 1498 - "node_modules/esbuild": { 1499 - "version": "0.25.4", 1500 - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", 1501 - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", 1502 - "dev": true, 1503 - "hasInstallScript": true, 1504 - "license": "MIT", 1505 - "bin": { 1506 - "esbuild": "bin/esbuild" 1507 - }, 1508 - "engines": { 1509 - "node": ">=18" 1510 - }, 1511 - "optionalDependencies": { 1512 - "@esbuild/aix-ppc64": "0.25.4", 1513 - "@esbuild/android-arm": "0.25.4", 1514 - "@esbuild/android-arm64": "0.25.4", 1515 - "@esbuild/android-x64": "0.25.4", 1516 - "@esbuild/darwin-arm64": "0.25.4", 1517 - "@esbuild/darwin-x64": "0.25.4", 1518 - "@esbuild/freebsd-arm64": "0.25.4", 1519 - "@esbuild/freebsd-x64": "0.25.4", 1520 - "@esbuild/linux-arm": "0.25.4", 1521 - "@esbuild/linux-arm64": "0.25.4", 1522 - "@esbuild/linux-ia32": "0.25.4", 1523 - "@esbuild/linux-loong64": "0.25.4", 1524 - "@esbuild/linux-mips64el": "0.25.4", 1525 - "@esbuild/linux-ppc64": "0.25.4", 1526 - "@esbuild/linux-riscv64": "0.25.4", 1527 - "@esbuild/linux-s390x": "0.25.4", 1528 - "@esbuild/linux-x64": "0.25.4", 1529 - "@esbuild/netbsd-arm64": "0.25.4", 1530 - "@esbuild/netbsd-x64": "0.25.4", 1531 - "@esbuild/openbsd-arm64": "0.25.4", 1532 - "@esbuild/openbsd-x64": "0.25.4", 1533 - "@esbuild/sunos-x64": "0.25.4", 1534 - "@esbuild/win32-arm64": "0.25.4", 1535 - "@esbuild/win32-ia32": "0.25.4", 1536 - "@esbuild/win32-x64": "0.25.4" 1537 - } 1538 - }, 1539 - "node_modules/escalade": { 1540 - "version": "3.2.0", 1541 - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1542 - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1543 - "dev": true, 1544 - "license": "MIT", 1545 - "engines": { 1546 - "node": ">=6" 1547 - } 1548 - }, 1549 - "node_modules/fdir": { 1550 - "version": "6.4.4", 1551 - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", 1552 - "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", 1553 - "dev": true, 1554 - "license": "MIT", 1555 - "peerDependencies": { 1556 - "picomatch": "^3 || ^4" 1557 - }, 1558 - "peerDependenciesMeta": { 1559 - "picomatch": { 1560 - "optional": true 1561 - } 1562 - } 1563 - }, 1564 - "node_modules/fsevents": { 1565 - "version": "2.3.3", 1566 - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1567 - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1568 - "dev": true, 1569 - "hasInstallScript": true, 1570 - "license": "MIT", 1571 - "optional": true, 1572 - "os": [ 1573 - "darwin" 1574 - ], 1575 - "engines": { 1576 - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1577 - } 1578 - }, 1579 - "node_modules/gensync": { 1580 - "version": "1.0.0-beta.2", 1581 - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1582 - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 1583 - "dev": true, 1584 - "license": "MIT", 1585 - "engines": { 1586 - "node": ">=6.9.0" 1587 - } 1588 - }, 1589 - "node_modules/globals": { 1590 - "version": "11.12.0", 1591 - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1592 - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 1593 - "dev": true, 1594 - "license": "MIT", 1595 - "engines": { 1596 - "node": ">=4" 1597 - } 1598 - }, 1599 - "node_modules/js-tokens": { 1600 - "version": "4.0.0", 1601 - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1602 - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1603 - "license": "MIT" 1604 - }, 1605 - "node_modules/jsesc": { 1606 - "version": "3.1.0", 1607 - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", 1608 - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", 1609 - "dev": true, 1610 - "license": "MIT", 1611 - "bin": { 1612 - "jsesc": "bin/jsesc" 1613 - }, 1614 - "engines": { 1615 - "node": ">=6" 1616 - } 1617 - }, 1618 - "node_modules/json5": { 1619 - "version": "2.2.3", 1620 - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 1621 - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 1622 - "dev": true, 1623 - "license": "MIT", 1624 - "bin": { 1625 - "json5": "lib/cli.js" 1626 - }, 1627 - "engines": { 1628 - "node": ">=6" 1629 - } 1630 - }, 1631 - "node_modules/loose-envify": { 1632 - "version": "1.4.0", 1633 - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 1634 - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 1635 - "license": "MIT", 1636 - "dependencies": { 1637 - "js-tokens": "^3.0.0 || ^4.0.0" 1638 - }, 1639 - "bin": { 1640 - "loose-envify": "cli.js" 1641 - } 1642 - }, 1643 - "node_modules/lru-cache": { 1644 - "version": "5.1.1", 1645 - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1646 - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1647 - "dev": true, 1648 - "license": "ISC", 1649 - "dependencies": { 1650 - "yallist": "^3.0.2" 1651 - } 1652 - }, 1653 - "node_modules/ms": { 1654 - "version": "2.1.3", 1655 - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1656 - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1657 - "dev": true, 1658 - "license": "MIT" 1659 - }, 1660 - "node_modules/nanoid": { 1661 - "version": "3.3.11", 1662 - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 1663 - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 1664 - "dev": true, 1665 - "funding": [ 1666 - { 1667 - "type": "github", 1668 - "url": "https://github.com/sponsors/ai" 1669 - } 1670 - ], 1671 - "license": "MIT", 1672 - "bin": { 1673 - "nanoid": "bin/nanoid.cjs" 1674 - }, 1675 - "engines": { 1676 - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1677 - } 1678 - }, 1679 - "node_modules/node-releases": { 1680 - "version": "2.0.19", 1681 - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", 1682 - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", 1683 - "dev": true, 1684 - "license": "MIT" 1685 - }, 1686 - "node_modules/picocolors": { 1687 - "version": "1.1.1", 1688 - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1689 - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1690 - "dev": true, 1691 - "license": "ISC" 1692 - }, 1693 - "node_modules/picomatch": { 1694 - "version": "4.0.2", 1695 - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1696 - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1697 - "dev": true, 1698 - "license": "MIT", 1699 - "engines": { 1700 - "node": ">=12" 1701 - }, 1702 - "funding": { 1703 - "url": "https://github.com/sponsors/jonschlinkert" 1704 - } 1705 - }, 1706 - "node_modules/postcss": { 1707 - "version": "8.5.3", 1708 - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", 1709 - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", 1710 - "dev": true, 1711 - "funding": [ 1712 - { 1713 - "type": "opencollective", 1714 - "url": "https://opencollective.com/postcss/" 64 + "node_modules/@babel/core": { 65 + "version": "7.27.4", 66 + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", 67 + "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", 68 + "dev": true, 69 + "license": "MIT", 70 + "dependencies": { 71 + "@ampproject/remapping": "^2.2.0", 72 + "@babel/code-frame": "^7.27.1", 73 + "@babel/generator": "^7.27.3", 74 + "@babel/helper-compilation-targets": "^7.27.2", 75 + "@babel/helper-module-transforms": "^7.27.3", 76 + "@babel/helpers": "^7.27.4", 77 + "@babel/parser": "^7.27.4", 78 + "@babel/template": "^7.27.2", 79 + "@babel/traverse": "^7.27.4", 80 + "@babel/types": "^7.27.3", 81 + "convert-source-map": "^2.0.0", 82 + "debug": "^4.1.0", 83 + "gensync": "^1.0.0-beta.2", 84 + "json5": "^2.2.3", 85 + "semver": "^6.3.1" 86 + }, 87 + "engines": { 88 + "node": ">=6.9.0" 89 + }, 90 + "funding": { 91 + "type": "opencollective", 92 + "url": "https://opencollective.com/babel" 93 + } 1715 94 }, 1716 - { 1717 - "type": "tidelift", 1718 - "url": "https://tidelift.com/funding/github/npm/postcss" 95 + "node_modules/@babel/generator": { 96 + "version": "7.27.5", 97 + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", 98 + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", 99 + "dev": true, 100 + "license": "MIT", 101 + "dependencies": { 102 + "@babel/parser": "^7.27.5", 103 + "@babel/types": "^7.27.3", 104 + "@jridgewell/gen-mapping": "^0.3.5", 105 + "@jridgewell/trace-mapping": "^0.3.25", 106 + "jsesc": "^3.0.2" 107 + }, 108 + "engines": { 109 + "node": ">=6.9.0" 110 + } 1719 111 }, 1720 - { 1721 - "type": "github", 1722 - "url": "https://github.com/sponsors/ai" 1723 - } 1724 - ], 1725 - "license": "MIT", 1726 - "dependencies": { 1727 - "nanoid": "^3.3.8", 1728 - "picocolors": "^1.1.1", 1729 - "source-map-js": "^1.2.1" 1730 - }, 1731 - "engines": { 1732 - "node": "^10 || ^12 || >=14" 1733 - } 1734 - }, 1735 - "node_modules/react": { 1736 - "version": "18.3.1", 1737 - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", 1738 - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", 1739 - "license": "MIT", 1740 - "dependencies": { 1741 - "loose-envify": "^1.1.0" 1742 - }, 1743 - "engines": { 1744 - "node": ">=0.10.0" 1745 - } 1746 - }, 1747 - "node_modules/react-dom": { 1748 - "version": "18.3.1", 1749 - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", 1750 - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", 1751 - "license": "MIT", 1752 - "dependencies": { 1753 - "loose-envify": "^1.1.0", 1754 - "scheduler": "^0.23.2" 1755 - }, 1756 - "peerDependencies": { 1757 - "react": "^18.3.1" 1758 - } 1759 - }, 1760 - "node_modules/react-refresh": { 1761 - "version": "0.17.0", 1762 - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", 1763 - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", 1764 - "dev": true, 1765 - "license": "MIT", 1766 - "engines": { 1767 - "node": ">=0.10.0" 1768 - } 1769 - }, 1770 - "node_modules/rollup": { 1771 - "version": "4.40.2", 1772 - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.2.tgz", 1773 - "integrity": "sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==", 1774 - "dev": true, 1775 - "license": "MIT", 1776 - "dependencies": { 1777 - "@types/estree": "1.0.7" 1778 - }, 1779 - "bin": { 1780 - "rollup": "dist/bin/rollup" 1781 - }, 1782 - "engines": { 1783 - "node": ">=18.0.0", 1784 - "npm": ">=8.0.0" 1785 - }, 1786 - "optionalDependencies": { 1787 - "@rollup/rollup-android-arm-eabi": "4.40.2", 1788 - "@rollup/rollup-android-arm64": "4.40.2", 1789 - "@rollup/rollup-darwin-arm64": "4.40.2", 1790 - "@rollup/rollup-darwin-x64": "4.40.2", 1791 - "@rollup/rollup-freebsd-arm64": "4.40.2", 1792 - "@rollup/rollup-freebsd-x64": "4.40.2", 1793 - "@rollup/rollup-linux-arm-gnueabihf": "4.40.2", 1794 - "@rollup/rollup-linux-arm-musleabihf": "4.40.2", 1795 - "@rollup/rollup-linux-arm64-gnu": "4.40.2", 1796 - "@rollup/rollup-linux-arm64-musl": "4.40.2", 1797 - "@rollup/rollup-linux-loongarch64-gnu": "4.40.2", 1798 - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.2", 1799 - "@rollup/rollup-linux-riscv64-gnu": "4.40.2", 1800 - "@rollup/rollup-linux-riscv64-musl": "4.40.2", 1801 - "@rollup/rollup-linux-s390x-gnu": "4.40.2", 1802 - "@rollup/rollup-linux-x64-gnu": "4.40.2", 1803 - "@rollup/rollup-linux-x64-musl": "4.40.2", 1804 - "@rollup/rollup-win32-arm64-msvc": "4.40.2", 1805 - "@rollup/rollup-win32-ia32-msvc": "4.40.2", 1806 - "@rollup/rollup-win32-x64-msvc": "4.40.2", 1807 - "fsevents": "~2.3.2" 1808 - } 1809 - }, 1810 - "node_modules/scheduler": { 1811 - "version": "0.23.2", 1812 - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", 1813 - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", 1814 - "license": "MIT", 1815 - "dependencies": { 1816 - "loose-envify": "^1.1.0" 1817 - } 1818 - }, 1819 - "node_modules/semver": { 1820 - "version": "6.3.1", 1821 - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 1822 - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 1823 - "dev": true, 1824 - "license": "ISC", 1825 - "bin": { 1826 - "semver": "bin/semver.js" 1827 - } 1828 - }, 1829 - "node_modules/source-map-js": { 1830 - "version": "1.2.1", 1831 - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1832 - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1833 - "dev": true, 1834 - "license": "BSD-3-Clause", 1835 - "engines": { 1836 - "node": ">=0.10.0" 1837 - } 1838 - }, 1839 - "node_modules/tinyglobby": { 1840 - "version": "0.2.13", 1841 - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", 1842 - "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", 1843 - "dev": true, 1844 - "license": "MIT", 1845 - "dependencies": { 1846 - "fdir": "^6.4.4", 1847 - "picomatch": "^4.0.2" 1848 - }, 1849 - "engines": { 1850 - "node": ">=12.0.0" 1851 - }, 1852 - "funding": { 1853 - "url": "https://github.com/sponsors/SuperchupuDev" 1854 - } 1855 - }, 1856 - "node_modules/typescript": { 1857 - "version": "5.6.3", 1858 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 1859 - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 1860 - "dev": true, 1861 - "license": "Apache-2.0", 1862 - "bin": { 1863 - "tsc": "bin/tsc", 1864 - "tsserver": "bin/tsserver" 1865 - }, 1866 - "engines": { 1867 - "node": ">=14.17" 1868 - } 1869 - }, 1870 - "node_modules/update-browserslist-db": { 1871 - "version": "1.1.3", 1872 - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", 1873 - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", 1874 - "dev": true, 1875 - "funding": [ 1876 - { 1877 - "type": "opencollective", 1878 - "url": "https://opencollective.com/browserslist" 112 + "node_modules/@babel/helper-compilation-targets": { 113 + "version": "7.27.2", 114 + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", 115 + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", 116 + "dev": true, 117 + "license": "MIT", 118 + "dependencies": { 119 + "@babel/compat-data": "^7.27.2", 120 + "@babel/helper-validator-option": "^7.27.1", 121 + "browserslist": "^4.24.0", 122 + "lru-cache": "^5.1.1", 123 + "semver": "^6.3.1" 124 + }, 125 + "engines": { 126 + "node": ">=6.9.0" 127 + } 128 + }, 129 + "node_modules/@babel/helper-module-imports": { 130 + "version": "7.27.1", 131 + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", 132 + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", 133 + "dev": true, 134 + "license": "MIT", 135 + "dependencies": { 136 + "@babel/traverse": "^7.27.1", 137 + "@babel/types": "^7.27.1" 138 + }, 139 + "engines": { 140 + "node": ">=6.9.0" 141 + } 142 + }, 143 + "node_modules/@babel/helper-module-transforms": { 144 + "version": "7.27.3", 145 + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", 146 + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", 147 + "dev": true, 148 + "license": "MIT", 149 + "dependencies": { 150 + "@babel/helper-module-imports": "^7.27.1", 151 + "@babel/helper-validator-identifier": "^7.27.1", 152 + "@babel/traverse": "^7.27.3" 153 + }, 154 + "engines": { 155 + "node": ">=6.9.0" 156 + }, 157 + "peerDependencies": { 158 + "@babel/core": "^7.0.0" 159 + } 160 + }, 161 + "node_modules/@babel/helper-plugin-utils": { 162 + "version": "7.27.1", 163 + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", 164 + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", 165 + "dev": true, 166 + "license": "MIT", 167 + "engines": { 168 + "node": ">=6.9.0" 169 + } 170 + }, 171 + "node_modules/@babel/helper-string-parser": { 172 + "version": "7.27.1", 173 + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", 174 + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", 175 + "dev": true, 176 + "license": "MIT", 177 + "engines": { 178 + "node": ">=6.9.0" 179 + } 180 + }, 181 + "node_modules/@babel/helper-validator-identifier": { 182 + "version": "7.27.1", 183 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", 184 + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", 185 + "dev": true, 186 + "license": "MIT", 187 + "engines": { 188 + "node": ">=6.9.0" 189 + } 190 + }, 191 + "node_modules/@babel/helper-validator-option": { 192 + "version": "7.27.1", 193 + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", 194 + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", 195 + "dev": true, 196 + "license": "MIT", 197 + "engines": { 198 + "node": ">=6.9.0" 199 + } 200 + }, 201 + "node_modules/@babel/helpers": { 202 + "version": "7.27.6", 203 + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", 204 + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", 205 + "dev": true, 206 + "license": "MIT", 207 + "dependencies": { 208 + "@babel/template": "^7.27.2", 209 + "@babel/types": "^7.27.6" 210 + }, 211 + "engines": { 212 + "node": ">=6.9.0" 213 + } 214 + }, 215 + "node_modules/@babel/parser": { 216 + "version": "7.27.5", 217 + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", 218 + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", 219 + "dev": true, 220 + "license": "MIT", 221 + "dependencies": { 222 + "@babel/types": "^7.27.3" 223 + }, 224 + "bin": { 225 + "parser": "bin/babel-parser.js" 226 + }, 227 + "engines": { 228 + "node": ">=6.0.0" 229 + } 230 + }, 231 + "node_modules/@babel/plugin-transform-react-jsx-self": { 232 + "version": "7.27.1", 233 + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", 234 + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", 235 + "dev": true, 236 + "license": "MIT", 237 + "dependencies": { 238 + "@babel/helper-plugin-utils": "^7.27.1" 239 + }, 240 + "engines": { 241 + "node": ">=6.9.0" 242 + }, 243 + "peerDependencies": { 244 + "@babel/core": "^7.0.0-0" 245 + } 246 + }, 247 + "node_modules/@babel/plugin-transform-react-jsx-source": { 248 + "version": "7.27.1", 249 + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", 250 + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", 251 + "dev": true, 252 + "license": "MIT", 253 + "dependencies": { 254 + "@babel/helper-plugin-utils": "^7.27.1" 255 + }, 256 + "engines": { 257 + "node": ">=6.9.0" 258 + }, 259 + "peerDependencies": { 260 + "@babel/core": "^7.0.0-0" 261 + } 262 + }, 263 + "node_modules/@babel/template": { 264 + "version": "7.27.2", 265 + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", 266 + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", 267 + "dev": true, 268 + "license": "MIT", 269 + "dependencies": { 270 + "@babel/code-frame": "^7.27.1", 271 + "@babel/parser": "^7.27.2", 272 + "@babel/types": "^7.27.1" 273 + }, 274 + "engines": { 275 + "node": ">=6.9.0" 276 + } 277 + }, 278 + "node_modules/@babel/traverse": { 279 + "version": "7.27.4", 280 + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", 281 + "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", 282 + "dev": true, 283 + "license": "MIT", 284 + "dependencies": { 285 + "@babel/code-frame": "^7.27.1", 286 + "@babel/generator": "^7.27.3", 287 + "@babel/parser": "^7.27.4", 288 + "@babel/template": "^7.27.2", 289 + "@babel/types": "^7.27.3", 290 + "debug": "^4.3.1", 291 + "globals": "^11.1.0" 292 + }, 293 + "engines": { 294 + "node": ">=6.9.0" 295 + } 296 + }, 297 + "node_modules/@babel/types": { 298 + "version": "7.27.6", 299 + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", 300 + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", 301 + "dev": true, 302 + "license": "MIT", 303 + "dependencies": { 304 + "@babel/helper-string-parser": "^7.27.1", 305 + "@babel/helper-validator-identifier": "^7.27.1" 306 + }, 307 + "engines": { 308 + "node": ">=6.9.0" 309 + } 310 + }, 311 + "node_modules/@esbuild/aix-ppc64": { 312 + "version": "0.25.5", 313 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", 314 + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", 315 + "cpu": [ 316 + "ppc64" 317 + ], 318 + "dev": true, 319 + "license": "MIT", 320 + "optional": true, 321 + "os": [ 322 + "aix" 323 + ], 324 + "engines": { 325 + "node": ">=18" 326 + } 327 + }, 328 + "node_modules/@esbuild/android-arm": { 329 + "version": "0.25.5", 330 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", 331 + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", 332 + "cpu": [ 333 + "arm" 334 + ], 335 + "dev": true, 336 + "license": "MIT", 337 + "optional": true, 338 + "os": [ 339 + "android" 340 + ], 341 + "engines": { 342 + "node": ">=18" 343 + } 344 + }, 345 + "node_modules/@esbuild/android-arm64": { 346 + "version": "0.25.5", 347 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", 348 + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", 349 + "cpu": [ 350 + "arm64" 351 + ], 352 + "dev": true, 353 + "license": "MIT", 354 + "optional": true, 355 + "os": [ 356 + "android" 357 + ], 358 + "engines": { 359 + "node": ">=18" 360 + } 361 + }, 362 + "node_modules/@esbuild/android-x64": { 363 + "version": "0.25.5", 364 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", 365 + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", 366 + "cpu": [ 367 + "x64" 368 + ], 369 + "dev": true, 370 + "license": "MIT", 371 + "optional": true, 372 + "os": [ 373 + "android" 374 + ], 375 + "engines": { 376 + "node": ">=18" 377 + } 378 + }, 379 + "node_modules/@esbuild/darwin-arm64": { 380 + "version": "0.25.5", 381 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", 382 + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", 383 + "cpu": [ 384 + "arm64" 385 + ], 386 + "dev": true, 387 + "license": "MIT", 388 + "optional": true, 389 + "os": [ 390 + "darwin" 391 + ], 392 + "engines": { 393 + "node": ">=18" 394 + } 395 + }, 396 + "node_modules/@esbuild/darwin-x64": { 397 + "version": "0.25.5", 398 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", 399 + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", 400 + "cpu": [ 401 + "x64" 402 + ], 403 + "dev": true, 404 + "license": "MIT", 405 + "optional": true, 406 + "os": [ 407 + "darwin" 408 + ], 409 + "engines": { 410 + "node": ">=18" 411 + } 412 + }, 413 + "node_modules/@esbuild/freebsd-arm64": { 414 + "version": "0.25.5", 415 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", 416 + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", 417 + "cpu": [ 418 + "arm64" 419 + ], 420 + "dev": true, 421 + "license": "MIT", 422 + "optional": true, 423 + "os": [ 424 + "freebsd" 425 + ], 426 + "engines": { 427 + "node": ">=18" 428 + } 429 + }, 430 + "node_modules/@esbuild/freebsd-x64": { 431 + "version": "0.25.5", 432 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", 433 + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", 434 + "cpu": [ 435 + "x64" 436 + ], 437 + "dev": true, 438 + "license": "MIT", 439 + "optional": true, 440 + "os": [ 441 + "freebsd" 442 + ], 443 + "engines": { 444 + "node": ">=18" 445 + } 446 + }, 447 + "node_modules/@esbuild/linux-arm": { 448 + "version": "0.25.5", 449 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", 450 + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", 451 + "cpu": [ 452 + "arm" 453 + ], 454 + "dev": true, 455 + "license": "MIT", 456 + "optional": true, 457 + "os": [ 458 + "linux" 459 + ], 460 + "engines": { 461 + "node": ">=18" 462 + } 463 + }, 464 + "node_modules/@esbuild/linux-arm64": { 465 + "version": "0.25.5", 466 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", 467 + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", 468 + "cpu": [ 469 + "arm64" 470 + ], 471 + "dev": true, 472 + "license": "MIT", 473 + "optional": true, 474 + "os": [ 475 + "linux" 476 + ], 477 + "engines": { 478 + "node": ">=18" 479 + } 480 + }, 481 + "node_modules/@esbuild/linux-ia32": { 482 + "version": "0.25.5", 483 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", 484 + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", 485 + "cpu": [ 486 + "ia32" 487 + ], 488 + "dev": true, 489 + "license": "MIT", 490 + "optional": true, 491 + "os": [ 492 + "linux" 493 + ], 494 + "engines": { 495 + "node": ">=18" 496 + } 497 + }, 498 + "node_modules/@esbuild/linux-loong64": { 499 + "version": "0.25.5", 500 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", 501 + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", 502 + "cpu": [ 503 + "loong64" 504 + ], 505 + "dev": true, 506 + "license": "MIT", 507 + "optional": true, 508 + "os": [ 509 + "linux" 510 + ], 511 + "engines": { 512 + "node": ">=18" 513 + } 514 + }, 515 + "node_modules/@esbuild/linux-mips64el": { 516 + "version": "0.25.5", 517 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", 518 + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", 519 + "cpu": [ 520 + "mips64el" 521 + ], 522 + "dev": true, 523 + "license": "MIT", 524 + "optional": true, 525 + "os": [ 526 + "linux" 527 + ], 528 + "engines": { 529 + "node": ">=18" 530 + } 531 + }, 532 + "node_modules/@esbuild/linux-ppc64": { 533 + "version": "0.25.5", 534 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", 535 + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", 536 + "cpu": [ 537 + "ppc64" 538 + ], 539 + "dev": true, 540 + "license": "MIT", 541 + "optional": true, 542 + "os": [ 543 + "linux" 544 + ], 545 + "engines": { 546 + "node": ">=18" 547 + } 548 + }, 549 + "node_modules/@esbuild/linux-riscv64": { 550 + "version": "0.25.5", 551 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", 552 + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", 553 + "cpu": [ 554 + "riscv64" 555 + ], 556 + "dev": true, 557 + "license": "MIT", 558 + "optional": true, 559 + "os": [ 560 + "linux" 561 + ], 562 + "engines": { 563 + "node": ">=18" 564 + } 565 + }, 566 + "node_modules/@esbuild/linux-s390x": { 567 + "version": "0.25.5", 568 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", 569 + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", 570 + "cpu": [ 571 + "s390x" 572 + ], 573 + "dev": true, 574 + "license": "MIT", 575 + "optional": true, 576 + "os": [ 577 + "linux" 578 + ], 579 + "engines": { 580 + "node": ">=18" 581 + } 582 + }, 583 + "node_modules/@esbuild/linux-x64": { 584 + "version": "0.25.5", 585 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", 586 + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", 587 + "cpu": [ 588 + "x64" 589 + ], 590 + "dev": true, 591 + "license": "MIT", 592 + "optional": true, 593 + "os": [ 594 + "linux" 595 + ], 596 + "engines": { 597 + "node": ">=18" 598 + } 599 + }, 600 + "node_modules/@esbuild/netbsd-arm64": { 601 + "version": "0.25.5", 602 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", 603 + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", 604 + "cpu": [ 605 + "arm64" 606 + ], 607 + "dev": true, 608 + "license": "MIT", 609 + "optional": true, 610 + "os": [ 611 + "netbsd" 612 + ], 613 + "engines": { 614 + "node": ">=18" 615 + } 616 + }, 617 + "node_modules/@esbuild/netbsd-x64": { 618 + "version": "0.25.5", 619 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", 620 + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", 621 + "cpu": [ 622 + "x64" 623 + ], 624 + "dev": true, 625 + "license": "MIT", 626 + "optional": true, 627 + "os": [ 628 + "netbsd" 629 + ], 630 + "engines": { 631 + "node": ">=18" 632 + } 633 + }, 634 + "node_modules/@esbuild/openbsd-arm64": { 635 + "version": "0.25.5", 636 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", 637 + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", 638 + "cpu": [ 639 + "arm64" 640 + ], 641 + "dev": true, 642 + "license": "MIT", 643 + "optional": true, 644 + "os": [ 645 + "openbsd" 646 + ], 647 + "engines": { 648 + "node": ">=18" 649 + } 650 + }, 651 + "node_modules/@esbuild/openbsd-x64": { 652 + "version": "0.25.5", 653 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", 654 + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", 655 + "cpu": [ 656 + "x64" 657 + ], 658 + "dev": true, 659 + "license": "MIT", 660 + "optional": true, 661 + "os": [ 662 + "openbsd" 663 + ], 664 + "engines": { 665 + "node": ">=18" 666 + } 667 + }, 668 + "node_modules/@esbuild/sunos-x64": { 669 + "version": "0.25.5", 670 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", 671 + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", 672 + "cpu": [ 673 + "x64" 674 + ], 675 + "dev": true, 676 + "license": "MIT", 677 + "optional": true, 678 + "os": [ 679 + "sunos" 680 + ], 681 + "engines": { 682 + "node": ">=18" 683 + } 684 + }, 685 + "node_modules/@esbuild/win32-arm64": { 686 + "version": "0.25.5", 687 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", 688 + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", 689 + "cpu": [ 690 + "arm64" 691 + ], 692 + "dev": true, 693 + "license": "MIT", 694 + "optional": true, 695 + "os": [ 696 + "win32" 697 + ], 698 + "engines": { 699 + "node": ">=18" 700 + } 701 + }, 702 + "node_modules/@esbuild/win32-ia32": { 703 + "version": "0.25.5", 704 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", 705 + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", 706 + "cpu": [ 707 + "ia32" 708 + ], 709 + "dev": true, 710 + "license": "MIT", 711 + "optional": true, 712 + "os": [ 713 + "win32" 714 + ], 715 + "engines": { 716 + "node": ">=18" 717 + } 718 + }, 719 + "node_modules/@esbuild/win32-x64": { 720 + "version": "0.25.5", 721 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", 722 + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", 723 + "cpu": [ 724 + "x64" 725 + ], 726 + "dev": true, 727 + "license": "MIT", 728 + "optional": true, 729 + "os": [ 730 + "win32" 731 + ], 732 + "engines": { 733 + "node": ">=18" 734 + } 735 + }, 736 + "node_modules/@jridgewell/gen-mapping": { 737 + "version": "0.3.8", 738 + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", 739 + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", 740 + "dev": true, 741 + "license": "MIT", 742 + "dependencies": { 743 + "@jridgewell/set-array": "^1.2.1", 744 + "@jridgewell/sourcemap-codec": "^1.4.10", 745 + "@jridgewell/trace-mapping": "^0.3.24" 746 + }, 747 + "engines": { 748 + "node": ">=6.0.0" 749 + } 750 + }, 751 + "node_modules/@jridgewell/resolve-uri": { 752 + "version": "3.1.2", 753 + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 754 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 755 + "dev": true, 756 + "license": "MIT", 757 + "engines": { 758 + "node": ">=6.0.0" 759 + } 760 + }, 761 + "node_modules/@jridgewell/set-array": { 762 + "version": "1.2.1", 763 + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", 764 + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", 765 + "dev": true, 766 + "license": "MIT", 767 + "engines": { 768 + "node": ">=6.0.0" 769 + } 770 + }, 771 + "node_modules/@jridgewell/sourcemap-codec": { 772 + "version": "1.5.0", 773 + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 774 + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 775 + "dev": true, 776 + "license": "MIT" 777 + }, 778 + "node_modules/@jridgewell/trace-mapping": { 779 + "version": "0.3.25", 780 + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", 781 + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", 782 + "dev": true, 783 + "license": "MIT", 784 + "dependencies": { 785 + "@jridgewell/resolve-uri": "^3.1.0", 786 + "@jridgewell/sourcemap-codec": "^1.4.14" 787 + } 788 + }, 789 + "node_modules/@rolldown/pluginutils": { 790 + "version": "1.0.0-beta.11", 791 + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz", 792 + "integrity": "sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==", 793 + "dev": true, 794 + "license": "MIT" 795 + }, 796 + "node_modules/@rollup/rollup-android-arm-eabi": { 797 + "version": "4.42.0", 798 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz", 799 + "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==", 800 + "cpu": [ 801 + "arm" 802 + ], 803 + "dev": true, 804 + "license": "MIT", 805 + "optional": true, 806 + "os": [ 807 + "android" 808 + ] 809 + }, 810 + "node_modules/@rollup/rollup-android-arm64": { 811 + "version": "4.42.0", 812 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz", 813 + "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==", 814 + "cpu": [ 815 + "arm64" 816 + ], 817 + "dev": true, 818 + "license": "MIT", 819 + "optional": true, 820 + "os": [ 821 + "android" 822 + ] 823 + }, 824 + "node_modules/@rollup/rollup-darwin-arm64": { 825 + "version": "4.42.0", 826 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz", 827 + "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==", 828 + "cpu": [ 829 + "arm64" 830 + ], 831 + "dev": true, 832 + "license": "MIT", 833 + "optional": true, 834 + "os": [ 835 + "darwin" 836 + ] 837 + }, 838 + "node_modules/@rollup/rollup-darwin-x64": { 839 + "version": "4.42.0", 840 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz", 841 + "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==", 842 + "cpu": [ 843 + "x64" 844 + ], 845 + "dev": true, 846 + "license": "MIT", 847 + "optional": true, 848 + "os": [ 849 + "darwin" 850 + ] 1879 851 }, 1880 - { 1881 - "type": "tidelift", 1882 - "url": "https://tidelift.com/funding/github/npm/browserslist" 852 + "node_modules/@rollup/rollup-freebsd-arm64": { 853 + "version": "4.42.0", 854 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz", 855 + "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==", 856 + "cpu": [ 857 + "arm64" 858 + ], 859 + "dev": true, 860 + "license": "MIT", 861 + "optional": true, 862 + "os": [ 863 + "freebsd" 864 + ] 1883 865 }, 1884 - { 1885 - "type": "github", 1886 - "url": "https://github.com/sponsors/ai" 1887 - } 1888 - ], 1889 - "license": "MIT", 1890 - "dependencies": { 1891 - "escalade": "^3.2.0", 1892 - "picocolors": "^1.1.1" 1893 - }, 1894 - "bin": { 1895 - "update-browserslist-db": "cli.js" 1896 - }, 1897 - "peerDependencies": { 1898 - "browserslist": ">= 4.21.0" 1899 - } 1900 - }, 1901 - "node_modules/vite": { 1902 - "version": "6.3.5", 1903 - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", 1904 - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", 1905 - "dev": true, 1906 - "license": "MIT", 1907 - "dependencies": { 1908 - "esbuild": "^0.25.0", 1909 - "fdir": "^6.4.4", 1910 - "picomatch": "^4.0.2", 1911 - "postcss": "^8.5.3", 1912 - "rollup": "^4.34.9", 1913 - "tinyglobby": "^0.2.13" 1914 - }, 1915 - "bin": { 1916 - "vite": "bin/vite.js" 1917 - }, 1918 - "engines": { 1919 - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 1920 - }, 1921 - "funding": { 1922 - "url": "https://github.com/vitejs/vite?sponsor=1" 1923 - }, 1924 - "optionalDependencies": { 1925 - "fsevents": "~2.3.3" 1926 - }, 1927 - "peerDependencies": { 1928 - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 1929 - "jiti": ">=1.21.0", 1930 - "less": "*", 1931 - "lightningcss": "^1.21.0", 1932 - "sass": "*", 1933 - "sass-embedded": "*", 1934 - "stylus": "*", 1935 - "sugarss": "*", 1936 - "terser": "^5.16.0", 1937 - "tsx": "^4.8.1", 1938 - "yaml": "^2.4.2" 1939 - }, 1940 - "peerDependenciesMeta": { 1941 - "@types/node": { 1942 - "optional": true 866 + "node_modules/@rollup/rollup-freebsd-x64": { 867 + "version": "4.42.0", 868 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz", 869 + "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==", 870 + "cpu": [ 871 + "x64" 872 + ], 873 + "dev": true, 874 + "license": "MIT", 875 + "optional": true, 876 + "os": [ 877 + "freebsd" 878 + ] 1943 879 }, 1944 - "jiti": { 1945 - "optional": true 880 + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 881 + "version": "4.42.0", 882 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz", 883 + "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==", 884 + "cpu": [ 885 + "arm" 886 + ], 887 + "dev": true, 888 + "license": "MIT", 889 + "optional": true, 890 + "os": [ 891 + "linux" 892 + ] 1946 893 }, 1947 - "less": { 1948 - "optional": true 894 + "node_modules/@rollup/rollup-linux-arm-musleabihf": { 895 + "version": "4.42.0", 896 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz", 897 + "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==", 898 + "cpu": [ 899 + "arm" 900 + ], 901 + "dev": true, 902 + "license": "MIT", 903 + "optional": true, 904 + "os": [ 905 + "linux" 906 + ] 1949 907 }, 1950 - "lightningcss": { 1951 - "optional": true 908 + "node_modules/@rollup/rollup-linux-arm64-gnu": { 909 + "version": "4.42.0", 910 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz", 911 + "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==", 912 + "cpu": [ 913 + "arm64" 914 + ], 915 + "dev": true, 916 + "license": "MIT", 917 + "optional": true, 918 + "os": [ 919 + "linux" 920 + ] 1952 921 }, 1953 - "sass": { 1954 - "optional": true 922 + "node_modules/@rollup/rollup-linux-arm64-musl": { 923 + "version": "4.42.0", 924 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz", 925 + "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==", 926 + "cpu": [ 927 + "arm64" 928 + ], 929 + "dev": true, 930 + "license": "MIT", 931 + "optional": true, 932 + "os": [ 933 + "linux" 934 + ] 1955 935 }, 1956 - "sass-embedded": { 1957 - "optional": true 936 + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 937 + "version": "4.42.0", 938 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz", 939 + "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==", 940 + "cpu": [ 941 + "loong64" 942 + ], 943 + "dev": true, 944 + "license": "MIT", 945 + "optional": true, 946 + "os": [ 947 + "linux" 948 + ] 1958 949 }, 1959 - "stylus": { 1960 - "optional": true 950 + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 951 + "version": "4.42.0", 952 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz", 953 + "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==", 954 + "cpu": [ 955 + "ppc64" 956 + ], 957 + "dev": true, 958 + "license": "MIT", 959 + "optional": true, 960 + "os": [ 961 + "linux" 962 + ] 1961 963 }, 1962 - "sugarss": { 1963 - "optional": true 964 + "node_modules/@rollup/rollup-linux-riscv64-gnu": { 965 + "version": "4.42.0", 966 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz", 967 + "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==", 968 + "cpu": [ 969 + "riscv64" 970 + ], 971 + "dev": true, 972 + "license": "MIT", 973 + "optional": true, 974 + "os": [ 975 + "linux" 976 + ] 1964 977 }, 1965 - "terser": { 1966 - "optional": true 978 + "node_modules/@rollup/rollup-linux-riscv64-musl": { 979 + "version": "4.42.0", 980 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz", 981 + "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==", 982 + "cpu": [ 983 + "riscv64" 984 + ], 985 + "dev": true, 986 + "license": "MIT", 987 + "optional": true, 988 + "os": [ 989 + "linux" 990 + ] 1967 991 }, 1968 - "tsx": { 1969 - "optional": true 992 + "node_modules/@rollup/rollup-linux-s390x-gnu": { 993 + "version": "4.42.0", 994 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz", 995 + "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==", 996 + "cpu": [ 997 + "s390x" 998 + ], 999 + "dev": true, 1000 + "license": "MIT", 1001 + "optional": true, 1002 + "os": [ 1003 + "linux" 1004 + ] 1970 1005 }, 1971 - "yaml": { 1972 - "optional": true 1006 + "node_modules/@rollup/rollup-linux-x64-gnu": { 1007 + "version": "4.42.0", 1008 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz", 1009 + "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==", 1010 + "cpu": [ 1011 + "x64" 1012 + ], 1013 + "dev": true, 1014 + "license": "MIT", 1015 + "optional": true, 1016 + "os": [ 1017 + "linux" 1018 + ] 1019 + }, 1020 + "node_modules/@rollup/rollup-linux-x64-musl": { 1021 + "version": "4.42.0", 1022 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz", 1023 + "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==", 1024 + "cpu": [ 1025 + "x64" 1026 + ], 1027 + "dev": true, 1028 + "license": "MIT", 1029 + "optional": true, 1030 + "os": [ 1031 + "linux" 1032 + ] 1033 + }, 1034 + "node_modules/@rollup/rollup-win32-arm64-msvc": { 1035 + "version": "4.42.0", 1036 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz", 1037 + "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==", 1038 + "cpu": [ 1039 + "arm64" 1040 + ], 1041 + "dev": true, 1042 + "license": "MIT", 1043 + "optional": true, 1044 + "os": [ 1045 + "win32" 1046 + ] 1047 + }, 1048 + "node_modules/@rollup/rollup-win32-ia32-msvc": { 1049 + "version": "4.42.0", 1050 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz", 1051 + "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==", 1052 + "cpu": [ 1053 + "ia32" 1054 + ], 1055 + "dev": true, 1056 + "license": "MIT", 1057 + "optional": true, 1058 + "os": [ 1059 + "win32" 1060 + ] 1061 + }, 1062 + "node_modules/@rollup/rollup-win32-x64-msvc": { 1063 + "version": "4.42.0", 1064 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz", 1065 + "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==", 1066 + "cpu": [ 1067 + "x64" 1068 + ], 1069 + "dev": true, 1070 + "license": "MIT", 1071 + "optional": true, 1072 + "os": [ 1073 + "win32" 1074 + ] 1075 + }, 1076 + "node_modules/@tauri-apps/api": { 1077 + "version": "2.5.0", 1078 + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.5.0.tgz", 1079 + "integrity": "sha512-Ldux4ip+HGAcPUmuLT8EIkk6yafl5vK0P0c0byzAKzxJh7vxelVtdPONjfgTm96PbN24yjZNESY8CKo8qniluA==", 1080 + "license": "Apache-2.0 OR MIT", 1081 + "funding": { 1082 + "type": "opencollective", 1083 + "url": "https://opencollective.com/tauri" 1084 + } 1085 + }, 1086 + "node_modules/@tauri-apps/cli": { 1087 + "version": "2.5.0", 1088 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.5.0.tgz", 1089 + "integrity": "sha512-rAtHqG0Gh/IWLjN2zTf3nZqYqbo81oMbqop56rGTjrlWk9pTTAjkqOjSL9XQLIMZ3RbeVjveCqqCA0s8RnLdMg==", 1090 + "dev": true, 1091 + "license": "Apache-2.0 OR MIT", 1092 + "bin": { 1093 + "tauri": "tauri.js" 1094 + }, 1095 + "engines": { 1096 + "node": ">= 10" 1097 + }, 1098 + "funding": { 1099 + "type": "opencollective", 1100 + "url": "https://opencollective.com/tauri" 1101 + }, 1102 + "optionalDependencies": { 1103 + "@tauri-apps/cli-darwin-arm64": "2.5.0", 1104 + "@tauri-apps/cli-darwin-x64": "2.5.0", 1105 + "@tauri-apps/cli-linux-arm-gnueabihf": "2.5.0", 1106 + "@tauri-apps/cli-linux-arm64-gnu": "2.5.0", 1107 + "@tauri-apps/cli-linux-arm64-musl": "2.5.0", 1108 + "@tauri-apps/cli-linux-riscv64-gnu": "2.5.0", 1109 + "@tauri-apps/cli-linux-x64-gnu": "2.5.0", 1110 + "@tauri-apps/cli-linux-x64-musl": "2.5.0", 1111 + "@tauri-apps/cli-win32-arm64-msvc": "2.5.0", 1112 + "@tauri-apps/cli-win32-ia32-msvc": "2.5.0", 1113 + "@tauri-apps/cli-win32-x64-msvc": "2.5.0" 1114 + } 1115 + }, 1116 + "node_modules/@tauri-apps/cli-darwin-arm64": { 1117 + "version": "2.5.0", 1118 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.5.0.tgz", 1119 + "integrity": "sha512-VuVAeTFq86dfpoBDNYAdtQVLbP0+2EKCHIIhkaxjeoPARR0sLpFHz2zs0PcFU76e+KAaxtEtAJAXGNUc8E1PzQ==", 1120 + "cpu": [ 1121 + "arm64" 1122 + ], 1123 + "dev": true, 1124 + "license": "Apache-2.0 OR MIT", 1125 + "optional": true, 1126 + "os": [ 1127 + "darwin" 1128 + ], 1129 + "engines": { 1130 + "node": ">= 10" 1131 + } 1132 + }, 1133 + "node_modules/@tauri-apps/cli-darwin-x64": { 1134 + "version": "2.5.0", 1135 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.5.0.tgz", 1136 + "integrity": "sha512-hUF01sC06cZVa8+I0/VtsHOk9BbO75rd+YdtHJ48xTdcYaQ5QIwL4yZz9OR1AKBTaUYhBam8UX9Pvd5V2/4Dpw==", 1137 + "cpu": [ 1138 + "x64" 1139 + ], 1140 + "dev": true, 1141 + "license": "Apache-2.0 OR MIT", 1142 + "optional": true, 1143 + "os": [ 1144 + "darwin" 1145 + ], 1146 + "engines": { 1147 + "node": ">= 10" 1148 + } 1149 + }, 1150 + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { 1151 + "version": "2.5.0", 1152 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.5.0.tgz", 1153 + "integrity": "sha512-LQKqttsK252LlqYyX8R02MinUsfFcy3+NZiJwHFgi5Y3+ZUIAED9cSxJkyNtuY5KMnR4RlpgWyLv4P6akN1xhg==", 1154 + "cpu": [ 1155 + "arm" 1156 + ], 1157 + "dev": true, 1158 + "license": "Apache-2.0 OR MIT", 1159 + "optional": true, 1160 + "os": [ 1161 + "linux" 1162 + ], 1163 + "engines": { 1164 + "node": ">= 10" 1165 + } 1166 + }, 1167 + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { 1168 + "version": "2.5.0", 1169 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.5.0.tgz", 1170 + "integrity": "sha512-mTQufsPcpdHg5RW0zypazMo4L55EfeE5snTzrPqbLX4yCK2qalN7+rnP8O8GT06xhp6ElSP/Ku1M2MR297SByQ==", 1171 + "cpu": [ 1172 + "arm64" 1173 + ], 1174 + "dev": true, 1175 + "license": "Apache-2.0 OR MIT", 1176 + "optional": true, 1177 + "os": [ 1178 + "linux" 1179 + ], 1180 + "engines": { 1181 + "node": ">= 10" 1182 + } 1183 + }, 1184 + "node_modules/@tauri-apps/cli-linux-arm64-musl": { 1185 + "version": "2.5.0", 1186 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.0.tgz", 1187 + "integrity": "sha512-rQO1HhRUQqyEaal5dUVOQruTRda/TD36s9kv1hTxZiFuSq3558lsTjAcUEnMAtBcBkps20sbyTJNMT0AwYIk8Q==", 1188 + "cpu": [ 1189 + "arm64" 1190 + ], 1191 + "dev": true, 1192 + "license": "Apache-2.0 OR MIT", 1193 + "optional": true, 1194 + "os": [ 1195 + "linux" 1196 + ], 1197 + "engines": { 1198 + "node": ">= 10" 1199 + } 1200 + }, 1201 + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { 1202 + "version": "2.5.0", 1203 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.5.0.tgz", 1204 + "integrity": "sha512-7oS18FN46yDxyw1zX/AxhLAd7T3GrLj3Ai6s8hZKd9qFVzrAn36ESL7d3G05s8wEtsJf26qjXnVF4qleS3dYsA==", 1205 + "cpu": [ 1206 + "riscv64" 1207 + ], 1208 + "dev": true, 1209 + "license": "Apache-2.0 OR MIT", 1210 + "optional": true, 1211 + "os": [ 1212 + "linux" 1213 + ], 1214 + "engines": { 1215 + "node": ">= 10" 1216 + } 1217 + }, 1218 + "node_modules/@tauri-apps/cli-linux-x64-gnu": { 1219 + "version": "2.5.0", 1220 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.5.0.tgz", 1221 + "integrity": "sha512-SG5sFNL7VMmDBdIg3nO3EzNRT306HsiEQ0N90ILe3ZABYAVoPDO/ttpCO37ApLInTzrq/DLN+gOlC/mgZvLw1w==", 1222 + "cpu": [ 1223 + "x64" 1224 + ], 1225 + "dev": true, 1226 + "license": "Apache-2.0 OR MIT", 1227 + "optional": true, 1228 + "os": [ 1229 + "linux" 1230 + ], 1231 + "engines": { 1232 + "node": ">= 10" 1233 + } 1234 + }, 1235 + "node_modules/@tauri-apps/cli-linux-x64-musl": { 1236 + "version": "2.5.0", 1237 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.0.tgz", 1238 + "integrity": "sha512-QXDM8zp/6v05PNWju5ELsVwF0VH1n6b5pk2E6W/jFbbiwz80Vs1lACl9pv5kEHkrxBj+aWU/03JzGuIj2g3SkQ==", 1239 + "cpu": [ 1240 + "x64" 1241 + ], 1242 + "dev": true, 1243 + "license": "Apache-2.0 OR MIT", 1244 + "optional": true, 1245 + "os": [ 1246 + "linux" 1247 + ], 1248 + "engines": { 1249 + "node": ">= 10" 1250 + } 1251 + }, 1252 + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { 1253 + "version": "2.5.0", 1254 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.5.0.tgz", 1255 + "integrity": "sha512-pFSHFK6b+o9y4Un8w0gGLwVyFTZaC3P0kQ7umRt/BLDkzD5RnQ4vBM7CF8BCU5nkwmEBUCZd7Wt3TWZxe41o6Q==", 1256 + "cpu": [ 1257 + "arm64" 1258 + ], 1259 + "dev": true, 1260 + "license": "Apache-2.0 OR MIT", 1261 + "optional": true, 1262 + "os": [ 1263 + "win32" 1264 + ], 1265 + "engines": { 1266 + "node": ">= 10" 1267 + } 1268 + }, 1269 + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { 1270 + "version": "2.5.0", 1271 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.5.0.tgz", 1272 + "integrity": "sha512-EArv1IaRlogdLAQyGlKmEqZqm5RfHCUMhJoedWu7GtdbOMUfSAz6FMX2boE1PtEmNO4An+g188flLeVErrxEKg==", 1273 + "cpu": [ 1274 + "ia32" 1275 + ], 1276 + "dev": true, 1277 + "license": "Apache-2.0 OR MIT", 1278 + "optional": true, 1279 + "os": [ 1280 + "win32" 1281 + ], 1282 + "engines": { 1283 + "node": ">= 10" 1284 + } 1285 + }, 1286 + "node_modules/@tauri-apps/cli-win32-x64-msvc": { 1287 + "version": "2.5.0", 1288 + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.5.0.tgz", 1289 + "integrity": "sha512-lj43EFYbnAta8pd9JnUq87o+xRUR0odz+4rixBtTUwUgdRdwQ2V9CzFtsMu6FQKpFQ6mujRK6P1IEwhL6ADRsQ==", 1290 + "cpu": [ 1291 + "x64" 1292 + ], 1293 + "dev": true, 1294 + "license": "Apache-2.0 OR MIT", 1295 + "optional": true, 1296 + "os": [ 1297 + "win32" 1298 + ], 1299 + "engines": { 1300 + "node": ">= 10" 1301 + } 1302 + }, 1303 + "node_modules/@tauri-apps/plugin-opener": { 1304 + "version": "2.2.7", 1305 + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.2.7.tgz", 1306 + "integrity": "sha512-uduEyvOdjpPOEeDRrhwlCspG/f9EQalHumWBtLBnp3fRp++fKGLqDOyUhSIn7PzX45b/rKep//ZQSAQoIxobLA==", 1307 + "license": "MIT OR Apache-2.0", 1308 + "dependencies": { 1309 + "@tauri-apps/api": "^2.0.0" 1310 + } 1311 + }, 1312 + "node_modules/@types/babel__core": { 1313 + "version": "7.20.5", 1314 + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", 1315 + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", 1316 + "dev": true, 1317 + "license": "MIT", 1318 + "dependencies": { 1319 + "@babel/parser": "^7.20.7", 1320 + "@babel/types": "^7.20.7", 1321 + "@types/babel__generator": "*", 1322 + "@types/babel__template": "*", 1323 + "@types/babel__traverse": "*" 1324 + } 1325 + }, 1326 + "node_modules/@types/babel__generator": { 1327 + "version": "7.27.0", 1328 + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", 1329 + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", 1330 + "dev": true, 1331 + "license": "MIT", 1332 + "dependencies": { 1333 + "@babel/types": "^7.0.0" 1334 + } 1335 + }, 1336 + "node_modules/@types/babel__template": { 1337 + "version": "7.4.4", 1338 + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", 1339 + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", 1340 + "dev": true, 1341 + "license": "MIT", 1342 + "dependencies": { 1343 + "@babel/parser": "^7.1.0", 1344 + "@babel/types": "^7.0.0" 1345 + } 1346 + }, 1347 + "node_modules/@types/babel__traverse": { 1348 + "version": "7.20.7", 1349 + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", 1350 + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", 1351 + "dev": true, 1352 + "license": "MIT", 1353 + "dependencies": { 1354 + "@babel/types": "^7.20.7" 1355 + } 1356 + }, 1357 + "node_modules/@types/estree": { 1358 + "version": "1.0.7", 1359 + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", 1360 + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", 1361 + "dev": true, 1362 + "license": "MIT" 1363 + }, 1364 + "node_modules/@types/prop-types": { 1365 + "version": "15.7.15", 1366 + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", 1367 + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", 1368 + "dev": true, 1369 + "license": "MIT" 1370 + }, 1371 + "node_modules/@types/react": { 1372 + "version": "18.3.23", 1373 + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", 1374 + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", 1375 + "dev": true, 1376 + "license": "MIT", 1377 + "dependencies": { 1378 + "@types/prop-types": "*", 1379 + "csstype": "^3.0.2" 1380 + } 1381 + }, 1382 + "node_modules/@types/react-dom": { 1383 + "version": "18.3.7", 1384 + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", 1385 + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", 1386 + "dev": true, 1387 + "license": "MIT", 1388 + "peerDependencies": { 1389 + "@types/react": "^18.0.0" 1390 + } 1391 + }, 1392 + "node_modules/@vitejs/plugin-react": { 1393 + "version": "4.5.2", 1394 + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.5.2.tgz", 1395 + "integrity": "sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==", 1396 + "dev": true, 1397 + "license": "MIT", 1398 + "dependencies": { 1399 + "@babel/core": "^7.27.4", 1400 + "@babel/plugin-transform-react-jsx-self": "^7.27.1", 1401 + "@babel/plugin-transform-react-jsx-source": "^7.27.1", 1402 + "@rolldown/pluginutils": "1.0.0-beta.11", 1403 + "@types/babel__core": "^7.20.5", 1404 + "react-refresh": "^0.17.0" 1405 + }, 1406 + "engines": { 1407 + "node": "^14.18.0 || >=16.0.0" 1408 + }, 1409 + "peerDependencies": { 1410 + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" 1411 + } 1412 + }, 1413 + "node_modules/browserslist": { 1414 + "version": "4.25.0", 1415 + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", 1416 + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", 1417 + "dev": true, 1418 + "funding": [ 1419 + { 1420 + "type": "opencollective", 1421 + "url": "https://opencollective.com/browserslist" 1422 + }, 1423 + { 1424 + "type": "tidelift", 1425 + "url": "https://tidelift.com/funding/github/npm/browserslist" 1426 + }, 1427 + { 1428 + "type": "github", 1429 + "url": "https://github.com/sponsors/ai" 1430 + } 1431 + ], 1432 + "license": "MIT", 1433 + "dependencies": { 1434 + "caniuse-lite": "^1.0.30001718", 1435 + "electron-to-chromium": "^1.5.160", 1436 + "node-releases": "^2.0.19", 1437 + "update-browserslist-db": "^1.1.3" 1438 + }, 1439 + "bin": { 1440 + "browserslist": "cli.js" 1441 + }, 1442 + "engines": { 1443 + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1444 + } 1445 + }, 1446 + "node_modules/caniuse-lite": { 1447 + "version": "1.0.30001721", 1448 + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz", 1449 + "integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==", 1450 + "dev": true, 1451 + "funding": [ 1452 + { 1453 + "type": "opencollective", 1454 + "url": "https://opencollective.com/browserslist" 1455 + }, 1456 + { 1457 + "type": "tidelift", 1458 + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 1459 + }, 1460 + { 1461 + "type": "github", 1462 + "url": "https://github.com/sponsors/ai" 1463 + } 1464 + ], 1465 + "license": "CC-BY-4.0" 1466 + }, 1467 + "node_modules/convert-source-map": { 1468 + "version": "2.0.0", 1469 + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", 1470 + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", 1471 + "dev": true, 1472 + "license": "MIT" 1473 + }, 1474 + "node_modules/csstype": { 1475 + "version": "3.1.3", 1476 + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1477 + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1478 + "dev": true, 1479 + "license": "MIT" 1480 + }, 1481 + "node_modules/debug": { 1482 + "version": "4.4.1", 1483 + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", 1484 + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", 1485 + "dev": true, 1486 + "license": "MIT", 1487 + "dependencies": { 1488 + "ms": "^2.1.3" 1489 + }, 1490 + "engines": { 1491 + "node": ">=6.0" 1492 + }, 1493 + "peerDependenciesMeta": { 1494 + "supports-color": { 1495 + "optional": true 1496 + } 1497 + } 1498 + }, 1499 + "node_modules/electron-to-chromium": { 1500 + "version": "1.5.166", 1501 + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.166.tgz", 1502 + "integrity": "sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==", 1503 + "dev": true, 1504 + "license": "ISC" 1505 + }, 1506 + "node_modules/esbuild": { 1507 + "version": "0.25.5", 1508 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", 1509 + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", 1510 + "dev": true, 1511 + "hasInstallScript": true, 1512 + "license": "MIT", 1513 + "bin": { 1514 + "esbuild": "bin/esbuild" 1515 + }, 1516 + "engines": { 1517 + "node": ">=18" 1518 + }, 1519 + "optionalDependencies": { 1520 + "@esbuild/aix-ppc64": "0.25.5", 1521 + "@esbuild/android-arm": "0.25.5", 1522 + "@esbuild/android-arm64": "0.25.5", 1523 + "@esbuild/android-x64": "0.25.5", 1524 + "@esbuild/darwin-arm64": "0.25.5", 1525 + "@esbuild/darwin-x64": "0.25.5", 1526 + "@esbuild/freebsd-arm64": "0.25.5", 1527 + "@esbuild/freebsd-x64": "0.25.5", 1528 + "@esbuild/linux-arm": "0.25.5", 1529 + "@esbuild/linux-arm64": "0.25.5", 1530 + "@esbuild/linux-ia32": "0.25.5", 1531 + "@esbuild/linux-loong64": "0.25.5", 1532 + "@esbuild/linux-mips64el": "0.25.5", 1533 + "@esbuild/linux-ppc64": "0.25.5", 1534 + "@esbuild/linux-riscv64": "0.25.5", 1535 + "@esbuild/linux-s390x": "0.25.5", 1536 + "@esbuild/linux-x64": "0.25.5", 1537 + "@esbuild/netbsd-arm64": "0.25.5", 1538 + "@esbuild/netbsd-x64": "0.25.5", 1539 + "@esbuild/openbsd-arm64": "0.25.5", 1540 + "@esbuild/openbsd-x64": "0.25.5", 1541 + "@esbuild/sunos-x64": "0.25.5", 1542 + "@esbuild/win32-arm64": "0.25.5", 1543 + "@esbuild/win32-ia32": "0.25.5", 1544 + "@esbuild/win32-x64": "0.25.5" 1545 + } 1546 + }, 1547 + "node_modules/escalade": { 1548 + "version": "3.2.0", 1549 + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1550 + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1551 + "dev": true, 1552 + "license": "MIT", 1553 + "engines": { 1554 + "node": ">=6" 1555 + } 1556 + }, 1557 + "node_modules/fdir": { 1558 + "version": "6.4.6", 1559 + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", 1560 + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", 1561 + "dev": true, 1562 + "license": "MIT", 1563 + "peerDependencies": { 1564 + "picomatch": "^3 || ^4" 1565 + }, 1566 + "peerDependenciesMeta": { 1567 + "picomatch": { 1568 + "optional": true 1569 + } 1570 + } 1571 + }, 1572 + "node_modules/fsevents": { 1573 + "version": "2.3.3", 1574 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1575 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1576 + "dev": true, 1577 + "hasInstallScript": true, 1578 + "license": "MIT", 1579 + "optional": true, 1580 + "os": [ 1581 + "darwin" 1582 + ], 1583 + "engines": { 1584 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1585 + } 1586 + }, 1587 + "node_modules/gensync": { 1588 + "version": "1.0.0-beta.2", 1589 + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1590 + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 1591 + "dev": true, 1592 + "license": "MIT", 1593 + "engines": { 1594 + "node": ">=6.9.0" 1595 + } 1596 + }, 1597 + "node_modules/globals": { 1598 + "version": "11.12.0", 1599 + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1600 + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 1601 + "dev": true, 1602 + "license": "MIT", 1603 + "engines": { 1604 + "node": ">=4" 1605 + } 1606 + }, 1607 + "node_modules/js-tokens": { 1608 + "version": "4.0.0", 1609 + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1610 + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1611 + "license": "MIT" 1612 + }, 1613 + "node_modules/jsesc": { 1614 + "version": "3.1.0", 1615 + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", 1616 + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", 1617 + "dev": true, 1618 + "license": "MIT", 1619 + "bin": { 1620 + "jsesc": "bin/jsesc" 1621 + }, 1622 + "engines": { 1623 + "node": ">=6" 1624 + } 1625 + }, 1626 + "node_modules/json5": { 1627 + "version": "2.2.3", 1628 + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 1629 + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 1630 + "dev": true, 1631 + "license": "MIT", 1632 + "bin": { 1633 + "json5": "lib/cli.js" 1634 + }, 1635 + "engines": { 1636 + "node": ">=6" 1637 + } 1638 + }, 1639 + "node_modules/loose-envify": { 1640 + "version": "1.4.0", 1641 + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 1642 + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 1643 + "license": "MIT", 1644 + "dependencies": { 1645 + "js-tokens": "^3.0.0 || ^4.0.0" 1646 + }, 1647 + "bin": { 1648 + "loose-envify": "cli.js" 1649 + } 1650 + }, 1651 + "node_modules/lru-cache": { 1652 + "version": "5.1.1", 1653 + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1654 + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1655 + "dev": true, 1656 + "license": "ISC", 1657 + "dependencies": { 1658 + "yallist": "^3.0.2" 1659 + } 1660 + }, 1661 + "node_modules/ms": { 1662 + "version": "2.1.3", 1663 + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1664 + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1665 + "dev": true, 1666 + "license": "MIT" 1667 + }, 1668 + "node_modules/nanoid": { 1669 + "version": "3.3.11", 1670 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 1671 + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 1672 + "dev": true, 1673 + "funding": [ 1674 + { 1675 + "type": "github", 1676 + "url": "https://github.com/sponsors/ai" 1677 + } 1678 + ], 1679 + "license": "MIT", 1680 + "bin": { 1681 + "nanoid": "bin/nanoid.cjs" 1682 + }, 1683 + "engines": { 1684 + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1685 + } 1686 + }, 1687 + "node_modules/node-releases": { 1688 + "version": "2.0.19", 1689 + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", 1690 + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", 1691 + "dev": true, 1692 + "license": "MIT" 1693 + }, 1694 + "node_modules/picocolors": { 1695 + "version": "1.1.1", 1696 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1697 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1698 + "dev": true, 1699 + "license": "ISC" 1700 + }, 1701 + "node_modules/picomatch": { 1702 + "version": "4.0.2", 1703 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", 1704 + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", 1705 + "dev": true, 1706 + "license": "MIT", 1707 + "engines": { 1708 + "node": ">=12" 1709 + }, 1710 + "funding": { 1711 + "url": "https://github.com/sponsors/jonschlinkert" 1712 + } 1713 + }, 1714 + "node_modules/postcss": { 1715 + "version": "8.5.4", 1716 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", 1717 + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", 1718 + "dev": true, 1719 + "funding": [ 1720 + { 1721 + "type": "opencollective", 1722 + "url": "https://opencollective.com/postcss/" 1723 + }, 1724 + { 1725 + "type": "tidelift", 1726 + "url": "https://tidelift.com/funding/github/npm/postcss" 1727 + }, 1728 + { 1729 + "type": "github", 1730 + "url": "https://github.com/sponsors/ai" 1731 + } 1732 + ], 1733 + "license": "MIT", 1734 + "dependencies": { 1735 + "nanoid": "^3.3.11", 1736 + "picocolors": "^1.1.1", 1737 + "source-map-js": "^1.2.1" 1738 + }, 1739 + "engines": { 1740 + "node": "^10 || ^12 || >=14" 1741 + } 1742 + }, 1743 + "node_modules/react": { 1744 + "version": "18.3.1", 1745 + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", 1746 + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", 1747 + "license": "MIT", 1748 + "dependencies": { 1749 + "loose-envify": "^1.1.0" 1750 + }, 1751 + "engines": { 1752 + "node": ">=0.10.0" 1753 + } 1754 + }, 1755 + "node_modules/react-dom": { 1756 + "version": "18.3.1", 1757 + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", 1758 + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", 1759 + "license": "MIT", 1760 + "dependencies": { 1761 + "loose-envify": "^1.1.0", 1762 + "scheduler": "^0.23.2" 1763 + }, 1764 + "peerDependencies": { 1765 + "react": "^18.3.1" 1766 + } 1767 + }, 1768 + "node_modules/react-refresh": { 1769 + "version": "0.17.0", 1770 + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", 1771 + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", 1772 + "dev": true, 1773 + "license": "MIT", 1774 + "engines": { 1775 + "node": ">=0.10.0" 1776 + } 1777 + }, 1778 + "node_modules/rollup": { 1779 + "version": "4.42.0", 1780 + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz", 1781 + "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==", 1782 + "dev": true, 1783 + "license": "MIT", 1784 + "dependencies": { 1785 + "@types/estree": "1.0.7" 1786 + }, 1787 + "bin": { 1788 + "rollup": "dist/bin/rollup" 1789 + }, 1790 + "engines": { 1791 + "node": ">=18.0.0", 1792 + "npm": ">=8.0.0" 1793 + }, 1794 + "optionalDependencies": { 1795 + "@rollup/rollup-android-arm-eabi": "4.42.0", 1796 + "@rollup/rollup-android-arm64": "4.42.0", 1797 + "@rollup/rollup-darwin-arm64": "4.42.0", 1798 + "@rollup/rollup-darwin-x64": "4.42.0", 1799 + "@rollup/rollup-freebsd-arm64": "4.42.0", 1800 + "@rollup/rollup-freebsd-x64": "4.42.0", 1801 + "@rollup/rollup-linux-arm-gnueabihf": "4.42.0", 1802 + "@rollup/rollup-linux-arm-musleabihf": "4.42.0", 1803 + "@rollup/rollup-linux-arm64-gnu": "4.42.0", 1804 + "@rollup/rollup-linux-arm64-musl": "4.42.0", 1805 + "@rollup/rollup-linux-loongarch64-gnu": "4.42.0", 1806 + "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0", 1807 + "@rollup/rollup-linux-riscv64-gnu": "4.42.0", 1808 + "@rollup/rollup-linux-riscv64-musl": "4.42.0", 1809 + "@rollup/rollup-linux-s390x-gnu": "4.42.0", 1810 + "@rollup/rollup-linux-x64-gnu": "4.42.0", 1811 + "@rollup/rollup-linux-x64-musl": "4.42.0", 1812 + "@rollup/rollup-win32-arm64-msvc": "4.42.0", 1813 + "@rollup/rollup-win32-ia32-msvc": "4.42.0", 1814 + "@rollup/rollup-win32-x64-msvc": "4.42.0", 1815 + "fsevents": "~2.3.2" 1816 + } 1817 + }, 1818 + "node_modules/scheduler": { 1819 + "version": "0.23.2", 1820 + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", 1821 + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", 1822 + "license": "MIT", 1823 + "dependencies": { 1824 + "loose-envify": "^1.1.0" 1825 + } 1826 + }, 1827 + "node_modules/semver": { 1828 + "version": "6.3.1", 1829 + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 1830 + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 1831 + "dev": true, 1832 + "license": "ISC", 1833 + "bin": { 1834 + "semver": "bin/semver.js" 1835 + } 1836 + }, 1837 + "node_modules/source-map-js": { 1838 + "version": "1.2.1", 1839 + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 1840 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 1841 + "dev": true, 1842 + "license": "BSD-3-Clause", 1843 + "engines": { 1844 + "node": ">=0.10.0" 1845 + } 1846 + }, 1847 + "node_modules/tinyglobby": { 1848 + "version": "0.2.14", 1849 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", 1850 + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", 1851 + "dev": true, 1852 + "license": "MIT", 1853 + "dependencies": { 1854 + "fdir": "^6.4.4", 1855 + "picomatch": "^4.0.2" 1856 + }, 1857 + "engines": { 1858 + "node": ">=12.0.0" 1859 + }, 1860 + "funding": { 1861 + "url": "https://github.com/sponsors/SuperchupuDev" 1862 + } 1863 + }, 1864 + "node_modules/typescript": { 1865 + "version": "5.6.3", 1866 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 1867 + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 1868 + "dev": true, 1869 + "license": "Apache-2.0", 1870 + "bin": { 1871 + "tsc": "bin/tsc", 1872 + "tsserver": "bin/tsserver" 1873 + }, 1874 + "engines": { 1875 + "node": ">=14.17" 1876 + } 1877 + }, 1878 + "node_modules/update-browserslist-db": { 1879 + "version": "1.1.3", 1880 + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", 1881 + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", 1882 + "dev": true, 1883 + "funding": [ 1884 + { 1885 + "type": "opencollective", 1886 + "url": "https://opencollective.com/browserslist" 1887 + }, 1888 + { 1889 + "type": "tidelift", 1890 + "url": "https://tidelift.com/funding/github/npm/browserslist" 1891 + }, 1892 + { 1893 + "type": "github", 1894 + "url": "https://github.com/sponsors/ai" 1895 + } 1896 + ], 1897 + "license": "MIT", 1898 + "dependencies": { 1899 + "escalade": "^3.2.0", 1900 + "picocolors": "^1.1.1" 1901 + }, 1902 + "bin": { 1903 + "update-browserslist-db": "cli.js" 1904 + }, 1905 + "peerDependencies": { 1906 + "browserslist": ">= 4.21.0" 1907 + } 1908 + }, 1909 + "node_modules/vite": { 1910 + "version": "6.3.5", 1911 + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", 1912 + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", 1913 + "dev": true, 1914 + "license": "MIT", 1915 + "dependencies": { 1916 + "esbuild": "^0.25.0", 1917 + "fdir": "^6.4.4", 1918 + "picomatch": "^4.0.2", 1919 + "postcss": "^8.5.3", 1920 + "rollup": "^4.34.9", 1921 + "tinyglobby": "^0.2.13" 1922 + }, 1923 + "bin": { 1924 + "vite": "bin/vite.js" 1925 + }, 1926 + "engines": { 1927 + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 1928 + }, 1929 + "funding": { 1930 + "url": "https://github.com/vitejs/vite?sponsor=1" 1931 + }, 1932 + "optionalDependencies": { 1933 + "fsevents": "~2.3.3" 1934 + }, 1935 + "peerDependencies": { 1936 + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 1937 + "jiti": ">=1.21.0", 1938 + "less": "*", 1939 + "lightningcss": "^1.21.0", 1940 + "sass": "*", 1941 + "sass-embedded": "*", 1942 + "stylus": "*", 1943 + "sugarss": "*", 1944 + "terser": "^5.16.0", 1945 + "tsx": "^4.8.1", 1946 + "yaml": "^2.4.2" 1947 + }, 1948 + "peerDependenciesMeta": { 1949 + "@types/node": { 1950 + "optional": true 1951 + }, 1952 + "jiti": { 1953 + "optional": true 1954 + }, 1955 + "less": { 1956 + "optional": true 1957 + }, 1958 + "lightningcss": { 1959 + "optional": true 1960 + }, 1961 + "sass": { 1962 + "optional": true 1963 + }, 1964 + "sass-embedded": { 1965 + "optional": true 1966 + }, 1967 + "stylus": { 1968 + "optional": true 1969 + }, 1970 + "sugarss": { 1971 + "optional": true 1972 + }, 1973 + "terser": { 1974 + "optional": true 1975 + }, 1976 + "tsx": { 1977 + "optional": true 1978 + }, 1979 + "yaml": { 1980 + "optional": true 1981 + } 1982 + } 1983 + }, 1984 + "node_modules/yallist": { 1985 + "version": "3.1.1", 1986 + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1987 + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 1988 + "dev": true, 1989 + "license": "ISC" 1973 1990 } 1974 - } 1975 - }, 1976 - "node_modules/yallist": { 1977 - "version": "3.1.1", 1978 - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1979 - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 1980 - "dev": true, 1981 - "license": "ISC" 1982 1991 } 1983 - } 1984 1992 }