From c8feed6371921cf76f9e453214640e12fcd602a4 Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Sun, 6 Sep 2026 09:46:22 +0400 Subject: [PATCH 01/15] refactor(hub): oneshot waiters and plugin hygiene Replace Condvar slot wait with sync_channel, unify drain idle semantics, and harden tests/deps/docs/playground AT quick cmds. Co-authored-by: Cursor --- Cargo.lock | 1079 +++--- Cargo.toml | 18 +- README.md | 39 +- crates/android-usb-serial/Cargo.toml | 6 +- .../serialport/test/jni/UsbErrorChainTest.kt | 8 +- examples/serialport-test/src-tauri/Cargo.lock | 95 +- .../src/components/TerminalPanel.vue | 62 + guest-js/index.ts | 1 - guest-js/serial-port.ts | 19 +- guest-js/types.ts | 5 +- package.json | 18 +- pnpm-lock.yaml | 3010 +++++++++++------ src/api/backend.rs | 2 +- src/exchange/io.rs | 6 - src/hub/desktop.rs | 65 +- src/hub/shared.rs | 485 ++- src/lib.rs | 4 + src/tests/acl_smoke_test.rs | 62 + src/tests/command_inventory_test.rs | 120 + src/tests/desktop_api_test.rs | 60 +- src/tests/invoke_contract_test.rs | 87 + tests/README.md | 24 +- tests/exchange-options.test.ts | 156 + 23 files changed, 3397 insertions(+), 2034 deletions(-) create mode 100644 src/tests/acl_smoke_test.rs create mode 100644 src/tests/command_inventory_test.rs create mode 100644 tests/exchange-options.test.ts diff --git a/Cargo.lock b/Cargo.lock index 26985946..5cf75f5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" name = "android-usb-serial" version = "0.1.1" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "libc", "log", "nusb", @@ -131,6 +131,27 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -170,7 +191,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.4", ] [[package]] @@ -285,7 +306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" dependencies = [ "serde", - "toml", + "toml 0.8.23", ] [[package]] @@ -346,7 +367,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -359,12 +380,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.18.1" @@ -404,6 +419,19 @@ dependencies = [ "libc", ] +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.9.1", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.2.0" @@ -460,19 +488,15 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.29.6" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", + "phf", "smallvec", - "syn 1.0.109", ] [[package]] @@ -487,14 +511,20 @@ dependencies = [ [[package]] name = "ctor" -version = "0.2.9" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" dependencies = [ - "quote", - "syn 2.0.104", + "ctor-proc-macro", + "dtor", ] +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + [[package]] name = "darling" version = "0.20.11" @@ -530,6 +560,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + [[package]] name = "deranged" version = "0.4.0" @@ -542,11 +583,19 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.20" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case", "proc-macro2", "quote", "rustc_version", @@ -584,12 +633,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - [[package]] name = "dispatch2" version = "0.3.0" @@ -597,7 +640,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ "bitflags 2.9.1", - "objc2 0.6.1", + "block2 0.6.1", + "libc", + "objc2 0.6.4", ] [[package]] @@ -613,9 +658,9 @@ dependencies = [ [[package]] name = "dlopen2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" dependencies = [ "dlopen2_derive", "libc", @@ -634,6 +679,21 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + [[package]] name = "dpi" version = "0.1.2" @@ -658,6 +718,21 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + [[package]] name = "dunce" version = "1.0.5" @@ -679,7 +754,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml", + "toml 0.8.23", "vswhom", "winreg", ] @@ -716,6 +791,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + [[package]] name = "fdeflate" version = "0.3.7" @@ -751,6 +832,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.5.0" @@ -787,16 +874,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -869,15 +946,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "gdk" version = "0.18.2" @@ -987,17 +1055,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.16" @@ -1183,9 +1240,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -1207,14 +1264,12 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.29.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ "log", - "mac", "markup5ever", - "match_token", ] [[package]] @@ -1326,12 +1381,12 @@ dependencies = [ [[package]] name = "ico" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -1460,13 +1515,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.17.1", "serde", + "serde_core", ] [[package]] @@ -1504,16 +1560,6 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "itoa" version = "1.0.15" @@ -1552,19 +1598,68 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.0", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.12", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.104", +] + [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.104", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1608,24 +1703,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.10.0", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libappindicator" version = "0.9.0" @@ -1652,9 +1729,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] [[package]] name = "libloading" @@ -1720,15 +1806,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "mac" -version = "0.1.1" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "mach2" @@ -1750,35 +1830,15 @@ dependencies = [ [[package]] name = "markup5ever" -version = "0.14.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" dependencies = [ "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", ] -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" version = "2.7.5" @@ -1823,23 +1883,23 @@ dependencies = [ [[package]] name = "muda" -version = "0.17.0" +version = "0.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" dependencies = [ "crossbeam-channel", "dpi", "gtk", "keyboard-types", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation 0.3.1", "once_cell", - "png", + "png 0.18.1", "serde", "thiserror 2.0.12", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1849,7 +1909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.9.1", - "jni-sys", + "jni-sys 0.3.0", "log", "ndk-sys", "num_enum", @@ -1857,19 +1917,13 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - [[package]] name = "ndk-sys" version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.0", ] [[package]] @@ -1889,12 +1943,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "num-conv" version = "0.1.0" @@ -1934,19 +1982,23 @@ dependencies = [ [[package]] name = "nusb" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "215a49c10e8cff30a0da93b258b21846c4e9242f7683748cfa8474fdc2e4d22b" +checksum = "18ef13beb3b3a8fc16fd7aea912ebd3d45dde00a9a5b968d0742297468065845" dependencies = [ "core-foundation", "core-foundation-sys", "futures-core", "io-kit-sys 0.5.0", + "js-sys", "linux-raw-sys", "log", "once_cell", "rustix", "slab", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", "windows-sys 0.60.2", ] @@ -1968,9 +2020,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", "objc2-exception-helper", @@ -1984,15 +2036,9 @@ checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" dependencies = [ "bitflags 2.9.1", "block2 0.6.1", - "libc", - "objc2 0.6.1", - "objc2-cloud-kit", - "objc2-core-data", + "objc2 0.6.4", "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", ] [[package]] @@ -2002,7 +2048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" dependencies = [ "bitflags 2.9.1", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-foundation 0.3.1", ] @@ -2012,8 +2058,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" dependencies = [ - "bitflags 2.9.1", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-foundation 0.3.1", ] @@ -2025,7 +2070,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ "bitflags 2.9.1", "dispatch2", - "objc2 0.6.1", + "objc2 0.6.4", ] [[package]] @@ -2036,7 +2081,7 @@ checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" dependencies = [ "bitflags 2.9.1", "dispatch2", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-core-foundation", "objc2-io-surface", ] @@ -2047,7 +2092,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.4", + "objc2-foundation 0.3.1", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac0f75792558aa9d618443bbb5db7426a7a0b6fddf96903f86ef9ad02e135740" +dependencies = [ + "objc2 0.6.4", "objc2-foundation 0.3.1", ] @@ -2086,8 +2141,7 @@ checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" dependencies = [ "bitflags 2.9.1", "block2 0.6.1", - "libc", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -2098,7 +2152,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" dependencies = [ "bitflags 2.9.1", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-core-foundation", ] @@ -2134,7 +2188,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" dependencies = [ "bitflags 2.9.1", - "objc2 0.6.1", + "objc2 0.6.4", + "objc2-core-foundation", "objc2-foundation 0.3.1", ] @@ -2145,8 +2200,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" dependencies = [ "bitflags 2.9.1", - "objc2 0.6.1", + "block2 0.6.1", + "objc2 0.6.4", + "objc2-cloud-kit", + "objc2-core-data", "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation 0.3.1", + "objc2-quartz-core 0.3.1", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3f5ec77a81d9e0c5a0b32159b0cb143d7086165e79708351e02bf37dfc65cd" +dependencies = [ + "objc2 0.6.4", "objc2-foundation 0.3.1", ] @@ -2158,7 +2231,7 @@ checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" dependencies = [ "bitflags 2.9.1", "block2 0.6.1", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -2241,106 +2314,43 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_macros", + "phf_shared", + "serde", ] [[package]] name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", + "phf_generator", + "phf_shared", ] [[package]] name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", + "fastrand", + "phf_shared", ] [[package]] name = "phf_macros" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.104", @@ -2348,29 +2358,11 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "siphasher 1.0.1", + "siphasher", ] [[package]] @@ -2398,7 +2390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" dependencies = [ "base64 0.22.1", - "indexmap 2.10.0", + "indexmap 2.14.2", "quick-xml", "serde", "time", @@ -2417,6 +2409,19 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.9.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -2432,15 +2437,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - [[package]] name = "precomputed-hash" version = "0.1.1" @@ -2499,12 +2495,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.95" @@ -2538,87 +2528,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2696,9 +2605,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.21" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8cea6b35bcceb099f30173754403d2eba0a5dc18cea3630fccd88251909288" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" dependencies = [ "base64 0.22.1", "bytes", @@ -2715,7 +2624,6 @@ dependencies = [ "pin-project-lite", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tokio-util", @@ -2735,6 +2643,12 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2763,12 +2677,6 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - [[package]] name = "same-file" version = "1.0.6" @@ -2837,18 +2745,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "selectors" -version = "0.24.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "cssparser", "derive_more", - "fxhash", "log", - "phf 0.8.0", - "phf_codegen 0.8.0", + "new_debug_unreachable", + "phf", + "phf_codegen", "precomputed-hash", + "rustc-hash", "servo_arc", "smallvec", ] @@ -2864,10 +2773,11 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ + "serde_core", "serde_derive", ] @@ -2882,15 +2792,24 @@ dependencies = [ "typeid", ] +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 3.0.5", ] [[package]] @@ -2906,14 +2825,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -2937,15 +2857,12 @@ dependencies = [ ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serde_spanned" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", + "serde_core", ] [[package]] @@ -2958,7 +2875,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.10.0", + "indexmap 2.14.2", "schemars 0.9.0", "schemars 1.0.3", "serde", @@ -2982,9 +2899,9 @@ dependencies = [ [[package]] name = "serialize-to-javascript" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" dependencies = [ "serde", "serde_json", @@ -2993,20 +2910,20 @@ dependencies = [ [[package]] name = "serialize-to-javascript-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] name = "serialport" -version = "4.9.0" +version = "4.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4d91116f97173694f1642263b2ff837f80d933aa837e2314969f6728f661df3" +checksum = "6a2f4ac56b5d3af3c40fbbee17be96d532cba02fa5853926aacdb77d926272ab" dependencies = [ "bitflags 2.9.1", "cfg-if", @@ -3023,11 +2940,10 @@ dependencies = [ [[package]] name = "servo_arc" -version = "0.2.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" dependencies = [ - "nodrop", "stable_deref_trait", ] @@ -3055,10 +2971,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] -name = "siphasher" -version = "0.3.11" +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" @@ -3096,7 +3022,7 @@ checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" dependencies = [ "bytemuck", "cfg_aliases", - "core-graphics", + "core-graphics 0.24.0", "foreign-types", "js-sys", "log", @@ -3144,25 +3070,24 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "string_cache" -version = "0.8.9" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared 0.11.3", + "phf_shared", "precomputed-hash", - "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -3191,7 +3116,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote", "unicode-ident", ] @@ -3206,6 +3130,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3235,40 +3170,41 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.23", "version-compare", ] [[package]] name = "tao" -version = "0.34.0" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" dependencies = [ "bitflags 2.9.1", + "block2 0.6.1", "core-foundation", - "core-graphics", + "core-graphics 0.25.0", "crossbeam-channel", - "dispatch", + "dbus", + "dispatch2", "dlopen2", "dpi", "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni", - "lazy_static", + "jni 0.21.1", "libc", "log", "ndk", - "ndk-context", "ndk-sys", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-foundation 0.3.1", + "objc2-ui-kit", "once_cell", "parking_lot", + "percent-encoding", "raw-window-handle", - "scopeguard", "tao-macros", "unicode-segmentation", "url", @@ -3297,12 +3233,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.6.2" +version = "2.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" dependencies = [ "anyhow", "bytes", + "cookie", "dirs", "dunce", "embed_plist", @@ -3311,15 +3248,16 @@ dependencies = [ "gtk", "heck 0.5.0", "http", - "jni", + "jni 0.21.1", "libc", "log", "mime", "muda", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-foundation 0.3.1", "objc2-ui-kit", + "objc2-web-kit", "percent-encoding", "plist", "raw-window-handle", @@ -3338,7 +3276,6 @@ dependencies = [ "tokio", "tray-icon", "url", - "urlpattern", "webkit2gtk", "webview2-com", "window-vibrancy", @@ -3347,9 +3284,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.3.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" dependencies = [ "anyhow", "cargo_toml", @@ -3363,22 +3300,21 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml", "walkdir", ] [[package]] name = "tauri-codegen" -version = "2.3.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" dependencies = [ "base64 0.22.1", "brotli", "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", "semver", @@ -3396,9 +3332,9 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.3.1" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3410,9 +3346,9 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.3.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" dependencies = [ "anyhow", "glob", @@ -3421,7 +3357,6 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml", "walkdir", ] @@ -3430,7 +3365,7 @@ name = "tauri-plugin-serialplugin" version = "3.0.4" dependencies = [ "android-usb-serial", - "jni", + "jni 0.22.4", "log", "serde", "serde_json", @@ -3441,39 +3376,41 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.7.0" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" dependencies = [ "cookie", "dpi", "gtk", "http", - "jni", - "objc2 0.6.1", + "jni 0.21.1", + "objc2 0.6.4", "objc2-ui-kit", + "objc2-web-kit", "raw-window-handle", "serde", "serde_json", "tauri-utils", "thiserror 2.0.12", "url", + "webkit2gtk", + "webview2-com", "windows", ] [[package]] name = "tauri-runtime-wry" -version = "2.7.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" dependencies = [ "gtk", "http", - "jni", + "jni 0.21.1", "log", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", - "objc2-foundation 0.3.1", "once_cell", "percent-encoding", "raw-window-handle", @@ -3490,24 +3427,24 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.5.0" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" dependencies = [ "anyhow", "brotli", "cargo_metadata", "ctor", + "dom_query", "dunce", "glob", - "html5ever", "http", "infer", "json-patch", - "kuchikiki", "log", "memchr", - "phf 0.11.3", + "phf", + "plist", "proc-macro2", "quote", "regex", @@ -3519,7 +3456,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.12", - "toml", + "toml 1.1.5+spec-1.1.0", "url", "urlpattern", "uuid", @@ -3533,19 +3470,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" dependencies = [ "embed-resource", - "indexmap 2.10.0", - "toml", + "indexmap 2.14.2", + "toml 0.8.23", ] [[package]] name = "tendril" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" dependencies = [ - "futf", - "mac", - "utf-8", + "new_debug_unreachable", ] [[package]] @@ -3664,11 +3599,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c0ba9680044b4ce98d391a62094047eada0d64860b80166c39f4a6b5640785" +dependencies = [ + "indexmap 2.14.2", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -3678,14 +3628,23 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.10.0", - "toml_datetime", + "indexmap 2.14.2", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -3695,8 +3654,8 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.10.0", - "toml_datetime", + "indexmap 2.14.2", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -3706,20 +3665,35 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.14.2", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", "winnow 0.7.11", ] +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + [[package]] name = "tower" version = "0.5.2" @@ -3737,20 +3711,20 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "bitflags 2.9.1", "bytes", "futures-util", "http", "http-body", - "iri-string", "pin-project-lite", "tower", "tower-layer", "tower-service", + "url", ] [[package]] @@ -3786,24 +3760,24 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" dependencies = [ "crossbeam-channel", "dirs", "libappindicator", "muda", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", "objc2-core-graphics", "objc2-foundation 0.3.1", "once_cell", - "png", + "png 0.18.1", "serde", "thiserror 2.0.12", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3910,12 +3884,6 @@ dependencies = [ "url", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3985,12 +3953,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -4100,11 +4062,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "webkit2gtk" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4126,9 +4100,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -4217,7 +4191,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" dependencies = [ - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -4235,7 +4209,7 @@ dependencies = [ "windows-collections", "windows-core", "windows-future", - "windows-link", + "windows-link 0.1.3", "windows-numerics", ] @@ -4256,7 +4230,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -4268,7 +4242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", "windows-threading", ] @@ -4300,6 +4274,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-numerics" version = "0.2.0" @@ -4307,7 +4287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ "windows-core", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4316,7 +4296,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4325,7 +4305,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4364,6 +4344,15 @@ dependencies = [ "windows-targets 0.53.2", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -4417,7 +4406,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4426,7 +4415,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -4585,6 +4574,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + [[package]] name = "winreg" version = "0.55.0" @@ -4612,26 +4607,26 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wry" -version = "0.52.1" +version = "0.55.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" dependencies = [ "base64 0.22.1", "block2 0.6.1", "cookie", "crossbeam-channel", + "dirs", + "dom_query", "dpi", "dunce", "gdkx11", "gtk", - "html5ever", "http", "javascriptcore-rs", - "jni", - "kuchikiki", + "jni 0.21.1", "libc", "ndk", - "objc2 0.6.1", + "objc2 0.6.4", "objc2-app-kit", "objc2-core-foundation", "objc2-foundation 0.3.1", @@ -4699,26 +4694,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "zerofrom" version = "0.1.6" @@ -4772,3 +4747,9 @@ dependencies = [ "quote", "syn 2.0.104", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml index c64fe199..4caa5636 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,21 +39,25 @@ macos = { level = "full", notes = "" } android = { level = "full", notes = "" } [build-dependencies] -tauri-plugin = { version = "2.3.0", features = [ "build" ] } +tauri-plugin = { version = "2", features = [ "build" ] } [dependencies] -tauri = { version = "2.6.2", features = ["test"] } -serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.140" +tauri = { version = "2" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" [target.'cfg(target_os = "android")'.dependencies] -jni = "0.21" +jni = "0.22" android-usb-serial = { path = "crates/android-usb-serial", version = "0.1.1" } -serialport = "4.9.0" +serialport = "4.10" log = { version = "0.4", features = ["std"] } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] -serialport = "4.9.0" +serialport = "4.10" + +[dev-dependencies] +# `test` feature only for this crate's unit tests — keep it off the published dependency graph. +tauri = { version = "2", features = ["test"] } [profile.release] codegen-units = 1 diff --git a/README.md b/README.md index c92b63fc..55e83140 100755 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Legacy Tauri events (`plugin-serialplugin-read-*`) and Android plugin triggers ( | Option | Desktop | Android | |--------|---------|---------| | `timeout` | Batch coalescing window (ms) | Coalescing / flush hint where supported | -| `serialDataFlushIntervalMs` | Preferred batch interval; falls back to `timeout` | `BufferedEmitter` flush (10–2000 ms) | +| `serialDataFlushIntervalMs` | Preferred batch interval for hub `batch_timeout_ms` (falls back to `timeout`) | Same; clamped typically 10–2000 ms | | `size` | Read chunk size per syscall | Reserved | | `decode` | JS-only: `TextDecoder` on `onData` | JS-only | @@ -92,11 +92,10 @@ Legacy Tauri events (`plugin-serialplugin-read-*`) and Android plugin triggers ( 7.8. [Auto-Reconnect](#auto-reconnect-management) 8. [Common Use Cases](#common-use-cases) 9. [Android Setup](#android-setup) -10. [Contributing](#contributing) -11. [Development Setup](#development-setup) -12. [Testing](#testing) -13. [Partners](#partners) -14. [License](#license) +10. [Development Setup](#development-setup) +11. [Testing](#testing) +12. [Partners](#partners) +13. [License](#license) --- @@ -104,7 +103,7 @@ Legacy Tauri events (`plugin-serialplugin-read-*`) and Android plugin triggers ( ### Prerequisites -- **Rust** version 1.70 or higher +- **Rust** version 1.79 or higher (MSRV) - **Tauri** 2.0 or higher - **Node.js** and an npm-compatible package manager (npm, yarn, pnpm) @@ -876,7 +875,17 @@ use tauri_plugin_serialplugin::commands::{ capabilities, // Runtime info watch, // Stream events via Channel unwatch, // Stop watch session - cancel_read, // Cancel poll read or active watch (shared stop channel) + cancel_read, // Cancel in-flight poll read only (does not detach watch) + exchange, // Write + read-until + exchange_binary, // Binary exchange + cancel_exchange, // Cancel in-flight exchange / AT job + at, // Native AT queue command + at_phases, // Multi-phase AT job + send_sms_pdu, // CMGS PDU helper + configure_at_session, // AT session defaults + enable_mux, // Enter CMUX + open_mux_channel, // Open virtual CMUX channel + disable_mux, // Tear down CMUX // Port configuration set_baud_rate, // Set baud rate @@ -930,7 +939,7 @@ pub fn open( parity: Option, stop_bits: Option, timeout: Option, -) -> Result<(), Error> +) -> Result // canonical path (Android session key / desktop echo) // Write data pub fn write( @@ -1157,13 +1166,13 @@ class SerialPort { class SerialPort { /** * Opens the serial port with specified configuration - * @returns {Promise} + * @returns {Promise} Canonical path (Android re-keys to session path; desktop echoes input) * @throws {Error} If port is already open or invalid configuration * @example * const port = new SerialPort({ path: "COM1", baudRate: 9600 }); - * await port.open(); + * const canonical = await port.open(); */ - async open(): Promise; + async open(): Promise; /** * Closes the serial port connection @@ -1693,12 +1702,6 @@ See [`android/README.md`](android/README.md) and [`android/BUILD_INSTRUCTIONS.md --- -## Contributing - -Pull requests are welcome! Please read our contributing guidelines before you start. - ---- - ## Development Setup ```bash diff --git a/crates/android-usb-serial/Cargo.toml b/crates/android-usb-serial/Cargo.toml index 3a7aa491..5fcd2907 100644 --- a/crates/android-usb-serial/Cargo.toml +++ b/crates/android-usb-serial/Cargo.toml @@ -44,11 +44,11 @@ version = "1.0" optional = true [dependencies.base64] -version = "0.22" +version = "0.23" optional = true [dependencies.serialport] -version = "4.9" +version = "4.10" optional = true [target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies] @@ -58,7 +58,7 @@ libc = "0.2" [dev-dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -base64 = "0.22" +base64 = "0.23" [[bin]] name = "golden_record" diff --git a/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt b/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt index 09777bd5..990d863d 100644 --- a/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt +++ b/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt @@ -22,7 +22,13 @@ class UsbErrorChainTest { fun fake_read_error_clears_registry() { assertTrue(MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath)) MobileBridge.testFakeInjectError(JniChainFixture.DEVICE_NAME, "device exploded") - Thread.sleep(1500) + val deadline = System.nanoTime() + 5_000_000_000L + while (System.nanoTime() < deadline) { + if (!MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath)) { + return + } + Thread.sleep(20) + } assertFalse( "registry should drop port after reader error → onUsbError", MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath), diff --git a/examples/serialport-test/src-tauri/Cargo.lock b/examples/serialport-test/src-tauri/Cargo.lock index 2a686068..49aabe44 100644 --- a/examples/serialport-test/src-tauri/Cargo.lock +++ b/examples/serialport-test/src-tauri/Cargo.lock @@ -51,7 +51,7 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" name = "android-usb-serial" version = "0.1.1" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "libc", "log", "nusb", @@ -209,6 +209,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bitflags" version = "1.3.2" @@ -1743,19 +1749,68 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.0", "log", "thiserror 1.0.68", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.12", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.87", +] + [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.87", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -2070,7 +2125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.6.0", - "jni-sys", + "jni-sys 0.3.0", "log", "ndk-sys", "num_enum", @@ -2090,7 +2145,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.0", ] [[package]] @@ -3334,9 +3389,9 @@ dependencies = [ [[package]] name = "serialport" -version = "4.9.0" +version = "4.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4d91116f97173694f1642263b2ff837f80d933aa837e2314969f6728f661df3" +checksum = "6a2f4ac56b5d3af3c40fbbee17be96d532cba02fa5853926aacdb77d926272ab" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3400,6 +3455,22 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "0.3.11" @@ -3592,7 +3663,7 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni", + "jni 0.21.1", "lazy_static", "libc", "log", @@ -3648,7 +3719,7 @@ dependencies = [ "gtk", "heck 0.5.0", "http 1.1.0", - "jni", + "jni 0.21.1", "libc", "log", "mime", @@ -3795,7 +3866,7 @@ name = "tauri-plugin-serialplugin" version = "3.0.4" dependencies = [ "android-usb-serial", - "jni", + "jni 0.22.4", "log", "serde", "serde_json", @@ -3814,7 +3885,7 @@ dependencies = [ "dpi", "gtk", "http 1.1.0", - "jni", + "jni 0.21.1", "objc2 0.6.0", "objc2-ui-kit", "raw-window-handle", @@ -3834,7 +3905,7 @@ checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad" dependencies = [ "gtk", "http 1.1.0", - "jni", + "jni 0.21.1", "log", "objc2 0.6.0", "objc2-app-kit 0.3.0", @@ -5160,7 +5231,7 @@ dependencies = [ "html5ever", "http 1.1.0", "javascriptcore-rs", - "jni", + "jni 0.21.1", "kuchikiki", "libc", "ndk", diff --git a/examples/serialport-test/src/components/TerminalPanel.vue b/examples/serialport-test/src/components/TerminalPanel.vue index 6edce0cf..d10ad5bc 100644 --- a/examples/serialport-test/src/components/TerminalPanel.vue +++ b/examples/serialport-test/src/components/TerminalPanel.vue @@ -30,6 +30,21 @@ const modeLabels: Record = { hex: 'Hex', }; +/** One-click modem probes via `sendAt()` (no need to type). */ +const quickAtCommands = [ + 'AT', + 'ATI', + 'AT+CGMI', + 'AT+CGMM', + 'AT+CGMR', + 'AT+CGSN', + 'AT+CSQ', + 'AT+CPIN?', + 'AT+CREG?', + 'ATE0', + 'ATE1', +] as const; + function send() { const text = input.value; if (!text.trim() || !props.connected) return; @@ -42,6 +57,16 @@ function send() { input.value = ''; } +function sendQuickAt(cmd: string) { + if (!props.connected || props.atBusy) return; + emit('send', { + text: cmd, + mode: 'at', + lineEnding: lineEnding.value, + localEcho: localEcho.value, + }); +} + function scrollToBottom() { if (!autoScroll.value || !scrollEl.value) return; scrollEl.value.scrollTop = scrollEl.value.scrollHeight; @@ -118,6 +143,21 @@ onMounted(scrollToBottom); +
+ AT + +
+
> ): Uint8Array { + return data instanceof Uint8Array ? data : new Uint8Array(data); +} + function dispatchWatchData( data: number[], decoder: TextDecoder, decode: boolean, onData: (data: string | Uint8Array) => void, ): void { - const bytes = new Uint8Array(data); + const bytes = toUint8Raw(data); if (!decode) { onData(bytes); return; @@ -565,7 +570,7 @@ export class SerialPort { timeout: options?.timeout ?? this.options.timeout, size: options?.size ?? this.size, }); - return new Uint8Array(result); + return toUint8Raw(result); } async setBaudRate(value: number | BaudRate): Promise { @@ -685,7 +690,7 @@ export class SerialPort { }); return { ...result, - raw: new Uint8Array(result.raw as unknown as number[]), + raw: toUint8Raw(result.raw as unknown as number[]), }; } @@ -701,7 +706,7 @@ export class SerialPort { }); return { ...result, - raw: new Uint8Array(result.raw as unknown as number[]), + raw: toUint8Raw(result.raw as unknown as number[]), }; } @@ -789,7 +794,7 @@ export class SerialPort { }); return { ...result, - raw: new Uint8Array(result.raw as unknown as number[]), + raw: toUint8Raw(result.raw as unknown as number[]), }; } @@ -804,7 +809,7 @@ export class SerialPort { }); return results.map((r) => ({ ...r, - raw: new Uint8Array(r.raw as unknown as number[]), + raw: toUint8Raw(r.raw as unknown as number[]), })); } @@ -825,7 +830,7 @@ export class SerialPort { }); return results.map((r) => ({ ...r, - raw: new Uint8Array(r.raw as unknown as number[]), + raw: toUint8Raw(r.raw as unknown as number[]), })); } diff --git a/guest-js/types.ts b/guest-js/types.ts index dbbe5b3e..dd54455b 100644 --- a/guest-js/types.ts +++ b/guest-js/types.ts @@ -30,7 +30,8 @@ export interface WatchOptions { size?: number; /** * Desktop: preferred batch flush interval (falls back to `timeout`). - * Android: `BufferedEmitter` flush interval (10–2000 ms). + * Android: watch batch flush interval (hub `batch_timeout_ms`, typically 10–2000 ms). + * Prefer this over relying on `timeout` alone when you need a specific coalesce window. */ serialDataFlushIntervalMs?: number; /** Default `true` — stream-decode with TextDecoder. */ @@ -134,8 +135,6 @@ export enum ClearBuffer { All = 'All', } -export type SerialPortConfig = SerialportOptions; - export interface AutoReconnectOptions { interval?: number; maxAttempts?: number | null; diff --git a/package.json b/package.json index 3d7421ce..d3f07b8c 100755 --- a/package.json +++ b/package.json @@ -42,18 +42,16 @@ "@tauri-apps/api": ">=2.0.0-beta.6" }, "devDependencies": { - "@rollup/plugin-node-resolve": "15.3.1", - "@rollup/plugin-terser": "0.4.4", - "@rollup/plugin-typescript": "^12.1.4", - "@types/jest": "^29.5.12", + "@rollup/plugin-typescript": "^12.3.0", + "@types/jest": "^30.0.0", "@types/node": "^20.17.22", - "jest": "^29.7.0", - "jest-environment-jsdom": "^30.0.2", - "jest-junit": "^16.0.0", - "jsdom": "^26.1.0", - "rollup": "4.34.9", + "jest": "^30.5.1", + "jest-environment-jsdom": "^30.5.1", + "jest-junit": "^17.0.0", + "jsdom": "^30.0.1", + "rollup": "4.63.1", "standard-version": "^9.5.0", - "ts-jest": "^29.1.2", + "ts-jest": "^29.4.12", "tslib": "^2.8.1", "typescript": "5.6.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28cf4b78..35de36ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,42 +12,36 @@ importers: specifier: '>=2.0.0-beta.6' version: 2.6.0 devDependencies: - '@rollup/plugin-node-resolve': - specifier: 15.3.1 - version: 15.3.1(rollup@4.34.9) - '@rollup/plugin-terser': - specifier: 0.4.4 - version: 0.4.4(rollup@4.34.9) '@rollup/plugin-typescript': - specifier: ^12.1.4 - version: 12.1.4(rollup@4.34.9)(tslib@2.8.1)(typescript@5.6.3) + specifier: ^12.3.0 + version: 12.3.0(rollup@4.63.1)(tslib@2.8.1)(typescript@5.6.3) '@types/jest': - specifier: ^29.5.12 - version: 29.5.14 + specifier: ^30.0.0 + version: 30.0.0 '@types/node': specifier: ^20.17.22 version: 20.17.22 jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.22) + specifier: ^30.5.1 + version: 30.5.1(@types/node@20.17.22) jest-environment-jsdom: - specifier: ^30.0.2 - version: 30.0.2 + specifier: ^30.5.1 + version: 30.5.1 jest-junit: - specifier: ^16.0.0 - version: 16.0.0 + specifier: ^17.0.0 + version: 17.0.0 jsdom: - specifier: ^26.1.0 - version: 26.1.0 + specifier: ^30.0.1 + version: 30.0.1 rollup: - specifier: 4.34.9 - version: 4.34.9 + specifier: 4.63.1 + version: 4.63.1 standard-version: specifier: ^9.5.0 version: 9.5.0 ts-jest: - specifier: ^29.1.2 - version: 29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.22))(typescript@5.6.3) + specifier: ^29.4.12 + version: 29.4.12(@babel/core@7.27.1)(@jest/transform@30.5.1)(@jest/types@30.5.1)(babel-jest@30.5.1(@babel/core@7.27.1))(jest-util@30.5.1)(jest@30.5.1(@types/node@20.17.22))(typescript@5.6.3) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -95,6 +89,14 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@asamuzakjp/css-color@6.0.7': + resolution: {integrity: sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==} + engines: {node: ^22.13.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@8.3.2': + resolution: {integrity: sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==} + engines: {node: ^22.13.0 || >=24.0.0} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -103,38 +105,68 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.27.2': resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + '@babel/core@7.27.1': resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} engines: {node: '>=6.9.0'} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.27.1': resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-transforms@7.27.1': resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.29.7': @@ -145,10 +177,6 @@ packages: resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} @@ -157,20 +185,28 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + '@babel/helpers@7.27.1': resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.2': - resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-syntax-async-generators@7.8.4': resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -266,25 +302,41 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.27.1': resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.1': - resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} '@babel/types@7.29.7': resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + '@csstools/color-helpers@5.0.2': resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} engines: {node: '>=18'} + '@csstools/color-helpers@6.1.1': + resolution: {integrity: sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==} + engines: {node: '>=20.19.0'} + '@csstools/css-calc@2.1.4': resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} engines: {node: '>=18'} @@ -292,6 +344,13 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-calc@3.3.0': + resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-color-parser@3.0.10': resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==} engines: {node: '>=18'} @@ -299,16 +358,50 @@ packages: '@csstools/css-parser-algorithms': ^3.0.5 '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-color-parser@4.2.2': + resolution: {integrity: sha512-3QKjR/vxyjcSXBLgb6lP0S3MGdvwbmqSsvLPbYdVORqPDc8FX1HAJ0Spk38bxaRXgvENTA47tlhhbb5Z2e8hEg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms@3.0.5': resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} engines: {node: '>=18'} peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.12': + resolution: {integrity: sha512-3vLQK+dXxhBMR2Wx99PTCifE+vHtW2ndZWyla8yK813ev6oGhyn8Lja8jCyGAWTJ+LEYZK7EVtJxrDj8ztevJw==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild/aix-ppc64@0.25.0': resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} engines: {node: '>=18'} @@ -459,10 +552,23 @@ packages: cpu: [x64] os: [win32] + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@hutson/parse-repository-url@3.0.2': resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} engines: {node: '>=6.9.0'} + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} @@ -471,106 +577,109 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - '@jest/console@29.7.0': - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@30.5.1': + resolution: {integrity: sha512-u5Ncuc+gXVUwjNMFQOnphHo2Qx2DxyC8Dvpmf4HCx4y0kvSkRRNiQYRixrvOP4V7y52JcSuNxqochCt0PpdHVg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/core@29.7.0': - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.5.1': + resolution: {integrity: sha512-BL9g6CJUUhIbdoAflz/Va658erSSXUIvU8XUYiWNTbZljJjZ5yaC9EJ9/dQ19rpbYV3ZOK4sBACqhPaTyhoUIA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - '@jest/environment-jsdom-abstract@30.0.2': - resolution: {integrity: sha512-8aMoEzGdUuJeQl71BUACkys1ZEX437AF376VBqdYXsGFd4l3F1SdTjFHmNq8vF0Rp+CYhUyxa0kRAzXbBaVzfQ==} + '@jest/diff-sequences@30.5.0': + resolution: {integrity: sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment-jsdom-abstract@30.5.1': + resolution: {integrity: sha512-J395vmP3Fb2Te0JmF7pe4si4jpfbXef1YsY4UpHYL6OOxS2molu9Dsie1VmIiUalXdtmz1P5QRgc+5hBD+ssBg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: + '@types/jsdom': '*' canvas: ^3.0.0 jsdom: '*' peerDependenciesMeta: canvas: optional: true - '@jest/environment@29.7.0': - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/environment@30.0.2': - resolution: {integrity: sha512-hRLhZRJNxBiOhxIKSq2UkrlhMt3/zVFQOAi5lvS8T9I03+kxsbflwHJEF+eXEYXCrRGRhHwECT7CDk6DyngsRA==} + '@jest/environment@30.5.1': + resolution: {integrity: sha512-eYJAkOsrpwDXPcoLNEG6lN9Zo3Cy35pxnVQD74vyIfsi/Q8wB/lZFsEjU4wrecOgT4ZviQDZaX/cFIJyMdMxTw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect-utils@29.7.0': - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@30.5.1': + resolution: {integrity: sha512-WcRWhHQdTMRDpyWKZ/6MINBmovI7zeD+bL8wFjCncRV3NQOwKy1X45IfyblfHR4k/XciIlNEdFL9QjFO+HNKOg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/expect@29.7.0': - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@30.5.1': + resolution: {integrity: sha512-uOGd40P/COyUp9xHf5jeGiGJC2/ANg+2+Tk9/xN5/LxmlY/r/gxsPrx3DTEtaRZsLAX4wgNSLEDELZ5bmVs2bA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/fake-timers@29.7.0': - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/fake-timers@30.5.1': + resolution: {integrity: sha512-rEkV6YzpBXo/L9cnj2ibyuYZuyGiNWaPUsyCu3HYJbqCV4jnEiKmf7hId20z8eKjZ0JQ9jtIYKxRSmYB/OYSsA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/fake-timers@30.0.2': - resolution: {integrity: sha512-jfx0Xg7l0gmphTY9UKm5RtH12BlLYj/2Plj6wXjVW5Era4FZKfXeIvwC67WX+4q8UCFxYS20IgnMcFBcEU0DtA==} + '@jest/get-type@30.5.0': + resolution: {integrity: sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/globals@29.7.0': - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/globals@30.5.1': + resolution: {integrity: sha512-VhqvQ251XIC7pk46YymI3HCeBLOdvriDw9zibekodAHEwoVvbVVgpU5H13GvmyOAzxtZCfsm1uvzqkaqJf2I+g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/pattern@30.0.1': - resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + '@jest/pattern@30.5.0': + resolution: {integrity: sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/reporters@29.7.0': - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/reporters@30.5.1': + resolution: {integrity: sha512-RbUXIfv85KxitJn4l3MpAoMilkvXe2QCO5lXxHWftywo/VdZ5vkEoHRDgphcxP6qmoIkUaN8/UZj6NhdkIFdJg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/schemas@30.0.1': - resolution: {integrity: sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==} + '@jest/schemas@30.5.0': + resolution: {integrity: sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/source-map@29.6.3': - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/snapshot-utils@30.5.1': + resolution: {integrity: sha512-V3wnxNtiVmw5PPVg433Cn3VdXnsOeu/ofLw3KC04Bn2y1wIlU5kozXQn48rhrgj/02LrCVtntTEF1yBha0XSUw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-result@29.7.0': - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@30.5.0': + resolution: {integrity: sha512-xWpTJP9D0bDFGbPGT8XuWSwwha/iHADyyKzUnMx4UbdgnHugxrDaQFO4RZ8x4ZsFzRP6pNii8uvlgKCDxCIuDg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/test-sequencer@29.7.0': - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.5.1': + resolution: {integrity: sha512-A/1S6ZBdpic50E0pxLgvaB9XNPL4k7AksmG69OO2oiotxciWZwHkbOec+qbIi+uUtIIByOVlXJUl97oZUsz+Jw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@30.5.1': + resolution: {integrity: sha512-SHcPnrjdVRYJv6y6l4JUTy4Jccu7zmO6BmiOfOA34UiVBto22s19WiDC0A/2qfM7MWB/qdcoqfSIRMitpjTT4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@30.5.1': + resolution: {integrity: sha512-EDnDhn0jleU9ZhpVoA4gvqw+Ev0iw/r5upNT2b79RiwiaTiYAMMhvNJP3lmocjIe5J2ZkoNr0B3K/J6O5GIm4Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/types@30.0.1': - resolution: {integrity: sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==} + '@jest/types@30.5.1': + resolution: {integrity: sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -582,35 +691,114 @@ packages: '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} - engines: {node: '>=14.0.0'} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + + '@napi-rs/wasm-runtime@1.2.3': + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + + '@parcel/watcher-android-arm64@2.6.0': + resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.6.0': + resolution: {integrity: sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.6.0': + resolution: {integrity: sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.6.0': + resolution: {integrity: sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.6.0': + resolution: {integrity: sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.6.0': + resolution: {integrity: sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.6.0': + resolution: {integrity: sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.6.0': + resolution: {integrity: sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.6.0': + resolution: {integrity: sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.6.0': + resolution: {integrity: sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.6.0': + resolution: {integrity: sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-x64@2.6.0': + resolution: {integrity: sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.6.0': + resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==} + engines: {node: '>= 10.0.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} - '@rollup/plugin-typescript@12.1.4': - resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} + '@pkgr/core@0.3.6': + resolution: {integrity: sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==} + engines: {node: ^14.18.0 || >=16.0.0} + + '@rollup/plugin-typescript@12.3.0': + resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.14.0||^3.0.0||^4.0.0 @@ -631,115 +819,139 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.34.9': - resolution: {integrity: sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==} + '@rollup/rollup-android-arm-eabi@4.63.1': + resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.34.9': - resolution: {integrity: sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==} + '@rollup/rollup-android-arm64@4.63.1': + resolution: {integrity: sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.34.9': - resolution: {integrity: sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==} + '@rollup/rollup-darwin-arm64@4.63.1': + resolution: {integrity: sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.34.9': - resolution: {integrity: sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==} + '@rollup/rollup-darwin-x64@4.63.1': + resolution: {integrity: sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.34.9': - resolution: {integrity: sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==} + '@rollup/rollup-freebsd-arm64@4.63.1': + resolution: {integrity: sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.34.9': - resolution: {integrity: sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==} + '@rollup/rollup-freebsd-x64@4.63.1': + resolution: {integrity: sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.34.9': - resolution: {integrity: sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==} + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': + resolution: {integrity: sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.34.9': - resolution: {integrity: sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==} + '@rollup/rollup-linux-arm-musleabihf@4.63.1': + resolution: {integrity: sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.34.9': - resolution: {integrity: sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==} + '@rollup/rollup-linux-arm64-gnu@4.63.1': + resolution: {integrity: sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.34.9': - resolution: {integrity: sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==} + '@rollup/rollup-linux-arm64-musl@4.63.1': + resolution: {integrity: sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.34.9': - resolution: {integrity: sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==} + '@rollup/rollup-linux-loong64-gnu@4.63.1': + resolution: {integrity: sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.63.1': + resolution: {integrity: sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.34.9': - resolution: {integrity: sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==} + '@rollup/rollup-linux-ppc64-gnu@4.63.1': + resolution: {integrity: sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.34.9': - resolution: {integrity: sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==} + '@rollup/rollup-linux-ppc64-musl@4.63.1': + resolution: {integrity: sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.63.1': + resolution: {integrity: sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.63.1': + resolution: {integrity: sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.34.9': - resolution: {integrity: sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==} + '@rollup/rollup-linux-s390x-gnu@4.63.1': + resolution: {integrity: sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.34.9': - resolution: {integrity: sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==} + '@rollup/rollup-linux-x64-gnu@4.63.1': + resolution: {integrity: sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.34.9': - resolution: {integrity: sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==} + '@rollup/rollup-linux-x64-musl@4.63.1': + resolution: {integrity: sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.34.9': - resolution: {integrity: sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==} + '@rollup/rollup-openbsd-x64@4.63.1': + resolution: {integrity: sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.1': + resolution: {integrity: sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + resolution: {integrity: sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.34.9': - resolution: {integrity: sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==} + '@rollup/rollup-win32-ia32-msvc@4.63.1': + resolution: {integrity: sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.34.9': - resolution: {integrity: sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==} + '@rollup/rollup-win32-x64-gnu@4.63.1': + resolution: {integrity: sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==} cpu: [x64] os: [win32] - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@rollup/rollup-win32-x64-msvc@4.63.1': + resolution: {integrity: sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==} + cpu: [x64] + os: [win32] - '@sinclair/typebox@0.34.37': - resolution: {integrity: sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==} + '@sinclair/typebox@0.34.52': + resolution: {integrity: sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==} '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - - '@sinonjs/fake-timers@13.0.5': - resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + '@sinonjs/fake-timers@15.4.0': + resolution: {integrity: sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==} '@tauri-apps/api@2.6.0': resolution: {integrity: sha512-hRNcdercfgpzgFrMXWwNDBN0B7vNzOzRepy6ZAmhxi5mDLVPNrTpo9MGg2tN/F7JRugj4d2aF7E1rtPXAHaetg==} @@ -815,6 +1027,9 @@ packages: engines: {node: '>= 10'} hasBin: true + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -830,8 +1045,8 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -842,8 +1057,8 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/jest@29.5.14': - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} '@types/jsdom@21.1.7': resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} @@ -857,9 +1072,6 @@ packages: '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - '@types/resolve@1.20.2': - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -872,6 +1084,119 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@ungap/structured-clone@1.4.0': + resolution: {integrity: sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + '@vitejs/plugin-vue@5.2.4': resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -955,6 +1280,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} + engines: {node: '>=12'} + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -967,6 +1296,10 @@ packages: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -981,49 +1314,50 @@ packages: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-jest@30.5.1: + resolution: {integrity: sha512-ge1xUVZS91ml09YRMgRGgeKJ4YJpcOiuwteAxFBYLugQyp7cRw+hHej6Ho0vPjvLrjq60bb7JPHH9LAMA1/krA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.8.0 + '@babel/core': ^7.11.0 || ^8.0.0-0 - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + babel-plugin-istanbul@8.0.0: + resolution: {integrity: sha512-18wCskrN3DgbuBmp1gr7LBGT8xdz5xhQQqFvFhVxbkl8VBCrMKQ2YtqBWtUal1Zrc1HTuX0011+Brjw78TCFkg==} + engines: {node: '>=18'} - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@30.5.0: + resolution: {integrity: sha512-gtGo1B+u14jrZQv6TdSWIWkTqclboo7Qn+dFAGUOIuXLFuJKAdg3U5MIWzZnW4vfUb4dX9skmAMiby86e/SF4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - babel-preset-current-node-syntax@1.1.0: - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.0.0 || ^8.0.0-0 - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-preset-jest@30.5.0: + resolution: {integrity: sha512-ZGPn5ClP4lBDpuOK8W1yQIOy359HmbnZv3suucAlIe+SEE9yDsxV4S2PjSbH2Vc97U+WmzYD7vw3kr8NsQ/i6w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.0.0 + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 || ^8.0.0 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - brace-expansion@2.1.1: resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} browserslist@4.24.5: resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} @@ -1071,16 +1405,12 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - ci-info@4.2.0: - resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.1: + resolution: {integrity: sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==} cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -1198,15 +1528,14 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + cssstyle@4.6.0: resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} engines: {node: '>=18'} @@ -1222,6 +1551,10 @@ packages: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} @@ -1248,6 +1581,9 @@ packages: decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + dedent@1.6.0: resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} peerDependencies: @@ -1264,14 +1600,14 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -1280,10 +1616,8 @@ packages: resolution: {integrity: sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA==} engines: {node: '>=6'} - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} electron-to-chromium@1.5.157: resolution: {integrity: sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==} @@ -1295,6 +1629,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -1303,9 +1640,16 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + esbuild@0.25.0: resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} engines: {node: '>=18'} @@ -1335,13 +1679,13 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + expect@30.5.1: + resolution: {integrity: sha512-m8YrYgvKe9+9gEnWEuKz+qCGfHqkrff7PPfyDnOFkjsfYRKqiYyOxDFMFieCGAuhtk/VNm63tvNgKZVzVy+Hvg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -1349,17 +1693,19 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} @@ -1376,8 +1722,9 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} @@ -1425,9 +1772,14 @@ packages: gitconfiglocal@1.0.0: resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -1441,8 +1793,13 @@ packages: engines: {node: '>=0.4.7'} hasBin: true - hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + hard-rejection@2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} has-flag@3.0.0: @@ -1472,6 +1829,10 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -1504,10 +1865,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1521,6 +1878,10 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -1529,12 +1890,9 @@ packages: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} - is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} is-obj@2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} @@ -1565,10 +1923,6 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - istanbul-lib-instrument@6.0.3: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} @@ -1577,30 +1931,28 @@ packages: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} istanbul-reports@3.1.7: resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} - jake@10.9.2: - resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} - engines: {node: '>=10'} - hasBin: true + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@30.5.1: + resolution: {integrity: sha512-0+bvMM/ENhDI29Z8q1r4HxiDIi4G5tnBmSw4esfPQoj9q8Nik7KIyuxHkTVnnniJQf05SxpGaKDQ+4h28ynGPg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@30.5.1: + resolution: {integrity: sha512-NgliezXQ6yznqR4W5Gqw++0cZSbBZlF0NknNIAE5VmSJKWOtmWJmWnBq3TSkUOVBTPrT7FGGhVdA8DLWnxo2Sw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-cli@30.5.1: + resolution: {integrity: sha512-uwNYepWgaNBCplm42fCIUZTf/tIEHIy5AYvx7eL1BrwIgyjPt+2poouR23UO2yopIP+kV8oZFHfv+l4pg/8prQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1608,32 +1960,35 @@ packages: node-notifier: optional: true - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-config@30.5.1: + resolution: {integrity: sha512-L8PKM2X/ngG8PxfLMqglKGZjylPgw84bVPUlMY9W/o76TnLqPWrmQgsaT0HrheGdRtpGE5FbmREA0Kvb+Qx5gQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' + esbuild-register: '>=3.4.0' ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': optional: true + esbuild-register: + optional: true ts-node: optional: true - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@30.5.1: + resolution: {integrity: sha512-e3cNNMpv8Kh20MjjphTXs+3Vz7DQyLM1nft7KJhnh46atFhjVJRa+0Hq0beywuwsACtMQUBihQkFl8zxb7gt1Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@30.5.0: + resolution: {integrity: sha512-NwDqcxtoZi33RhuW+zJS/RVA3rmheQ8BnwpYZuc/Eruaz6seQb7+aoCeDZu/3X7W2XmD8DbSo9Pn72DbKsBFYw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@30.5.1: + resolution: {integrity: sha512-S1af0TU4v1EZ/AUlkFs/sxf/5KGsbAT9kRgdyoMX/x72y7C8ZEgETE5o1TPnbKRnrbprc5FR/moYLfdRmqEjsQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-environment-jsdom@30.0.2: - resolution: {integrity: sha512-lwMpe7hZ81e2PpHj+4nowAzSkC0p8ftRfzC+qEjav9p5ElCs6LAce3y46iLwMS27oL9+/KQe55gUvUDwrlDeJQ==} + jest-environment-jsdom@30.5.1: + resolution: {integrity: sha512-8lzKbC/SRbQE24wr1OOJV+aYtDAuVNKBryN6YcFiCcaZZ3I7grcZY7w91BwNvGET0ubKDmomEHZFHMaF+6pAlA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 @@ -1641,106 +1996,77 @@ packages: canvas: optional: true - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-junit@16.0.0: - resolution: {integrity: sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==} - engines: {node: '>=10.12.0'} - - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@30.5.1: + resolution: {integrity: sha512-LrPj3sPMjsQoOB3jrb8p/sa+XkSFNKo60TTsyc+EB2kxQJHgbwElpXnx1yX25fdFn5958FIObRtcLSHyV8VIAw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-message-util@30.0.2: - resolution: {integrity: sha512-vXywcxmr0SsKXF/bAD7t7nMamRvPuJkras00gqYeB1V0WllxZrbZ0paRr3XqpFU2sYYjD0qAaG2fRyn/CGZ0aw==} + jest-haste-map@30.5.1: + resolution: {integrity: sha512-VIFgt67jW480YDxKfEv9IYQKrFpYt7bOCMn3VsnjK7AK9qo7p6acpnA1DHwsVOULE3dTaYew/6JaTD/d0VDHoQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-junit@17.0.0: + resolution: {integrity: sha512-RYWCkq4j59gUXj5DsgbIE7xFBZzu1gtibPhyjSjMmGaOTLnqlXhg7x9zuGCwgbCuMAyoyvk0Mi8wSrRR5uOeLA==} + engines: {node: '>=20.0.0'} - jest-mock@30.0.2: - resolution: {integrity: sha512-PnZOHmqup/9cT/y+pXIVbbi8ID6U1XHRmbvR7MvUy4SLqhCbwpkmXhLbsWbGewHrV5x/1bF7YDjs+x24/QSvFA==} + jest-leak-detector@30.5.1: + resolution: {integrity: sha512-gt4GT2aWgEoCNTcBe4rqS74xTIUJxi+UD9SNSu9aOk5LmTEd6fS5KSTmAKAfitCCktQHNN+upUuL6EkBfFbMDQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-pnp-resolver@1.2.3: - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true + jest-matcher-utils@30.5.1: + resolution: {integrity: sha512-aroZVqwOz/wC2y6pC+obgFWKV9viaQWQTTSB6W5H55+egtUczIfXR/rxExTv92xD/ADYwpqaYfVWx1aqwKg7FA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@30.5.1: + resolution: {integrity: sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-regex-util@30.0.1: - resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + jest-mock@30.5.1: + resolution: {integrity: sha512-9fVjc3leUpGID2/by/LU4Dvdcp7PFh9LlxS3QRWK3ABm+KtvEVsG/AEGeLY3gKOZsjkBxyfwGltoAVlW7dygHg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@30.5.0: + resolution: {integrity: sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@30.5.1: + resolution: {integrity: sha512-JKpXGONDcTaunrNVn8KCl6qAnwl06jIkvv70lhq0Ze47lsPx9sH5HoeEUiXX6iFGnliHN/qpIbQ0l38wrVmXaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@30.5.1: + resolution: {integrity: sha512-wprhLejRtwN6h8ZgaqC0eYjGJ1uMdGPT/+b3eFncbG4NWuuP9QL+vWwRinu9waw7hkOLcpMJGVJAMgBwsPssMQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@30.5.1: + resolution: {integrity: sha512-FPlQE4+mwnFxXmpPrSi836KV2ZzvK1g6/nPCT8o5BcoDUUNJQeHo1/Qdkoe/QeoL4M7OeJpbnGUhYKhC1VMdaQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@30.5.1: + resolution: {integrity: sha512-UB88+NRkK2Tw/OqV7dofYcyiUGrVZtD41k/N0xQOs9fG//57XHK7JLWG52HD1UYpUAhjK4xm6DBvFX3yWudsMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@30.5.1: + resolution: {integrity: sha512-cNWFdSb5xuDGl8hKkAZJ3YtI/PzHpAPFV+HUXWIOG8rMhpDTLVbvAc2d2wRicoYw2wGsJGLaurJT6BLC97bLXQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-util@30.0.2: - resolution: {integrity: sha512-8IyqfKS4MqprBuUpZNlFB5l+WFehc8bfCe1HSZFHzft2mOuND8Cvi9r1musli+u6F3TqanCZ/Ik4H4pXUolZIg==} + jest-util@30.5.1: + resolution: {integrity: sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@30.5.1: + resolution: {integrity: sha512-i/buJ56wTpxihE93hQYNMfdOThS87+HGvLZzZJmU4xggPcdTYQq051iwALLCHp3q+SkCGH+EFejQZz5EbBSkkg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@30.5.1: + resolution: {integrity: sha512-+FHJ7C+S7b3ySfhA1aFmoa6TztsnwZVv84ycPRn0tVN93np2EU4b8C/KadqA3l6igdjgLBTnUotab9ER0HLG8A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@30.5.1: + resolution: {integrity: sha512-Cbxh5v7AoLuFRmFJSM4/aHdQ68rjXvUWr716EE0Dh3I7T+T/3FgFKhOERGXHcU2Meftq9+9zxPM3TSNyI9D+HA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest@30.5.1: + resolution: {integrity: sha512-3qrR8+ZXFnn7y0H2yjWQNkGGBLBY4zTRoTMAq9zJcgwLLtlyonfsCLviIXK9xuE2KgIyM+M36AFcoK2DgFR36w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 @@ -1764,6 +2090,15 @@ packages: canvas: optional: true + jsdom@30.0.1: + resolution: {integrity: sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + peerDependencies: + canvas: ^3.2.3 + peerDependenciesMeta: + canvas: + optional: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -1791,10 +2126,6 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -1834,6 +2165,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1851,9 +2186,6 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -1862,6 +2194,9 @@ packages: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + meow@8.1.2: resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} engines: {node: '>=10'} @@ -1869,10 +2204,6 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -1881,13 +2212,13 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -1899,6 +2230,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -1924,12 +2259,20 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -1954,9 +2297,6 @@ packages: nwsapi@2.2.20: resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -1997,6 +2337,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -2008,6 +2351,9 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -2019,10 +2365,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2030,6 +2372,14 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-type@3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -2045,6 +2395,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -2069,27 +2423,19 @@ packages: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - pretty-format@30.0.2: - resolution: {integrity: sha512-yC5/EBSOrTtqhCKfLHqoUIAXVRZnukHPwWBJWR7h84Q3Be1DRQZLncwcfLoPA5RPQ65qfiCMqgYwdUuQ//eVpg==} + pretty-format@30.5.1: + resolution: {integrity: sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} @@ -2103,12 +2449,12 @@ packages: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-is@19.2.8: + resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==} + read-pkg-up@3.0.0: resolution: {integrity: sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw==} engines: {node: '>=4'} @@ -2140,6 +2486,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -2148,17 +2498,13 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - resolve@1.22.10: resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} engines: {node: '>= 0.4'} hasBin: true - rollup@4.34.9: - resolution: {integrity: sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==} + rollup@4.63.1: + resolution: {integrity: sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2191,14 +2537,11 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2210,23 +2553,18 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -2272,6 +2610,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -2286,6 +2628,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -2325,6 +2671,10 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + synckit@0.11.13: + resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} + engines: {node: ^14.18.0 || >=16.0.0} + 'tauri-plugin-serialplugin-api@file:': resolution: {directory: '', type: directory} @@ -2333,9 +2683,9 @@ packages: engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} text-extensions@1.9.0: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} @@ -2353,41 +2703,50 @@ packages: tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + tldts-core@7.4.11: + resolution: {integrity: sha512-CW3WN2rIIE/Of21mulhgnGOwoDyEFNygyIBOONSdyAuSATgMMUCpLeUlB+E8sAwA5xRV9hYPl+kyZ9citHCaKg==} + tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + tldts@7.4.11: + resolution: {integrity: sha512-aBiNayCfTQxuIJBm06M+xR14cYaYlDlSXZbgsnKzKNxDKUVq7KFwTjwBSsb7m9Y5xO8WfPnBc63WaYFMTGlvqw==} + hasBin: true tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} + engines: {node: '>=16'} + tr46@5.1.1: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} - ts-jest@29.3.4: - resolution: {integrity: sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==} + ts-jest@29.4.12: + resolution: {integrity: sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/transform': ^29.0.0 - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <7' peerDependenciesMeta: '@babel/core': optional: true @@ -2399,6 +2758,8 @@ packages: optional: true esbuild: optional: true + jest-util: + optional: true tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2443,6 +2804,13 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + engines: {node: '>=22.19.0'} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -2452,8 +2820,8 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + uuid@14.0.2: + resolution: {integrity: sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==} hasBin: true v8-to-istanbul@9.3.0: @@ -2524,25 +2892,39 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + whatwg-url@14.2.0: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + whatwg-url@17.1.0: + resolution: {integrity: sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==} + engines: {node: ^22.14.0 || >=24.0.0} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2555,12 +2937,13 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} @@ -2623,7 +3006,7 @@ snapshots: '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 '@asamuzakjp/css-color@3.2.0': dependencies: @@ -2633,6 +3016,21 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 + '@asamuzakjp/css-color@6.0.7': + dependencies: + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.2.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.5.2 + + '@asamuzakjp/dom-selector@8.3.2': + dependencies: + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.2 + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -2641,12 +3039,20 @@ snapshots: '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 '@babel/compat-data@7.27.2': {} + '@babel/compat-data@7.29.7': {} + '@babel/core@7.27.1': dependencies: '@ampproject/remapping': 2.3.0 @@ -2655,10 +3061,30 @@ snapshots: '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) '@babel/helpers': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.29.7 '@babel/template': 7.27.2 '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 + convert-source-map: 2.0.0 + debug: 4.4.0 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -2669,10 +3095,18 @@ snapshots: '@babel/generator@7.27.1': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-compilation-targets@7.27.2': @@ -2683,10 +3117,27 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.24.5 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.27.1 - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -2694,160 +3145,291 @@ snapshots: dependencies: '@babel/core': 7.27.1 '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/helper-validator-identifier': 7.29.7 '@babel/traverse': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-plugin-utils@7.27.1': {} '@babel/helper-string-parser@7.29.7': {} '@babel/helper-validator-identifier@7.25.9': {} - '@babel/helper-validator-identifier@7.27.1': {} - '@babel/helper-validator-identifier@7.29.7': {} '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} + '@babel/helpers@7.27.1': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 - '@babel/parser@7.27.2': + '@babel/helpers@7.29.7': dependencies: - '@babel/types': 7.27.1 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 '@babel/parser@7.29.7': dependencies: '@babel/types': 7.29.7 + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.1)': dependencies: '@babel/core': 7.27.1 '@babel/helper-plugin-utils': 7.27.1 + optional: true - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.1)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.27.1 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.27.1 '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@babel/traverse@7.27.1': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.29.7 '@babel/template': 7.27.2 - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.27.1': + '@babel/traverse@7.29.8': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color '@babel/types@7.29.7': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@bcoe/v8-coverage@0.2.3': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + '@csstools/color-helpers@5.0.2': {} + '@csstools/color-helpers@6.1.1': {} + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-color-parser@3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/color-helpers': 5.0.2 @@ -2855,12 +3437,45 @@ snapshots: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-color-parser@4.2.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.1.1 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.12(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@4.0.0': {} + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild/aix-ppc64@0.25.0': optional: true @@ -2936,8 +3551,19 @@ snapshots: '@esbuild/win32-x64@0.25.0': optional: true + '@exodus/bytes@1.15.1': {} + '@hutson/parse-repository-url@3.0.2': {} + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 @@ -2948,219 +3574,211 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/console@29.7.0': + '@jest/console@30.5.1': dependencies: - '@jest/types': 29.6.3 + '@jest/types': 30.5.1 '@types/node': 20.17.22 chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + jest-message-util: 30.5.1 + jest-util: 30.5.1 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@30.5.1': dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.5.1 + '@jest/pattern': 30.5.0 + '@jest/reporters': 30.5.1 + '@jest/test-result': 30.5.1 + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.22) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 + jest-changed-files: 30.5.1 + jest-config: 30.5.1(@types/node@20.17.22) + jest-haste-map: 30.5.1 + jest-message-util: 30.5.1 + jest-regex-util: 30.5.0 + jest-resolve: 30.5.1 + jest-resolve-dependencies: 30.5.1 + jest-runner: 30.5.1 + jest-runtime: 30.5.1 + jest-snapshot: 30.5.1 + jest-util: 30.5.1 + jest-validate: 30.5.1 + jest-watcher: 30.5.1 + pretty-format: 30.5.1 slash: 3.0.0 - strip-ansi: 6.0.1 transitivePeerDependencies: - babel-plugin-macros + - esbuild-register - supports-color - ts-node - '@jest/environment-jsdom-abstract@30.0.2(jsdom@26.1.0)': + '@jest/diff-sequences@30.5.0': {} + + '@jest/environment-jsdom-abstract@30.5.1(@types/jsdom@21.1.7)(jsdom@26.1.0)': dependencies: - '@jest/environment': 30.0.2 - '@jest/fake-timers': 30.0.2 - '@jest/types': 30.0.1 + '@jest/environment': 30.5.1 + '@jest/fake-timers': 30.5.1 + '@jest/types': 30.5.1 '@types/jsdom': 21.1.7 '@types/node': 20.17.22 - jest-mock: 30.0.2 - jest-util: 30.0.2 + jest-mock: 30.5.1 + jest-util: 30.5.1 jsdom: 26.1.0 - '@jest/environment@29.7.0': + '@jest/environment@30.5.1': dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 + '@jest/fake-timers': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 - jest-mock: 29.7.0 + jest-mock: 30.5.1 - '@jest/environment@30.0.2': + '@jest/expect-utils@30.5.1': dependencies: - '@jest/fake-timers': 30.0.2 - '@jest/types': 30.0.1 - '@types/node': 20.17.22 - jest-mock: 30.0.2 + '@jest/get-type': 30.5.0 - '@jest/expect-utils@29.7.0': + '@jest/expect@30.5.1': dependencies: - jest-get-type: 29.6.3 - - '@jest/expect@29.7.0': - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 + expect: 30.5.1 + jest-snapshot: 30.5.1 transitivePeerDependencies: - supports-color - '@jest/fake-timers@29.7.0': + '@jest/fake-timers@30.5.1': dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 + '@jest/types': 30.5.1 + '@sinonjs/fake-timers': 15.4.0 '@types/node': 20.17.22 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 + jest-message-util: 30.5.1 + jest-mock: 30.5.1 + jest-util: 30.5.1 - '@jest/fake-timers@30.0.2': - dependencies: - '@jest/types': 30.0.1 - '@sinonjs/fake-timers': 13.0.5 - '@types/node': 20.17.22 - jest-message-util: 30.0.2 - jest-mock: 30.0.2 - jest-util: 30.0.2 + '@jest/get-type@30.5.0': {} - '@jest/globals@29.7.0': + '@jest/globals@30.5.1': dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 + '@jest/environment': 30.5.1 + '@jest/expect': 30.5.1 + '@jest/types': 30.5.1 + jest-mock: 30.5.1 transitivePeerDependencies: - supports-color - '@jest/pattern@30.0.1': + '@jest/pattern@30.5.0': dependencies: '@types/node': 20.17.22 - jest-regex-util: 30.0.1 + jest-regex-util: 30.5.0 - '@jest/reporters@29.7.0': + '@jest/reporters@30.5.1': dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jest/console': 30.5.1 + '@jest/test-result': 30.5.1 + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 + '@jridgewell/trace-mapping': 0.3.31 '@types/node': 20.17.22 chalk: 4.1.2 collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 + exit-x: 0.2.2 + glob: 13.0.6 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.1.7 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 + jest-message-util: 30.5.1 + jest-util: 30.5.1 + jest-worker: 30.5.1 slash: 3.0.0 string-length: 4.0.2 - strip-ansi: 6.0.1 v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - '@jest/schemas@29.6.3': + '@jest/schemas@30.5.0': dependencies: - '@sinclair/typebox': 0.27.8 + '@sinclair/typebox': 0.34.52 - '@jest/schemas@30.0.1': + '@jest/snapshot-utils@30.5.1': dependencies: - '@sinclair/typebox': 0.34.37 + '@jest/types': 30.5.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 - '@jest/source-map@29.6.3': + '@jest/source-map@30.5.0': dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 + convert-source-map: 2.0.0 graceful-fs: 4.2.11 - '@jest/test-result@29.7.0': + '@jest/test-result@30.5.1': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.5.1 + '@jest/types': 30.5.1 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.2 - '@jest/test-sequencer@29.7.0': + '@jest/test-sequencer@30.5.1': dependencies: - '@jest/test-result': 29.7.0 + '@jest/test-result': 30.5.1 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 + jest-haste-map: 30.5.1 slash: 3.0.0 - '@jest/transform@29.7.0': + '@jest/transform@30.5.1': dependencies: - '@babel/core': 7.27.1 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 + '@babel/core': 7.29.7 + '@jest/types': 30.5.1 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 8.0.0 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 + jest-haste-map: 30.5.1 + jest-regex-util: 30.5.0 + jest-util: 30.5.1 pirates: 4.0.7 slash: 3.0.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - '@jest/types@29.6.3': + '@jest/types@30.5.1': dependencies: - '@jest/schemas': 29.6.3 + '@jest/pattern': 30.5.0 + '@jest/schemas': 30.5.0 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 '@types/node': 20.17.22 '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jest/types@30.0.1': + '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jest/pattern': 30.0.1 - '@jest/schemas': 30.0.1 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 20.17.22 - '@types/yargs': 17.0.33 - chalk: 4.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} @@ -3170,121 +3788,191 @@ snapshots: dependencies: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/sourcemap-codec@1.5.0': {} + optional: true '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 + optional: true - '@rollup/plugin-node-resolve@15.3.1(rollup@4.34.9)': + '@jridgewell/trace-mapping@0.3.31': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.34.9) - '@types/resolve': 1.20.2 - deepmerge: 4.3.1 - is-module: 1.0.0 - resolve: 1.22.10 - optionalDependencies: - rollup: 4.34.9 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@rollup/plugin-terser@0.4.4(rollup@4.34.9)': + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.39.0 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@parcel/watcher-android-arm64@2.6.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.6.0': + optional: true + + '@parcel/watcher-darwin-x64@2.6.0': + optional: true + + '@parcel/watcher-freebsd-x64@2.6.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.6.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.6.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.6.0': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.6.0': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.6.0': + optional: true + + '@parcel/watcher-linux-x64-musl@2.6.0': + optional: true + + '@parcel/watcher-win32-arm64@2.6.0': + optional: true + + '@parcel/watcher-win32-x64@2.6.0': + optional: true + + '@parcel/watcher@2.6.0': + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.7 optionalDependencies: - rollup: 4.34.9 + '@parcel/watcher-android-arm64': 2.6.0 + '@parcel/watcher-darwin-arm64': 2.6.0 + '@parcel/watcher-darwin-x64': 2.6.0 + '@parcel/watcher-freebsd-x64': 2.6.0 + '@parcel/watcher-linux-arm-glibc': 2.6.0 + '@parcel/watcher-linux-arm-musl': 2.6.0 + '@parcel/watcher-linux-arm64-glibc': 2.6.0 + '@parcel/watcher-linux-arm64-musl': 2.6.0 + '@parcel/watcher-linux-x64-glibc': 2.6.0 + '@parcel/watcher-linux-x64-musl': 2.6.0 + '@parcel/watcher-win32-arm64': 2.6.0 + '@parcel/watcher-win32-x64': 2.6.0 + + '@pkgjs/parseargs@0.11.0': + optional: true - '@rollup/plugin-typescript@12.1.4(rollup@4.34.9)(tslib@2.8.1)(typescript@5.6.3)': + '@pkgr/core@0.3.6': {} + + '@rollup/plugin-typescript@12.3.0(rollup@4.63.1)(tslib@2.8.1)(typescript@5.6.3)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.34.9) + '@rollup/pluginutils': 5.1.4(rollup@4.63.1) resolve: 1.22.10 typescript: 5.6.3 optionalDependencies: - rollup: 4.34.9 + rollup: 4.63.1 tslib: 2.8.1 - '@rollup/pluginutils@5.1.4(rollup@4.34.9)': + '@rollup/pluginutils@5.1.4(rollup@4.63.1)': dependencies: '@types/estree': 1.0.6 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.34.9 + rollup: 4.63.1 - '@rollup/rollup-android-arm-eabi@4.34.9': + '@rollup/rollup-android-arm-eabi@4.63.1': optional: true - '@rollup/rollup-android-arm64@4.34.9': + '@rollup/rollup-android-arm64@4.63.1': optional: true - '@rollup/rollup-darwin-arm64@4.34.9': + '@rollup/rollup-darwin-arm64@4.63.1': optional: true - '@rollup/rollup-darwin-x64@4.34.9': + '@rollup/rollup-darwin-x64@4.63.1': optional: true - '@rollup/rollup-freebsd-arm64@4.34.9': + '@rollup/rollup-freebsd-arm64@4.63.1': optional: true - '@rollup/rollup-freebsd-x64@4.34.9': + '@rollup/rollup-freebsd-x64@4.63.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.34.9': + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.34.9': + '@rollup/rollup-linux-arm-musleabihf@4.63.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.34.9': + '@rollup/rollup-linux-arm64-gnu@4.63.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.34.9': + '@rollup/rollup-linux-arm64-musl@4.63.1': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.34.9': + '@rollup/rollup-linux-loong64-gnu@4.63.1': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.34.9': + '@rollup/rollup-linux-loong64-musl@4.63.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.34.9': + '@rollup/rollup-linux-ppc64-gnu@4.63.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.34.9': + '@rollup/rollup-linux-ppc64-musl@4.63.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.34.9': + '@rollup/rollup-linux-riscv64-gnu@4.63.1': optional: true - '@rollup/rollup-linux-x64-musl@4.34.9': + '@rollup/rollup-linux-riscv64-musl@4.63.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.34.9': + '@rollup/rollup-linux-s390x-gnu@4.63.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.34.9': + '@rollup/rollup-linux-x64-gnu@4.63.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.34.9': + '@rollup/rollup-linux-x64-musl@4.63.1': optional: true - '@sinclair/typebox@0.27.8': {} + '@rollup/rollup-openbsd-x64@4.63.1': + optional: true - '@sinclair/typebox@0.34.37': {} + '@rollup/rollup-openharmony-arm64@4.63.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.1': + optional: true + + '@sinclair/typebox@0.34.52': {} '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - '@sinonjs/fake-timers@10.3.0': - dependencies: - '@sinonjs/commons': 3.0.1 - - '@sinonjs/fake-timers@13.0.5': + '@sinonjs/fake-timers@15.4.0': dependencies: '@sinonjs/commons': 3.0.1 @@ -3337,73 +4025,146 @@ snapshots: '@tauri-apps/cli-win32-ia32-msvc': 2.11.4 '@tauri-apps/cli-win32-x64-msvc': 2.11.4 + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true + '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.7 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.27.2 - '@babel/types': 7.27.1 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@types/babel__traverse@7.20.7': dependencies: - '@babel/types': 7.27.1 + '@babel/types': 7.29.7 '@types/estree@1.0.6': {} - '@types/graceful-fs@4.1.9': + '@types/estree@1.0.9': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@30.0.0': + dependencies: + expect: 30.5.1 + pretty-format: 30.5.1 + + '@types/jsdom@21.1.7': dependencies: '@types/node': 20.17.22 + '@types/tough-cookie': 4.0.5 + parse5: 7.3.0 + + '@types/minimist@1.2.5': {} + + '@types/node@20.17.22': + dependencies: + undici-types: 6.19.8 + + '@types/normalize-package-data@2.4.4': {} + + '@types/stack-utils@2.0.3': {} + + '@types/tough-cookie@4.0.5': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@ungap/structured-clone@1.4.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true - '@types/istanbul-lib-coverage@2.0.6': {} + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true - '@types/jest@29.5.14': - dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true - '@types/jsdom@21.1.7': - dependencies: - '@types/node': 20.17.22 - '@types/tough-cookie': 4.0.5 - parse5: 7.3.0 + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true - '@types/minimist@1.2.5': {} + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true - '@types/node@20.17.22': - dependencies: - undici-types: 6.19.8 + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true - '@types/normalize-package-data@2.4.4': {} + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true - '@types/resolve@1.20.2': {} + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true - '@types/stack-utils@2.0.3': {} + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true - '@types/tough-cookie@4.0.5': {} + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true - '@types/yargs-parser@21.0.3': {} + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true - '@types/yargs@17.0.33': + '@unrs/resolver-binding-wasm32-wasi@1.12.2': dependencies: - '@types/yargs-parser': 21.0.3 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true '@vitejs/plugin-vue@5.2.4(vite@6.2.5(@types/node@20.17.22)(terser@5.39.0))(vue@3.5.39(typescript@5.6.3))': dependencies: @@ -3499,7 +4260,8 @@ snapshots: jsonparse: 1.3.1 through: 2.3.8 - acorn@8.14.0: {} + acorn@8.14.0: + optional: true add-stream@1.0.0: {} @@ -3513,6 +4275,8 @@ snapshots: ansi-regex@5.0.1: {} + ansi-regex@6.3.0: {} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -3523,6 +4287,8 @@ snapshots: ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -3536,39 +4302,48 @@ snapshots: arrify@1.0.1: {} - async@3.2.6: {} - - babel-jest@29.7.0(@babel/core@7.27.1): + babel-jest@30.5.1(@babel/core@7.27.1): dependencies: '@babel/core': 7.27.1 - '@jest/transform': 29.7.0 + '@jest/transform': 30.5.1 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 8.0.0 + babel-preset-jest: 30.5.0(@babel/core@7.27.1) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + optional: true + + babel-jest@30.5.1(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@jest/transform': 30.5.1 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.27.1) + babel-plugin-istanbul: 8.0.0 + babel-preset-jest: 30.5.0(@babel/core@7.29.7) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - babel-plugin-istanbul@6.1.1: + babel-plugin-istanbul@8.0.0: dependencies: '@babel/helper-plugin-utils': 7.27.1 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 + istanbul-lib-instrument: 6.0.3 + test-exclude: 7.0.2 transitivePeerDependencies: - supports-color - babel-plugin-jest-hoist@29.6.3: + babel-plugin-jest-hoist@30.5.0: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.27.1 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.7 - babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.1): + babel-preset-current-node-syntax@1.2.0(@babel/core@7.27.1): dependencies: '@babel/core': 7.27.1 '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.1) @@ -3586,31 +4361,60 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.1) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.1) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.1) + optional: true - babel-preset-jest@29.6.3(@babel/core@7.27.1): + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) + + babel-preset-jest@30.5.0(@babel/core@7.27.1): dependencies: '@babel/core': 7.27.1 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) + babel-plugin-jest-hoist: 30.5.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.27.1) + optional: true + + babel-preset-jest@30.5.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + babel-plugin-jest-hoist: 30.5.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) balanced-match@1.0.2: {} - brace-expansion@1.1.11: + balanced-match@4.0.4: {} + + bidi-js@1.0.3: dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 + require-from-string: 2.0.2 - brace-expansion@2.0.1: + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 + concat-map: 0.0.1 brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 - braces@3.0.3: + brace-expansion@5.0.9: dependencies: - fill-range: 7.1.1 + balanced-match: 4.0.4 browserslist@4.24.5: dependencies: @@ -3656,11 +4460,9 @@ snapshots: char-regex@1.0.2: {} - ci-info@3.9.0: {} - - ci-info@4.2.0: {} + ci-info@4.4.0: {} - cjs-module-lexer@1.4.3: {} + cjs-module-lexer@2.2.1: {} cliui@7.0.4: dependencies: @@ -3690,7 +4492,8 @@ snapshots: color-name@1.1.4: {} - commander@2.20.3: {} + commander@2.20.3: + optional: true compare-func@2.0.0: dependencies: @@ -3822,27 +4625,17 @@ snapshots: core-util-is@1.0.3: {} - create-jest@29.7.0(@types/node@20.17.22): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.22) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + cssstyle@4.6.0: dependencies: '@asamuzakjp/css-color': 3.2.0 @@ -3857,6 +4650,13 @@ snapshots: whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + dateformat@3.0.3: {} de-indent@1.0.2: {} @@ -3874,15 +4674,17 @@ snapshots: decimal.js@10.5.0: {} + decimal.js@10.6.0: {} + dedent@1.6.0: {} deepmerge@4.3.1: {} detect-indent@6.1.0: {} - detect-newline@3.1.0: {} + detect-libc@2.1.2: {} - diff-sequences@29.6.3: {} + detect-newline@3.1.0: {} dot-prop@5.3.0: dependencies: @@ -3893,9 +4695,7 @@ snapshots: find-up: 3.0.0 minimatch: 3.1.2 - ejs@3.1.10: - dependencies: - jake: 10.9.2 + eastasianwidth@0.2.0: {} electron-to-chromium@1.5.157: {} @@ -3903,14 +4703,20 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + entities@6.0.1: {} entities@7.0.1: {} + entities@8.0.0: {} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 + es-module-lexer@2.3.2: {} + esbuild@0.25.0: optionalDependencies: '@esbuild/aix-ppc64': 0.25.0 @@ -3961,15 +4767,16 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - exit@0.1.2: {} + exit-x@0.2.2: {} - expect@29.7.0: + expect@30.5.1: dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 + '@jest/expect-utils': 30.5.1 + '@jest/get-type': 30.5.0 + jest-matcher-utils: 30.5.1 + jest-message-util: 30.5.1 + jest-mock: 30.5.1 + jest-util: 30.5.1 fast-json-stable-stringify@2.1.0: {} @@ -3977,18 +4784,14 @@ snapshots: dependencies: bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - find-up@2.1.0: dependencies: locate-path: 2.0.0 @@ -4007,7 +4810,10 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - fs.realpath@1.0.0: {} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 fsevents@2.3.3: optional: true @@ -4051,14 +4857,20 @@ snapshots: dependencies: ini: 1.3.8 - glob@7.2.3: + glob@10.5.0: dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@13.0.6: + dependencies: + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 globals@11.12.0: {} @@ -4073,6 +4885,15 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + handlebars@4.7.9: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + hard-rejection@2.1.0: {} has-flag@3.0.0: {} @@ -4095,6 +4916,12 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + html-escaper@2.0.2: {} http-proxy-agent@7.0.2: @@ -4126,11 +4953,6 @@ snapshots: indent-string@4.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@1.3.8: {} @@ -4141,13 +4963,15 @@ snapshots: dependencies: hasown: 2.0.2 + is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} is-generator-fn@2.1.0: {} - is-module@1.0.0: {} - - is-number@7.0.0: {} + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 is-obj@2.0.0: {} @@ -4167,23 +4991,13 @@ snapshots: istanbul-lib-coverage@3.2.2: {} - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.27.1 - '@babel/parser': 7.27.2 + '@babel/parser': 7.29.7 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.1 + semver: 7.8.5 transitivePeerDependencies: - supports-color @@ -4193,11 +5007,11 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@5.0.6: dependencies: + '@jridgewell/trace-mapping': 0.3.31 debug: 4.4.0 istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 transitivePeerDependencies: - supports-color @@ -4206,86 +5020,86 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jake@10.9.2: + jackspeak@3.4.3: dependencies: - async: 3.2.6 - chalk: 4.1.2 - filelist: 1.0.4 - minimatch: 3.1.2 + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 - jest-changed-files@29.7.0: + jest-changed-files@30.5.1: dependencies: execa: 5.1.1 - jest-util: 29.7.0 + jest-util: 30.5.1 p-limit: 3.1.0 - jest-circus@29.7.0: + jest-circus@30.5.1: dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.5.1 + '@jest/expect': 30.5.1 + '@jest/test-result': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 chalk: 4.1.2 co: 4.6.0 dedent: 1.6.0 is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-each: 30.5.1 + jest-matcher-utils: 30.5.1 + jest-message-util: 30.5.1 + jest-runtime: 30.5.1 + jest-snapshot: 30.5.1 + jest-util: 30.5.1 p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 + pretty-format: 30.5.1 + pure-rand: 7.0.1 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.17.22): + jest-cli@30.5.1(@types/node@20.17.22): dependencies: - '@jest/core': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.5.1 + '@jest/test-result': 30.5.1 + '@jest/types': 30.5.1 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.22) - exit: 0.1.2 + exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.22) - jest-util: 29.7.0 - jest-validate: 29.7.0 + jest-config: 30.5.1(@types/node@20.17.22) + jest-util: 30.5.1 + jest-validate: 30.5.1 yargs: 17.7.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node - jest-config@29.7.0(@types/node@20.17.22): + jest-config@30.5.1(@types/node@20.17.22): dependencies: - '@babel/core': 7.27.1 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + '@babel/core': 7.29.7 + '@jest/get-type': 30.5.0 + '@jest/pattern': 30.5.0 + '@jest/test-sequencer': 30.5.1 + '@jest/types': 30.5.1 + babel-jest: 30.5.1(@babel/core@7.29.7) chalk: 4.1.2 - ci-info: 3.9.0 + ci-info: 4.4.0 deepmerge: 4.3.1 - glob: 7.2.3 + glob: 13.0.6 graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 + jest-circus: 30.5.1 + jest-docblock: 30.5.0 + jest-environment-node: 30.5.1 + jest-regex-util: 30.5.0 + jest-resolve: 30.5.1 + jest-runner: 30.5.1 + jest-util: 30.5.1 + jest-validate: 30.5.1 parse-json: 5.2.0 - pretty-format: 29.7.0 + pretty-format: 30.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: @@ -4294,278 +5108,246 @@ snapshots: - babel-plugin-macros - supports-color - jest-diff@29.7.0: + jest-diff@30.5.1: dependencies: + '@jest/diff-sequences': 30.5.0 + '@jest/get-type': 30.5.0 chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 + pretty-format: 30.5.1 - jest-docblock@29.7.0: + jest-docblock@30.5.0: dependencies: detect-newline: 3.1.0 - jest-each@29.7.0: + jest-each@30.5.1: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.5.0 + '@jest/types': 30.5.1 chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 + jest-util: 30.5.1 + pretty-format: 30.5.1 - jest-environment-jsdom@30.0.2: + jest-environment-jsdom@30.5.1: dependencies: - '@jest/environment': 30.0.2 - '@jest/environment-jsdom-abstract': 30.0.2(jsdom@26.1.0) + '@jest/environment': 30.5.1 + '@jest/environment-jsdom-abstract': 30.5.1(@types/jsdom@21.1.7)(jsdom@26.1.0) '@types/jsdom': 21.1.7 - '@types/node': 20.17.22 jsdom: 26.1.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - jest-environment-node@29.7.0: + jest-environment-node@30.5.1: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.5.1 + '@jest/fake-timers': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 - jest-mock: 29.7.0 - jest-util: 29.7.0 - - jest-get-type@29.6.3: {} + jest-mock: 30.5.1 + jest-util: 30.5.1 + jest-validate: 30.5.1 - jest-haste-map@29.7.0: + jest-haste-map@30.5.1: dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 + '@jest/types': 30.5.1 + '@parcel/watcher': 2.6.0 '@types/node': 20.17.22 anymatch: 3.1.3 fb-watchman: 2.0.2 + fdir: 6.5.0(picomatch@4.0.7) graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 + jest-regex-util: 30.5.0 + jest-util: 30.5.1 + jest-worker: 30.5.1 + picomatch: 4.0.7 - jest-junit@16.0.0: + jest-junit@17.0.0: dependencies: mkdirp: 1.0.4 strip-ansi: 6.0.1 - uuid: 8.3.2 + uuid: 14.0.2 xml: 1.0.1 - jest-leak-detector@29.7.0: - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - - jest-matcher-utils@29.7.0: + jest-leak-detector@30.5.1: dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 + '@jest/get-type': 30.5.0 + pretty-format: 30.5.1 - jest-message-util@29.7.0: + jest-matcher-utils@30.5.1: dependencies: - '@babel/code-frame': 7.26.2 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 + '@jest/get-type': 30.5.0 chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 + jest-diff: 30.5.1 + pretty-format: 30.5.1 - jest-message-util@30.0.2: + jest-message-util@30.5.1: dependencies: '@babel/code-frame': 7.27.1 - '@jest/types': 30.0.1 + '@jest/types': 30.5.1 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 30.0.2 + jest-util: 30.5.1 + picomatch: 4.0.7 + pretty-format: 30.5.1 slash: 3.0.0 stack-utils: 2.0.6 - jest-mock@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 20.17.22 - jest-util: 29.7.0 - - jest-mock@30.0.2: + jest-mock@30.5.1: dependencies: - '@jest/types': 30.0.1 + '@jest/expect-utils': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 - jest-util: 30.0.2 - - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: - jest-resolve: 29.7.0 - - jest-regex-util@29.6.3: {} + jest-util: 30.5.1 - jest-regex-util@30.0.1: {} + jest-regex-util@30.5.0: {} - jest-resolve-dependencies@29.7.0: + jest-resolve-dependencies@30.5.1: dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 + jest-regex-util: 30.5.0 + jest-snapshot: 30.5.1 transitivePeerDependencies: - supports-color - jest-resolve@29.7.0: + jest-resolve@30.5.1: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.10 - resolve.exports: 2.0.3 + jest-haste-map: 30.5.1 + jest-util: 30.5.1 + jest-validate: 30.5.1 slash: 3.0.0 + unrs-resolver: 1.12.2 - jest-runner@29.7.0: + jest-runner@30.5.1: dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.5.1 + '@jest/environment': 30.5.1 + '@jest/source-map': 30.5.0 + '@jest/test-result': 30.5.1 + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 chalk: 4.1.2 emittery: 0.13.1 + exit-x: 0.2.2 graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 + jest-docblock: 30.5.0 + jest-environment-node: 30.5.1 + jest-haste-map: 30.5.1 + jest-leak-detector: 30.5.1 + jest-message-util: 30.5.1 + jest-resolve: 30.5.1 + jest-runtime: 30.5.1 + jest-util: 30.5.1 + jest-watcher: 30.5.1 + jest-worker: 30.5.1 p-limit: 3.1.0 - source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - jest-runtime@29.7.0: + jest-runtime@30.5.1: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 + '@jest/environment': 30.5.1 + '@jest/fake-timers': 30.5.1 + '@jest/globals': 30.5.1 + '@jest/source-map': 30.5.0 + '@jest/test-result': 30.5.1 + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 chalk: 4.1.2 - cjs-module-lexer: 1.4.3 + cjs-module-lexer: 2.2.1 collect-v8-coverage: 1.0.2 - glob: 7.2.3 + es-module-lexer: 2.3.2 + glob: 13.0.6 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 + jest-haste-map: 30.5.1 + jest-message-util: 30.5.1 + jest-mock: 30.5.1 + jest-regex-util: 30.5.0 + jest-resolve: 30.5.1 + jest-snapshot: 30.5.1 + jest-util: 30.5.1 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - jest-snapshot@29.7.0: + jest-snapshot@30.5.1: dependencies: - '@babel/core': 7.27.1 - '@babel/generator': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.1) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.1) - '@babel/types': 7.27.1 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.1) + '@babel/core': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.7) + '@babel/types': 7.29.7 + '@jest/expect-utils': 30.5.1 + '@jest/get-type': 30.5.0 + '@jest/snapshot-utils': 30.5.1 + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) chalk: 4.1.2 - expect: 29.7.0 + expect: 30.5.1 graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.7.1 + jest-diff: 30.5.1 + jest-matcher-utils: 30.5.1 + jest-message-util: 30.5.1 + jest-util: 30.5.1 + pretty-format: 30.5.1 + semver: 7.8.5 + synckit: 0.11.13 transitivePeerDependencies: - supports-color - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 20.17.22 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - - jest-util@30.0.2: + jest-util@30.5.1: dependencies: - '@jest/types': 30.0.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 chalk: 4.1.2 - ci-info: 4.2.0 + ci-info: 4.4.0 graceful-fs: 4.2.11 - picomatch: 4.0.2 + picomatch: 4.0.7 - jest-validate@29.7.0: + jest-validate@30.5.1: dependencies: - '@jest/types': 29.6.3 + '@jest/get-type': 30.5.0 + '@jest/types': 30.5.1 camelcase: 6.3.0 chalk: 4.1.2 - jest-get-type: 29.6.3 leven: 3.1.0 - pretty-format: 29.7.0 + pretty-format: 30.5.1 - jest-watcher@29.7.0: + jest-watcher@30.5.1: dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 + '@jest/test-result': 30.5.1 + '@jest/types': 30.5.1 '@types/node': 20.17.22 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 - jest-util: 29.7.0 + jest-util: 30.5.1 string-length: 4.0.2 - jest-worker@29.7.0: + jest-worker@30.5.1: dependencies: '@types/node': 20.17.22 - jest-util: 29.7.0 + '@ungap/structured-clone': 1.4.0 + jest-util: 30.5.1 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.17.22): + jest@30.5.1(@types/node@20.17.22): dependencies: - '@jest/core': 29.7.0 - '@jest/types': 29.6.3 + '@jest/core': 30.5.1 + '@jest/types': 30.5.1 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.22) + jest-cli: 30.5.1(@types/node@20.17.22) transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - supports-color - ts-node @@ -4603,6 +5385,32 @@ snapshots: - supports-color - utf-8-validate + jsdom@30.0.1: + dependencies: + '@asamuzakjp/css-color': 6.0.7 + '@asamuzakjp/dom-selector': 8.3.2 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.12(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.2 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.2 + undici: 8.10.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 17.1.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + jsesc@3.1.0: {} json-parse-better-errors@1.0.2: {} @@ -4617,8 +5425,6 @@ snapshots: kind-of@6.0.3: {} - kleur@3.0.3: {} - leven@3.1.0: {} lines-and-columns@1.2.4: {} @@ -4656,6 +5462,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.2: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -4670,18 +5478,16 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.1 + semver: 7.8.5 make-error@1.3.6: {} - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - map-obj@1.0.1: {} map-obj@4.3.0: {} + mdn-data@2.27.1: {} + meow@8.1.2: dependencies: '@types/minimist': 1.2.5 @@ -4698,22 +5504,17 @@ snapshots: merge-stream@2.0.0: {} - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - mimic-fn@2.1.0: {} min-indent@1.0.1: {} - minimatch@3.1.2: + minimatch@10.2.6: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 5.0.9 - minimatch@5.1.6: + minimatch@3.1.2: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 1.1.11 minimatch@9.0.9: dependencies: @@ -4727,6 +5528,8 @@ snapshots: minimist@1.2.8: {} + minipass@7.1.3: {} + mkdirp@1.0.4: {} modify-values@1.0.1: {} @@ -4739,10 +5542,14 @@ snapshots: nanoid@3.3.8: {} + napi-postinstall@0.3.4: {} + natural-compare@1.4.0: {} neo-async@2.6.2: {} + node-addon-api@7.1.1: {} + node-int64@0.4.0: {} node-releases@2.0.19: {} @@ -4769,10 +5576,6 @@ snapshots: nwsapi@2.2.20: {} - once@1.4.0: - dependencies: - wrappy: 1.0.2 - onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -4809,6 +5612,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + parse-json@4.0.0: dependencies: error-ex: 1.3.2 @@ -4825,18 +5630,30 @@ snapshots: dependencies: entities: 6.0.1 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + path-browserify@1.0.1: {} path-exists@3.0.0: {} path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + path-type@3.0.0: dependencies: pify: 3.0.0 @@ -4847,6 +5664,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.7: {} + pify@2.3.0: {} pify@3.0.0: {} @@ -4869,39 +5688,27 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - pretty-format@29.7.0: + pretty-format@30.5.1: dependencies: - '@jest/schemas': 29.6.3 + '@jest/react-is-18': react-is@18.3.1 + '@jest/react-is-19': react-is@19.2.8 + '@jest/schemas': 30.5.0 ansi-styles: 5.2.0 - react-is: 18.3.1 - - pretty-format@30.0.2: - dependencies: - '@jest/schemas': 30.0.1 - ansi-styles: 5.2.0 - react-is: 18.3.1 process-nextick-args@2.0.1: {} - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - punycode@2.3.1: {} - pure-rand@6.1.0: {} + pure-rand@7.0.1: {} q@1.5.1: {} quick-lru@4.0.1: {} - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - react-is@18.3.1: {} + react-is@19.2.8: {} + read-pkg-up@3.0.0: dependencies: find-up: 2.1.0 @@ -4949,43 +5756,50 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 resolve-from@5.0.0: {} - resolve.exports@2.0.3: {} - resolve@1.22.10: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rollup@4.34.9: + rollup@4.63.1: dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.34.9 - '@rollup/rollup-android-arm64': 4.34.9 - '@rollup/rollup-darwin-arm64': 4.34.9 - '@rollup/rollup-darwin-x64': 4.34.9 - '@rollup/rollup-freebsd-arm64': 4.34.9 - '@rollup/rollup-freebsd-x64': 4.34.9 - '@rollup/rollup-linux-arm-gnueabihf': 4.34.9 - '@rollup/rollup-linux-arm-musleabihf': 4.34.9 - '@rollup/rollup-linux-arm64-gnu': 4.34.9 - '@rollup/rollup-linux-arm64-musl': 4.34.9 - '@rollup/rollup-linux-loongarch64-gnu': 4.34.9 - '@rollup/rollup-linux-powerpc64le-gnu': 4.34.9 - '@rollup/rollup-linux-riscv64-gnu': 4.34.9 - '@rollup/rollup-linux-s390x-gnu': 4.34.9 - '@rollup/rollup-linux-x64-gnu': 4.34.9 - '@rollup/rollup-linux-x64-musl': 4.34.9 - '@rollup/rollup-win32-arm64-msvc': 4.34.9 - '@rollup/rollup-win32-ia32-msvc': 4.34.9 - '@rollup/rollup-win32-x64-msvc': 4.34.9 + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.1 + '@rollup/rollup-android-arm64': 4.63.1 + '@rollup/rollup-darwin-arm64': 4.63.1 + '@rollup/rollup-darwin-x64': 4.63.1 + '@rollup/rollup-freebsd-arm64': 4.63.1 + '@rollup/rollup-freebsd-x64': 4.63.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.1 + '@rollup/rollup-linux-arm-musleabihf': 4.63.1 + '@rollup/rollup-linux-arm64-gnu': 4.63.1 + '@rollup/rollup-linux-arm64-musl': 4.63.1 + '@rollup/rollup-linux-loong64-gnu': 4.63.1 + '@rollup/rollup-linux-loong64-musl': 4.63.1 + '@rollup/rollup-linux-ppc64-gnu': 4.63.1 + '@rollup/rollup-linux-ppc64-musl': 4.63.1 + '@rollup/rollup-linux-riscv64-gnu': 4.63.1 + '@rollup/rollup-linux-riscv64-musl': 4.63.1 + '@rollup/rollup-linux-s390x-gnu': 4.63.1 + '@rollup/rollup-linux-x64-gnu': 4.63.1 + '@rollup/rollup-linux-x64-musl': 4.63.1 + '@rollup/rollup-openbsd-x64': 4.63.1 + '@rollup/rollup-openharmony-arm64': 4.63.1 + '@rollup/rollup-win32-arm64-msvc': 4.63.1 + '@rollup/rollup-win32-ia32-msvc': 4.63.1 + '@rollup/rollup-win32-x64-gnu': 4.63.1 + '@rollup/rollup-win32-x64-msvc': 4.63.1 fsevents: 2.3.3 rrweb-cssom@0.8.0: {} @@ -5006,11 +5820,7 @@ snapshots: semver@7.7.1: {} - semver@7.7.2: {} - - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + semver@7.8.5: {} shebang-command@2.0.0: dependencies: @@ -5020,23 +5830,17 @@ snapshots: signal-exit@3.0.7: {} - sisteransi@1.0.5: {} + signal-exit@4.1.0: {} slash@3.0.0: {} - smob@1.5.0: {} - source-map-js@1.2.1: {} - source-map-support@0.5.13: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true source-map@0.6.1: {} @@ -5096,6 +5900,12 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -5110,6 +5920,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.3.0 + strip-bom@3.0.0: {} strip-bom@4.0.0: {} @@ -5138,6 +5952,10 @@ snapshots: symbol-tree@3.2.4: {} + synckit@0.11.13: + dependencies: + '@pkgr/core': 0.3.6 + 'tauri-plugin-serialplugin-api@file:': dependencies: '@tauri-apps/api': 2.6.0 @@ -5148,12 +5966,13 @@ snapshots: acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true - test-exclude@6.0.0: + test-exclude@7.0.2: dependencies: '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 + glob: 10.5.0 + minimatch: 10.2.6 text-extensions@1.9.0: {} @@ -5170,45 +5989,53 @@ snapshots: tldts-core@6.1.86: {} + tldts-core@7.4.11: {} + tldts@6.1.86: dependencies: tldts-core: 6.1.86 - tmpl@1.0.5: {} - - to-regex-range@5.0.1: + tldts@7.4.11: dependencies: - is-number: 7.0.0 + tldts-core: 7.4.11 tough-cookie@5.1.2: dependencies: tldts: 6.1.86 + tough-cookie@6.0.2: + dependencies: + tldts: 7.4.11 + tr46@5.1.1: dependencies: punycode: 2.3.1 + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + trim-newlines@3.0.1: {} - ts-jest@29.3.4(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.22))(typescript@5.6.3): + ts-jest@29.4.12(@babel/core@7.27.1)(@jest/transform@30.5.1)(@jest/types@30.5.1)(babel-jest@30.5.1(@babel/core@7.27.1))(jest-util@30.5.1)(jest@30.5.1(@types/node@20.17.22))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 - ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.22) - jest-util: 29.7.0 + handlebars: 4.7.9 + jest: 30.5.1(@types/node@20.17.22) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.7.2 + semver: 7.8.5 type-fest: 4.41.0 typescript: 5.6.3 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.27.1 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.1) + '@jest/transform': 30.5.1 + '@jest/types': 30.5.1 + babel-jest: 30.5.1(@babel/core@7.27.1) + jest-util: 30.5.1 tslib@2.8.1: {} @@ -5233,6 +6060,35 @@ snapshots: undici-types@6.19.8: {} + undici@8.10.2: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + update-browserslist-db@1.1.3(browserslist@4.24.5): dependencies: browserslist: 4.24.5 @@ -5241,11 +6097,11 @@ snapshots: util-deprecate@1.0.2: {} - uuid@8.3.2: {} + uuid@14.0.2: {} v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 @@ -5258,7 +6114,7 @@ snapshots: dependencies: esbuild: 0.25.0 postcss: 8.5.3 - rollup: 4.34.9 + rollup: 4.63.1 optionalDependencies: '@types/node': 20.17.22 fsevents: 2.3.3 @@ -5286,23 +6142,39 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - walker@1.0.8: - dependencies: - makeerror: 1.0.12 - webidl-conversions@7.0.0: {} + webidl-conversions@8.0.1: {} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 whatwg-mimetype@4.0.0: {} + whatwg-mimetype@5.0.0: {} + whatwg-url@14.2.0: dependencies: tr46: 5.1.1 webidl-conversions: 7.0.0 + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + whatwg-url@17.1.0: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + which@2.0.2: dependencies: isexe: 2.0.0 @@ -5315,12 +6187,16 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrappy@1.0.2: {} + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 - write-file-atomic@4.0.2: + write-file-atomic@5.0.1: dependencies: imurmurhash: 0.1.4 - signal-exit: 3.0.7 + signal-exit: 4.1.0 ws@8.18.3: {} diff --git a/src/api/backend.rs b/src/api/backend.rs index 01856380..7a2a0524 100644 --- a/src/api/backend.rs +++ b/src/api/backend.rs @@ -5,7 +5,7 @@ use crate::error::Error; use crate::port::tx_queue::PortTxQueue; use std::sync::Mutex; -pub use crate::exchange::io::{ExchangeIo, PortBackend}; +pub use crate::exchange::io::ExchangeIo; /// Configure AT session on physical or virtual path. pub fn configure_at_session_on_path( diff --git a/src/exchange/io.rs b/src/exchange/io.rs index e9567d33..580e3efd 100644 --- a/src/exchange/io.rs +++ b/src/exchange/io.rs @@ -7,9 +7,3 @@ pub trait ExchangeIo { fn purge_rx(&self) -> Result<(), Error>; fn write_payload(&self, payload: &[u8]) -> Result<(), Error>; } - -/// Physical port write / purge (alias for unified backend trait surface). -pub trait PortBackend: ExchangeIo { - fn write_physical(&self, path: &str, data: &[u8]) -> Result<(), Error>; - fn purge_rx(&self, path: &str) -> Result<(), Error>; -} diff --git a/src/hub/desktop.rs b/src/hub/desktop.rs index 95c2997f..01aacffc 100644 --- a/src/hub/desktop.rs +++ b/src/hub/desktop.rs @@ -52,7 +52,9 @@ use io_errors::{is_benign_read_error, is_disconnect_read_error}; use crate::cmux::CmuxSession; use crate::events::SerialEvent; -use crate::hub::shared::{finish_drain, wake_done, ExchangeWaiter, HubRoutingState, RxHubShared}; +use crate::hub::shared::{ + finish_drain, tick_read_slot, try_complete_drain, ExchangeWaiter, HubRoutingState, RxHubShared, +}; use serialport::SerialPort; use std::io::Read; use std::sync::atomic::AtomicBool; @@ -234,35 +236,7 @@ fn hub_loop( } if crate::sync_util::lock_or_recover(&shared.drain).is_some() { - let early_finish = { - let mut guard = crate::sync_util::lock_or_recover(&shared.drain); - #[derive(Clone, Copy)] - enum Kind { - Cancel, - Buffer, - } - let kind = match guard.as_ref() { - None => None, - Some(d) if d.cancel.load(std::sync::atomic::Ordering::SeqCst) => { - Some(Kind::Cancel) - } - Some(d) if Instant::now() >= d.deadline => Some(Kind::Buffer), - _ => None, - }; - kind.map(|k| { - let d = guard.take().unwrap(); - match k { - Kind::Cancel => (d.done, Err("exchange cancelled".into())), - Kind::Buffer => (d.done, Ok(d.buffer)), - } - }) - }; - if let Some((done, result)) = early_finish { - wake_done(&done, result); - continue; - } - // Slot may have been reclaimed/finished between the outer is_some() - // check and early_finish — don't stay in the drain branch and eat RX. + try_complete_drain(&shared); if crate::sync_util::lock_or_recover(&shared.drain).is_none() { continue; } @@ -284,35 +258,8 @@ fn hub_loop( shared.feed_bytes(&buf[..n], &mut routing); shared.dispatch_pending_events(std::mem::take(&mut routing.pending_events)); } - let finish = { - let mut guard = crate::sync_util::lock_or_recover(&shared.drain); - #[derive(Clone, Copy)] - enum Kind { - Empty, - Buffer, - } - let kind = match guard.as_ref() { - None => None, - Some(d) if d.last_byte_at.is_none() => Some(Kind::Empty), - Some(d) - if d.last_byte_at - .is_some_and(|t| t.elapsed() >= Duration::from_millis(d.idle_ms)) => - { - Some(Kind::Buffer) - } - _ => None, - }; - kind.map(|k| { - let d = guard.take().unwrap(); - match k { - Kind::Empty => (d.done, Ok(Vec::new())), - Kind::Buffer => (d.done, Ok(d.buffer)), - } - }) - }; - if let Some((done, result)) = finish { - wake_done(&done, result); - } + try_complete_drain(&shared); + tick_read_slot(&shared); continue; } diff --git a/src/hub/shared.rs b/src/hub/shared.rs index d86d217d..d4c8146b 100644 --- a/src/hub/shared.rs +++ b/src/hub/shared.rs @@ -6,30 +6,18 @@ use crate::events::SerialEvent; use crate::exchange::completion::check_exchange_complete; use crate::exchange::options::ResolvedExchangeOptions; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{self, RecvTimeoutError, SyncSender}; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; use tauri::ipc::Channel; pub(crate) const IDLE_BUFFER_CAP: usize = 64 * 1024; -/// Bounded grace window `recover_or_timeout()` waits for a `done` result -/// after losing the `read_slot` reclaim race. Deliberately independent of -/// the read's own `timeout_ms`/deadline — by the time this runs, that -/// deadline has already elapsed, so there is no "remaining" budget left to -/// derive a value from. This is a second, much shorter window covering -/// only the race itself: the hub thread has already taken the slot and is -/// in the middle of posting its result, which takes microseconds under -/// normal scheduling (no I/O in that path). Not a full elimination of the -/// race under pathological scheduler starvation, but any finite bound has -/// that same limit. -const READ_SLOT_RACE_RECOVERY_WINDOW: Duration = Duration::from_millis(50); - type ExchangeDone = Arc<( Mutex, ExchangeMatch), String>>>, Condvar, )>; -type DrainDone = Arc<(Mutex, String>>>, Condvar)>; -type ReadDone = Arc<(Mutex, String>>>, Condvar)>; +type ByteResultTx = SyncSender, String>>; /// Actions produced when routing incoming bytes in streaming mode. #[derive(Debug, Clone, PartialEq, Eq)] @@ -196,7 +184,7 @@ pub(crate) struct DrainSlot { pub(crate) started_at: Instant, pub(crate) deadline: Instant, pub(crate) solicited_prefixes: Vec, - pub(crate) done: DrainDone, + pub(crate) tx: ByteResultTx, } pub(crate) struct ReadSlot { @@ -205,7 +193,7 @@ pub(crate) struct ReadSlot { pub(crate) timeout_ms: u64, pub(crate) buffer: Vec, pub(crate) deadline: Instant, - pub(crate) done: ReadDone, + pub(crate) tx: ByteResultTx, } /// Shared hub state between the RX thread and API handlers. @@ -287,8 +275,6 @@ impl RxHubShared { session.feed_physical_rx(chunk); return; } - // Try drain without a separate is_some() check — that races with reclaim - // and route_drain_chunk used to drop bytes when the slot disappeared. if route_drain_chunk(self, &path, chunk) { return; } @@ -296,8 +282,7 @@ impl RxHubShared { route_exchange_chunk(self, &path, chunk, state, waiter); return; } - if crate::sync_util::lock_or_recover(&self.read_slot).is_some() { - route_read_slot_chunk(self, chunk); + if route_read_slot_chunk(self, chunk) { return; } if self.has_watch() { @@ -310,50 +295,9 @@ impl RxHubShared { /// Idle timers for push model: drain completion + watch batch flush + read deadlines. pub fn tick(&self, path: &str, state: &mut HubRoutingState) { tick_read_slot(self); - let completed = { - let mut guard = crate::sync_util::lock_or_recover(&self.drain); - #[derive(Clone, Copy)] - enum Kind { - Cancel, - Buffer, - Empty, - } - let kind = match guard.as_ref() { - None => None, - Some(d) if d.cancel.load(Ordering::SeqCst) => Some(Kind::Cancel), - Some(d) if Instant::now() >= d.deadline => Some(Kind::Buffer), - Some(d) - if d.last_byte_at - .is_some_and(|t| t.elapsed() >= Duration::from_millis(d.idle_ms)) => - { - Some(Kind::Buffer) - } - Some(d) - if d.last_byte_at.is_none() - && d.started_at.elapsed() >= Duration::from_millis(d.idle_ms) => - { - Some(Kind::Empty) - } - _ => None, - }; - kind.map(|k| { - let d = guard.take().unwrap(); - let result = match k { - Kind::Cancel => Err("exchange cancelled".into()), - Kind::Buffer => Ok(d.buffer), - Kind::Empty => Ok(Vec::new()), - }; - (d.done, result) - }) - }; - if let Some((done, result)) = completed { - wake_done(&done, result); - } + try_complete_drain(self); - let batch_timeout_ms = self - .watch - .lock() - .unwrap() + let batch_timeout_ms = crate::sync_util::lock_or_recover(&self.watch) .as_ref() .map(|w| w.batch_timeout_ms) .unwrap_or(1000); @@ -379,10 +323,7 @@ impl RxHubShared { pub fn buffered_len(&self) -> usize { let idle_len = crate::sync_util::lock_or_recover(&self.idle).len(); - let read_len = self - .read_slot - .lock() - .unwrap() + let read_len = crate::sync_util::lock_or_recover(&self.read_slot) .as_ref() .map(|slot| slot.buffer.len()) .unwrap_or(0); @@ -412,12 +353,10 @@ impl RxHubShared { if self.has_watch() { return Err("Cannot read while watch is active; use watch or exchange".into()); } - if crate::sync_util::lock_or_recover(&self.read_slot).is_some() { - return Err("read already in progress".into()); - } let max_bytes = max_bytes.max(1); - let deadline = Instant::now() + Duration::from_millis(timeout_ms); + let wait = Duration::from_millis(timeout_ms); + let deadline = Instant::now() + wait; let mut initial = Vec::new(); { @@ -436,101 +375,41 @@ impl RxHubShared { } } - let done = Arc::new((Mutex::new(None), Condvar::new())); + let (tx, rx) = mpsc::sync_channel(1); { - *crate::sync_util::lock_or_recover(&self.read_slot) = Some(ReadSlot { + let mut guard = crate::sync_util::lock_or_recover(&self.read_slot); + if guard.is_some() { + return Err("read already in progress".into()); + } + *guard = Some(ReadSlot { max_bytes, fill, timeout_ms, buffer: initial, deadline, - done: done.clone(), + tx, }); } - let (lock, cvar) = &*done; - let mut guard = crate::sync_util::lock_or_recover(lock); - while guard.is_none() { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - // Deadlock fix: drop the `done` mutex guard before locking - // `read_slot` — finish_read_slot() locks the same two mutexes - // in the opposite order (read_slot then done), so holding both - // here at once is an ABBA lock inversion. - drop(guard); - if let Some(slot) = crate::sync_util::lock_or_recover(&self.read_slot).take() { - if slot.buffer.is_empty() { - return Err(format!("no data received within {} ms", timeout_ms)); - } - return Ok(slot.buffer); - } - return Self::recover_or_timeout(lock, cvar, timeout_ms); - } - let (g, timeout_result) = cvar - .wait_timeout(guard, remaining) - .map_err(|e| e.to_string())?; - guard = g; - if guard.is_none() && timeout_result.timed_out() && Instant::now() >= deadline { - // Same ABBA fix as above. - drop(guard); + match rx.recv_timeout(wait) { + Ok(result) => result, + Err(RecvTimeoutError::Timeout) => { if let Some(slot) = crate::sync_util::lock_or_recover(&self.read_slot).take() { if slot.buffer.is_empty() { - return Err(format!("no data received within {} ms", timeout_ms)); + Err(format!("no data received within {} ms", timeout_ms)) + } else { + Ok(slot.buffer) } - return Ok(slot.buffer); + } else { + // Completer won the race — result is already in flight / sent. + rx.try_recv().unwrap_or_else(|_| { + Err(format!("no data received within {} ms", timeout_ms)) + }) } - return Self::recover_or_timeout(lock, cvar, timeout_ms); } - } - guard.take().unwrap() - } - - /// Re-check `done` after losing the `read_slot` reclaim race on a - /// timeout path: dropping the `done` guard to avoid the ABBA deadlock - /// with `finish_read_slot()` opens a window where the hub thread can - /// claim the slot and post its result to `done` before we re-lock - /// `read_slot` and find it already empty. Wait briefly for that result - /// instead of discarding it as a spurious timeout. - fn recover_or_timeout( - lock: &Mutex, String>>>, - cvar: &Condvar, - timeout_ms: u64, - ) -> Result, String> { - Self::recover_or_timeout_within(lock, cvar, timeout_ms, READ_SLOT_RACE_RECOVERY_WINDOW) - } - - // `window` is a parameter (not always `READ_SLOT_RACE_RECOVERY_WINDOW`) - // so tests can use a much wider margin than production's 50ms — a slow - // CI runner preempting a spawned thread past a tight window would - // otherwise make timing-based tests flaky independent of whether the - // production code is correct. - fn recover_or_timeout_within( - lock: &Mutex, String>>>, - cvar: &Condvar, - timeout_ms: u64, - window: Duration, - ) -> Result, String> { - let mut guard = crate::sync_util::lock_or_recover(lock); - let deadline = Instant::now() + window; - // Loop, not a single wait: `Condvar::wait_timeout` can return on a - // spurious wakeup with `guard` still `None` (no OS/libc condvar - // guarantees against this) — a single wait would then treat that - // spurious wakeup as "recovery window over, no result", discarding - // a real result that shows up a moment later, the same class of - // bug this function exists to fix. - while guard.is_none() { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - break; + Err(RecvTimeoutError::Disconnected) => { + Err(format!("no data received within {} ms", timeout_ms)) } - let (g, _) = cvar - .wait_timeout(guard, remaining) - .unwrap_or_else(|e| e.into_inner()); - guard = g; - } - match guard.take() { - Some(result) => result, - None => Err(format!("no data received within {} ms", timeout_ms)), } } @@ -586,9 +465,14 @@ impl RxHubShared { cancel: Arc, solicited_prefixes: Vec, ) -> Result, String> { - let done = Arc::new((Mutex::new(None), Condvar::new())); + let wait = Duration::from_millis(max_ms.saturating_add(500)); + let (tx, rx) = mpsc::sync_channel(1); { - *crate::sync_util::lock_or_recover(&self.drain) = Some(DrainSlot { + let mut guard = crate::sync_util::lock_or_recover(&self.drain); + if guard.is_some() { + return Err("drain already in progress".into()); + } + *guard = Some(DrainSlot { idle_ms, cancel, buffer: Vec::new(), @@ -596,42 +480,29 @@ impl RxHubShared { started_at: Instant::now(), deadline: Instant::now() + Duration::from_millis(max_ms), solicited_prefixes, - done: done.clone(), + tx, }); } - let (lock, cvar) = &*done; - let mut guard = crate::sync_util::lock_or_recover(lock); - let deadline = Instant::now() + Duration::from_millis(max_ms + 500); - while guard.is_none() { - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining.is_zero() { - // Same ABBA deadlock fix as read_request(): drop `done` before - // locking `drain` — finish_drain() takes them in the opposite - // order. - drop(guard); - // Same reclaim as read_request: take leftover slot, else recover posted done. + + match rx.recv_timeout(wait) { + Ok(result) => result, + Err(RecvTimeoutError::Timeout) => { if let Some(slot) = crate::sync_util::lock_or_recover(&self.drain).take() { if slot.buffer.is_empty() { - return Err("drain timed out waiting for hub".into()); - } - return Ok(slot.buffer); - } - return match Self::recover_or_timeout(lock, cvar, 0) { - Ok(buf) => Ok(buf), - Err(e) if e.contains("no data received") => { Err("drain timed out waiting for hub".into()) + } else { + Ok(slot.buffer) } - Err(e) => Err(e), - }; + } else { + rx.try_recv() + .unwrap_or_else(|_| Err("drain timed out waiting for hub".into())) + } } - let (g, _) = cvar - .wait_timeout(guard, remaining) - .map_err(|e| e.to_string())?; - guard = g; + Err(RecvTimeoutError::Disconnected) => Err("drain timed out waiting for hub".into()), } - guard.take().unwrap() } } + /// Append RX into the active drain slot. Returns `false` if there is no slot /// (caller must route elsewhere — never silently drop the chunk). pub(crate) fn route_drain_chunk(shared: &RxHubShared, path: &str, chunk: &[u8]) -> bool { @@ -689,12 +560,13 @@ pub(crate) fn route_watch_chunk(path: &str, chunk: &[u8], state: &mut HubRouting } } -pub(crate) fn route_read_slot_chunk(shared: &RxHubShared, chunk: &[u8]) { +/// Feed a read slot. Returns `false` if there is no slot (fall through). +pub(crate) fn route_read_slot_chunk(shared: &RxHubShared, chunk: &[u8]) -> bool { let completed = { let mut guard = crate::sync_util::lock_or_recover(&shared.read_slot); let ready = { let Some(slot) = guard.as_mut() else { - return; + return false; }; let remaining = slot.max_bytes.saturating_sub(slot.buffer.len()); if remaining > 0 { @@ -707,12 +579,13 @@ pub(crate) fn route_read_slot_chunk(shared: &RxHubShared, chunk: &[u8]) { None } else { let slot = guard.take().unwrap(); - Some((slot.done, Ok(slot.buffer))) + Some((slot.tx, Ok(slot.buffer))) } }; - if let Some((done, result)) = completed { - wake_done(&done, result); + if let Some((tx, result)) = completed { + let _ = tx.send(result); } + true } pub(crate) fn tick_read_slot(shared: &RxHubShared) { @@ -731,24 +604,60 @@ pub(crate) fn tick_read_slot(shared: &RxHubShared) { } else { Ok(slot.buffer) }; - Some((slot.done, result)) + Some((slot.tx, result)) }; - if let Some((done, result)) = completed { - wake_done(&done, result); + if let Some((tx, result)) = completed { + let _ = tx.send(result); } } -pub(crate) fn wake_done(done: &ReadDone, result: Result, String>) { - let (lock, cvar) = &**done; - *crate::sync_util::lock_or_recover(lock) = Some(result); - cvar.notify_all(); +/// Shared idle/deadline/cancel completion for drain (desktop poll + Android tick). +pub(crate) fn try_complete_drain(shared: &RxHubShared) { + let completed = { + let mut guard = crate::sync_util::lock_or_recover(&shared.drain); + let kind = match guard.as_ref() { + None => None, + Some(d) if d.cancel.load(Ordering::SeqCst) => Some(DrainCompleteKind::Cancel), + Some(d) if Instant::now() >= d.deadline => Some(DrainCompleteKind::Buffer), + Some(d) + if d.last_byte_at + .is_some_and(|t| t.elapsed() >= Duration::from_millis(d.idle_ms)) => + { + Some(DrainCompleteKind::Buffer) + } + Some(d) + if d.last_byte_at.is_none() + && d.started_at.elapsed() >= Duration::from_millis(d.idle_ms) => + { + Some(DrainCompleteKind::Empty) + } + _ => None, + }; + kind.map(|k| { + let d = guard.take().unwrap(); + let result = match k { + DrainCompleteKind::Cancel => Err("exchange cancelled".into()), + DrainCompleteKind::Buffer => Ok(d.buffer), + DrainCompleteKind::Empty => Ok(Vec::new()), + }; + (d.tx, result) + }) + }; + if let Some((tx, result)) = completed { + let _ = tx.send(result); + } +} + +#[derive(Clone, Copy)] +enum DrainCompleteKind { + Cancel, + Buffer, + Empty, } pub(crate) fn finish_read_slot(shared: &RxHubShared, result: Result, String>) { - // Take slot first so the read_slot guard drops before locking done (ABBA). - let slot = crate::sync_util::lock_or_recover(&shared.read_slot).take(); - if let Some(slot) = slot { - wake_done(&slot.done, result); + if let Some(slot) = crate::sync_util::lock_or_recover(&shared.read_slot).take() { + let _ = slot.tx.send(result); } } @@ -762,9 +671,8 @@ pub(crate) fn push_idle(shared: &RxHubShared, chunk: &[u8]) { } pub(crate) fn finish_drain(shared: &RxHubShared, result: Result, String>) { - let drain = crate::sync_util::lock_or_recover(&shared.drain).take(); - if let Some(drain) = drain { - wake_done(&drain.done, result); + if let Some(drain) = crate::sync_util::lock_or_recover(&shared.drain).take() { + let _ = drain.tx.send(result); } } @@ -992,109 +900,68 @@ mod tests { assert!(crate::sync_util::lock_or_recover(&shared.idle).is_empty()); } - // Regression coverage for RxHubShared::recover_or_timeout(). Exercises - // it directly (it's a private assoc fn, visible to this nested test - // module via `use super::*`), independent of the full ABBA-race timing - // in read_request() itself. Uses recover_or_timeout_within() with a - // wide window (well beyond each test's own posting delay) rather than - // the production 50ms constant, so a slow/preempted CI runner can't - // turn a correct implementation into a flaky test. + // --- Oneshot slot model (post Condvar) --- - #[test] - fn recover_or_timeout_returns_result_posted_during_recovery_window() { - let done: ReadDone = Arc::new((Mutex::new(None), Condvar::new())); - let done_bg = done.clone(); - thread::spawn(move || { - thread::sleep(Duration::from_millis(10)); - let (lock, cvar) = &*done_bg; - *crate::sync_util::lock_or_recover(lock) = Some(Ok(b"late".to_vec())); - cvar.notify_all(); - }); - let (lock, cvar) = &*done; - let result = RxHubShared::recover_or_timeout_within(lock, cvar, 5, Duration::from_secs(2)); - assert_eq!(result.expect("recovered result"), b"late"); + fn mock_read_slot(tx: ByteResultTx, buffer: Vec, max_bytes: usize, fill: bool) -> ReadSlot { + ReadSlot { + max_bytes, + fill, + timeout_ms: 100, + buffer, + deadline: Instant::now() + Duration::from_secs(5), + tx, + } } #[test] - fn recover_or_timeout_survives_spurious_wakeups() { - // Fires several notify_all()s with `done` still None before the - // real result lands — simulates the condvar spurious-wakeup case. - // A single-`wait_timeout` version returns a false timeout on the - // first one; the fixed loop keeps waiting out the recovery window. - let done: ReadDone = Arc::new((Mutex::new(None), Condvar::new())); - let done_bg = done.clone(); - thread::spawn(move || { - for _ in 0..3 { - thread::sleep(Duration::from_millis(5)); - done_bg.1.notify_all(); - } - thread::sleep(Duration::from_millis(5)); - let (lock, cvar) = &*done_bg; - *crate::sync_util::lock_or_recover(lock) = Some(Ok(b"after-spurious".to_vec())); - cvar.notify_all(); - }); - let (lock, cvar) = &*done; - let result = RxHubShared::recover_or_timeout_within(lock, cvar, 5, Duration::from_secs(2)); - assert_eq!(result.expect("recovered result"), b"after-spurious"); + fn route_read_slot_chunk_returns_false_when_no_slot() { + let shared = RxHubShared::new(); + assert!(!route_read_slot_chunk(&shared, b"x")); } #[test] - fn recover_or_timeout_falls_back_to_timeout_error_when_nothing_arrives() { - let done: ReadDone = Arc::new((Mutex::new(None), Condvar::new())); - let start = Instant::now(); - let result = RxHubShared::recover_or_timeout(&done.0, &done.1, 5); - let err = result.expect_err("no result ever posted"); - assert!(err.contains("no data received"), "unexpected: {err}"); - // Bounded by READ_SLOT_RACE_RECOVERY_WINDOW (50ms), not a hang. - assert!(start.elapsed() < Duration::from_secs(2)); - } - - // --- Post-#38: completing a slot takes it whole (no emptied-Some window) --- - - fn mock_done() -> ReadDone { - Arc::new((Mutex::new(None), Condvar::new())) + fn route_read_slot_chunk_completing_removes_slot_before_post() { + let shared = RxHubShared::new(); + let (tx, rx) = mpsc::sync_channel(1); + *crate::sync_util::lock_or_recover(&shared.read_slot) = + Some(mock_read_slot(tx, Vec::new(), 3, false)); + assert!(route_read_slot_chunk(&shared, b"xyz")); + assert!(crate::sync_util::lock_or_recover(&shared.read_slot).is_none()); + assert_eq!(rx.recv().unwrap().unwrap(), b"xyz"); } #[test] - fn route_read_slot_chunk_completing_removes_slot_before_post() { + fn feed_bytes_read_fallthrough_to_idle_when_slot_gone() { + // Mirror drain fallthrough: route_read_slot_chunk false → idle, no drop. let shared = RxHubShared::new(); - let done = mock_done(); - *crate::sync_util::lock_or_recover(&shared.read_slot) = Some(ReadSlot { - max_bytes: 3, - fill: false, - timeout_ms: 100, - buffer: Vec::new(), - deadline: Instant::now() + Duration::from_secs(5), - done: done.clone(), - }); - route_read_slot_chunk(&shared, b"xyz"); - assert!(crate::sync_util::lock_or_recover(&shared.read_slot).is_none()); - let guard = crate::sync_util::lock_or_recover(&done.0); - assert_eq!(guard.as_ref().unwrap().as_ref().unwrap(), b"xyz"); + shared.feed_bytes(b"saved", &mut HubRoutingState::new("p".into())); + assert_eq!( + &crate::sync_util::lock_or_recover(&shared.idle)[..], + b"saved" + ); } #[test] fn tick_read_slot_deadline_takes_whole_slot() { let shared = RxHubShared::new(); - let done = mock_done(); + let (tx, rx) = mpsc::sync_channel(1); *crate::sync_util::lock_or_recover(&shared.read_slot) = Some(ReadSlot { max_bytes: 64, fill: false, timeout_ms: 50, buffer: b"late".to_vec(), deadline: Instant::now() - Duration::from_millis(1), - done: done.clone(), + tx, }); tick_read_slot(&shared); assert!(crate::sync_util::lock_or_recover(&shared.read_slot).is_none()); - let guard = crate::sync_util::lock_or_recover(&done.0); - assert_eq!(guard.as_ref().unwrap().as_ref().unwrap(), b"late"); + assert_eq!(rx.recv().unwrap().unwrap(), b"late"); } #[test] - fn tick_drain_complete_takes_whole_slot() { + fn try_complete_drain_takes_whole_slot() { let shared = RxHubShared::new(); - let done: DrainDone = Arc::new((Mutex::new(None), Condvar::new())); + let (tx, rx) = mpsc::sync_channel(1); *crate::sync_util::lock_or_recover(&shared.drain) = Some(DrainSlot { idle_ms: 1, cancel: Arc::new(AtomicBool::new(false)), @@ -1103,13 +970,33 @@ mod tests { started_at: Instant::now() - Duration::from_millis(100), deadline: Instant::now() + Duration::from_secs(5), solicited_prefixes: vec![], - done: done.clone(), + tx, }); - let mut routing = HubRoutingState::new("p".into()); - shared.tick("p", &mut routing); + try_complete_drain(&shared); assert!(crate::sync_util::lock_or_recover(&shared.drain).is_none()); - let guard = crate::sync_util::lock_or_recover(&done.0); - assert_eq!(guard.as_ref().unwrap().as_ref().unwrap(), b"buf"); + assert_eq!(rx.recv().unwrap().unwrap(), b"buf"); + } + + #[test] + fn try_complete_drain_empty_waits_idle_from_started_at() { + let shared = RxHubShared::new(); + let (tx, rx) = mpsc::sync_channel(1); + *crate::sync_util::lock_or_recover(&shared.drain) = Some(DrainSlot { + idle_ms: 30, + cancel: Arc::new(AtomicBool::new(false)), + buffer: Vec::new(), + last_byte_at: None, + started_at: Instant::now(), + deadline: Instant::now() + Duration::from_secs(5), + solicited_prefixes: vec![], + tx, + }); + try_complete_drain(&shared); + assert!(crate::sync_util::lock_or_recover(&shared.drain).is_some()); + thread::sleep(Duration::from_millis(40)); + try_complete_drain(&shared); + assert!(crate::sync_util::lock_or_recover(&shared.drain).is_none()); + assert_eq!(rx.recv().unwrap().unwrap(), b""); } fn wait_until_drain_slot(shared: &RxHubShared) { @@ -1123,6 +1010,17 @@ mod tests { } } + fn wait_until_read_slot(shared: &RxHubShared) { + let start = Instant::now(); + while crate::sync_util::lock_or_recover(&shared.read_slot).is_none() { + assert!( + start.elapsed() < Duration::from_secs(2), + "read worker never installed slot" + ); + thread::sleep(Duration::from_millis(1)); + } + } + #[test] fn route_drain_chunk_returns_false_when_no_slot() { let shared = RxHubShared::new(); @@ -1140,9 +1038,24 @@ mod tests { } #[test] - fn drain_timeout_recovers_result_already_posted_to_done() { - // finish_drain posts before the wait loop's hard deadline; reclaim - // must return that Ok rather than a synthetic timeout. + fn drain_rejects_second_concurrent_slot() { + let shared = Arc::new(RxHubShared::new()); + let cancel = Arc::new(AtomicBool::new(false)); + let shared_bg = shared.clone(); + let handle = thread::spawn(move || { + shared_bg.drain(10_000, 5_000, Arc::new(AtomicBool::new(false)), vec![]) + }); + wait_until_drain_slot(&shared); + let err = shared + .drain(10, 100, cancel, vec![]) + .expect_err("second drain"); + assert!(err.contains("already in progress"), "unexpected: {err}"); + finish_drain(&shared, Ok(Vec::new())); + let _ = handle.join(); + } + + #[test] + fn drain_timeout_recovers_result_already_posted() { let shared = Arc::new(RxHubShared::new()); let cancel = Arc::new(AtomicBool::new(false)); let shared_bg = shared.clone(); @@ -1154,8 +1067,6 @@ mod tests { #[test] fn drain_timeout_reclaim_returns_buffer_left_in_slot() { - // max_ms=0 → wait loop hard deadline is ~500ms; inject bytes into the - // live slot without completing via tick so reclaim's take() path runs. let shared = Arc::new(RxHubShared::new()); let cancel = Arc::new(AtomicBool::new(false)); let shared_bg = shared.clone(); @@ -1194,4 +1105,14 @@ mod tests { "must not rewrite to generic timeout, got: {err}" ); } + + #[test] + fn read_request_timeout_recovers_result_already_posted() { + let shared = Arc::new(RxHubShared::new()); + let shared_bg = shared.clone(); + let handle = thread::spawn(move || shared_bg.read_request(64, 500, false)); + wait_until_read_slot(&shared); + finish_read_slot(&shared, Ok(b"late".to_vec())); + assert_eq!(handle.join().unwrap().expect("recovered"), b"late"); + } } diff --git a/src/lib.rs b/src/lib.rs index 2dcc72e9..127582d3 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,9 +166,13 @@ pub fn init() -> TauriPlugin { #[cfg(test)] mod tests { + #[cfg(desktop)] + mod acl_smoke_test; #[cfg(desktop)] mod available_ports_options_test; #[cfg(desktop)] + mod command_inventory_test; + #[cfg(desktop)] mod commands_test; #[cfg(desktop)] mod desktop_api_test; diff --git a/src/tests/acl_smoke_test.rs b/src/tests/acl_smoke_test.rs new file mode 100644 index 00000000..ad571bd6 --- /dev/null +++ b/src/tests/acl_smoke_test.rs @@ -0,0 +1,62 @@ +//! ACL smoke: deny-open is defined; open is not reachable without allow-open in default set. +//! +//! Full IPC capability enforcement needs an app fixture; `mock_app` bypasses the ACL +//! runtime. This test still fails loudly if permission wiring drifts. + +#[cfg(test)] +mod tests { + use std::fs; + use std::path::PathBuf; + + fn repo_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + } + + #[test] + fn deny_open_permission_is_defined() { + let open = + fs::read_to_string(repo_root().join("permissions/autogenerated/commands/open.toml")) + .expect("open.toml"); + assert!( + open.contains("identifier = \"deny-open\""), + "deny-open missing from open.toml" + ); + assert!( + open.contains("commands.deny = [\"open\"]"), + "deny-open must deny the open command" + ); + assert!( + open.contains("identifier = \"allow-open\""), + "allow-open missing from open.toml" + ); + assert!( + open.contains("commands.allow = [\"open\"]"), + "allow-open must allow the open command" + ); + } + + #[test] + fn default_capability_includes_allow_open_not_deny() { + let default = + fs::read_to_string(repo_root().join("permissions/default.toml")).expect("default.toml"); + assert!( + default.contains("\"allow-open\""), + "default set must grant allow-open" + ); + assert!( + !default.contains("\"deny-open\""), + "default set must not include deny-open" + ); + } + + /// Document the contract: a capability that omits allow-open (and does not + /// pull in serialplugin:default) must not list open as allowed. + #[test] + fn capability_without_allow_open_has_no_open_grant() { + // Minimal capability body an app would use when intentionally denying open. + let capability_permissions: &[&str] = &["serialplugin:allow-available-ports"]; + assert!(!capability_permissions + .iter() + .any(|p| *p == "serialplugin:allow-open" || *p == "serialplugin:default")); + } +} diff --git a/src/tests/command_inventory_test.rs b/src/tests/command_inventory_test.rs new file mode 100644 index 00000000..1d57e235 --- /dev/null +++ b/src/tests/command_inventory_test.rs @@ -0,0 +1,120 @@ +//! Command inventory: handler ↔ guest-js ↔ ACL permission files stay in sync. + +#[cfg(test)] +mod tests { + use std::collections::BTreeSet; + use std::fs; + use std::path::PathBuf; + + /// Keep in sync with `generate_handler!` in `src/lib.rs`. + const HANDLER_COMMANDS: &[&str] = &[ + "available_ports", + "managed_ports", + "cancel_read", + "close", + "close_all", + "force_close", + "open", + "capabilities", + "watch", + "unwatch", + "watch_ports", + "unwatch_ports", + "read", + "read_binary", + "write", + "write_binary", + "set_baud_rate", + "set_data_bits", + "set_flow_control", + "set_parity", + "set_stop_bits", + "set_timeout", + "write_request_to_send", + "write_data_terminal_ready", + "read_clear_to_send", + "read_data_set_ready", + "read_ring_indicator", + "read_carrier_detect", + "bytes_to_read", + "bytes_to_write", + "clear_buffer", + "set_break", + "clear_break", + "set_log_level", + "get_log_level", + "exchange", + "exchange_binary", + "cancel_exchange", + "at", + "at_phases", + "send_sms_pdu", + "configure_at_session", + "enable_mux", + "open_mux_channel", + "disable_mux", + ]; + + fn repo_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + } + + fn permission_command_names() -> BTreeSet { + let dir = repo_root().join("permissions/autogenerated/commands"); + fs::read_dir(&dir) + .unwrap_or_else(|e| panic!("read {}: {e}", dir.display())) + .filter_map(|e| e.ok()) + .filter_map(|e| { + let name = e.file_name().into_string().ok()?; + name.strip_suffix(".toml").map(str::to_string) + }) + .collect() + } + + fn guest_js_invoke_commands() -> BTreeSet { + let js = fs::read_to_string(repo_root().join("guest-js/serial-port.ts")) + .expect("guest-js/serial-port.ts"); + let needle = "plugin:serialplugin|"; + let mut out = BTreeSet::new(); + let mut rest = js.as_str(); + while let Some(i) = rest.find(needle) { + let after = &rest[i + needle.len()..]; + let end = after + .find(|c: char| !c.is_ascii_alphanumeric() && c != '_') + .unwrap_or(after.len()); + out.insert(after[..end].to_string()); + rest = &after[end..]; + } + out + } + + #[test] + fn handler_commands_match_permission_files() { + let perms = permission_command_names(); + let handler: BTreeSet<_> = HANDLER_COMMANDS.iter().map(|s| (*s).to_string()).collect(); + assert_eq!( + handler, perms, + "mismatch generate_handler! ↔ permissions/autogenerated/commands" + ); + } + + #[test] + fn guest_js_invokes_exactly_handler_commands() { + let js = guest_js_invoke_commands(); + let handler: BTreeSet<_> = HANDLER_COMMANDS.iter().map(|s| (*s).to_string()).collect(); + assert_eq!(js, handler, "mismatch guest-js invoke ↔ generate_handler!"); + } + + #[test] + fn default_permission_set_covers_all_allow_commands() { + let default = fs::read_to_string(repo_root().join("permissions/default.toml")) + .expect("permissions/default.toml"); + for cmd in HANDLER_COMMANDS { + let allow = format!("allow-{}", cmd.replace('_', "-")); + assert!( + default.contains(&allow), + "default.toml missing {allow} for command {cmd}" + ); + } + } +} diff --git a/src/tests/desktop_api_test.rs b/src/tests/desktop_api_test.rs index 00af3cc4..f42564fa 100644 --- a/src/tests/desktop_api_test.rs +++ b/src/tests/desktop_api_test.rs @@ -444,6 +444,7 @@ mod tests { use crate::events::ExchangeOptions; use crate::state::{ConnectedPort, PortState, SerialportInfo}; use serialport::SerialPort as SerialPortTrait; + use std::io::Read; use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Duration, Instant}; @@ -464,12 +465,33 @@ mod tests { }, ); + let (cmd_seen_tx, cmd_seen_rx) = std::sync::mpsc::sync_channel::<()>(1); + let (hold_tx, hold_rx) = std::sync::mpsc::channel::<()>(); + let drain = thread::spawn(move || { + let mut buf = [0u8; 256]; + let deadline = Instant::now() + Duration::from_secs(3); + while Instant::now() < deadline { + match master.read(&mut buf) { + Ok(n) if n > 0 => { + let _ = cmd_seen_tx.send(()); + break; + } + Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => continue, + _ => continue, + } + } + let _ = hold_rx.recv_timeout(Duration::from_secs(5)); + let _ = master; + }); + let sp_cancel = sp.clone(); let path_cancel = path.clone(); let cancel_elapsed = Arc::new(Mutex::new(None::)); let cancel_elapsed_bg = cancel_elapsed.clone(); let cancel_thread = thread::spawn(move || { - thread::sleep(Duration::from_millis(100)); + cmd_seen_rx + .recv_timeout(Duration::from_secs(3)) + .expect("exchange should write AT before cancel"); let start = Instant::now(); sp_cancel .cancel_exchange(path_cancel) @@ -488,6 +510,8 @@ mod tests { ); cancel_thread.join().expect("cancel thread join"); + let _ = hold_tx.send(()); + drain.join().expect("drain join"); let elapsed = cancel_elapsed .lock() .unwrap() @@ -523,9 +547,6 @@ mod tests { use std::thread; use std::time::{Duration, Instant}; - // Let prior PTY / hub threads from parallel tests settle (macOS). - thread::sleep(Duration::from_millis(150)); - let app = create_test_app(); let sp = app.state::>().inner().clone(); @@ -1517,6 +1538,8 @@ mod tests { fn exchange_fails_fast_on_disconnect() { use crate::events::ExchangeOptions; use crate::state::{ConnectedPort, PortState, SerialportInfo}; + use serialport::SerialPort as SerialPortTrait; + use std::io::Read; use std::thread; use std::time::{Duration, Instant}; @@ -1524,7 +1547,10 @@ mod tests { let serial_port = app.state::>().inner().clone(); let path = "pty-exchange-disconnect".to_string(); - let (_pty, master, slave) = pty_pair_locked(); + let (_pty, mut master, slave) = pty_pair_locked(); + master + .set_timeout(Duration::from_millis(50)) + .expect("master timeout"); serial_port.serialports.lock().unwrap().insert( path.clone(), SerialportInfo { @@ -1532,6 +1558,24 @@ mod tests { }, ); + let (cmd_seen_tx, cmd_seen_rx) = std::sync::mpsc::sync_channel::<()>(1); + let master_holder = thread::spawn(move || { + let mut buf = [0u8; 256]; + let deadline = Instant::now() + Duration::from_secs(3); + while Instant::now() < deadline { + match master.read(&mut buf) { + Ok(n) if n > 0 => { + let _ = cmd_seen_tx.send(()); + break; + } + Err(ref e) if e.kind() == std::io::ErrorKind::TimedOut => continue, + _ => continue, + } + } + // Drop master after AT is seen → disconnect the slave/hub. + drop(master); + }); + let sp = serial_port.clone(); let path_bg = path.clone(); let exchange_thread = thread::spawn(move || { @@ -1546,8 +1590,10 @@ mod tests { ) }); - thread::sleep(Duration::from_millis(80)); - drop(master); + cmd_seen_rx + .recv_timeout(Duration::from_secs(3)) + .expect("exchange should write AT before disconnect"); + master_holder.join().expect("master holder"); let start = Instant::now(); let exchange_result = exchange_thread.join().expect("join"); diff --git a/src/tests/invoke_contract_test.rs b/src/tests/invoke_contract_test.rs index dcc0008f..2a179c61 100644 --- a/src/tests/invoke_contract_test.rs +++ b/src/tests/invoke_contract_test.rs @@ -140,4 +140,91 @@ mod tests { let back: ExchangeMatch = serde_json::from_value(json).unwrap(); assert!(matches!(back, ExchangeMatch::Ok)); } + + #[test] + fn enable_mux_options_deserialize_camel_case() { + use crate::commands::EnableMuxOptions; + + let json = serde_json::json!({ + "command": "AT+CMUX=0,0,5,31", + "timeoutMs": 3000 + }); + let opts: EnableMuxOptions = serde_json::from_value(json).unwrap(); + assert_eq!(opts.command.as_deref(), Some("AT+CMUX=0,0,5,31")); + assert_eq!(opts.timeout_ms, Some(3000)); + } + + #[test] + fn at_session_config_deserialize_camel_case() { + use crate::at::session::AtSessionConfig; + use crate::events::{AtResultFormat, RxPrepareMode}; + + let json = serde_json::json!({ + "defaultTimeoutMs": 4000, + "defaultIdleMs": 50, + "defaultRxPrepare": "drain", + "stopOnError": false, + "appendCr": true, + "resultFormat": "verbose" + }); + let cfg: AtSessionConfig = serde_json::from_value(json).unwrap(); + assert_eq!(cfg.default_timeout_ms, Some(4000)); + assert_eq!(cfg.default_idle_ms, Some(50)); + assert_eq!(cfg.default_rx_prepare, Some(RxPrepareMode::Drain)); + assert_eq!(cfg.stop_on_error, Some(false)); + assert_eq!(cfg.append_cr, Some(true)); + assert_eq!(cfg.result_format, Some(AtResultFormat::Verbose)); + } + + #[test] + fn at_command_options_deserialize_camel_case() { + use crate::at::session::AtCommandOptions; + use crate::events::ExchangeCompletionMode; + + let json = serde_json::json!({ + "timeoutMs": 1500, + "completionMode": "atIntermediate", + "solicitedPrefixes": ["+CMGS:"], + "appendCr": false + }); + let opts: AtCommandOptions = serde_json::from_value(json).unwrap(); + assert_eq!(opts.timeout_ms, Some(1500)); + assert_eq!( + opts.completion_mode, + Some(ExchangeCompletionMode::AtIntermediate) + ); + assert_eq!( + opts.solicited_prefixes.as_deref(), + Some(&["+CMGS:".to_string()][..]) + ); + assert_eq!(opts.append_cr, Some(false)); + } + + #[test] + fn at_phase_and_sms_pdu_options_deserialize_camel_case() { + use crate::at::session::{AtPhase, AtPhaseWrite, SendSmsPduOptions}; + use crate::events::{AtResultFormat, ExchangeCompletionMode}; + + let phase_json = serde_json::json!({ + "write": "AT+CMGS=12", + "completionMode": "atIntermediate", + "timeoutMs": 2000, + "command": "AT+CMGS" + }); + let phase: AtPhase = serde_json::from_value(phase_json).unwrap(); + assert!(matches!(phase.write, AtPhaseWrite::Text(ref s) if s == "AT+CMGS=12")); + assert_eq!( + phase.completion_mode, + Some(ExchangeCompletionMode::AtIntermediate) + ); + assert_eq!(phase.timeout_ms, Some(2000)); + + let sms_json = serde_json::json!({ + "timeoutMs": 9000, + "resultFormat": "numeric" + }); + let sms: SendSmsPduOptions = serde_json::from_value(sms_json).unwrap(); + assert_eq!(sms.timeout_ms, Some(9000)); + assert_eq!(sms.result_format, Some(AtResultFormat::Numeric)); + } } diff --git a/tests/README.md b/tests/README.md index 555f58cc..b1b24458 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,5 +1,17 @@ # Tests +## Trust matrix + +| Layer | What it proves | Where | +|-------|----------------|-------| +| Jest | JS wrapper → `invoke` payload/shape | `tests/*.test.ts` | +| nextest desktop | PTY / hub / exchange / watch behavior | `src/tests/*` | +| golden | USB chipset byte parity | `crates/android-usb-serial` | +| Robolectric | Android fd / permission glue | `android/` | +| JNI | Full native bridge (local / nightly) | `android-integration-ci.sh test` | + +Emulator / JNI is **not** on every PR — keep it local or nightly. + ## Jest (guest-js) ```bash @@ -10,6 +22,7 @@ Key suites: - `watch-lifecycle.test.ts` — Channel + `watch` / `unwatch` - `port-operations.test.ts`, `encoding-operations.test.ts` +- `exchange.test.ts`, `exchange-options.test.ts` — native exchange payloads - `auto-reconnect.test.ts` — reconnect on `watch` disconnect Mocks: `@tauri-apps/api/core` (`invoke`, `Channel`) in `tests/setup.ts`. @@ -18,12 +31,21 @@ Mocks: `@tauri-apps/api/core` (`invoke`, `Channel`) in `tests/setup.ts`. ```bash cargo nextest run +# hub-only: +cargo test --lib hub:: ``` -- `watch_registry_test`, `invoke_contract_test`, `desktop_api_test::watch_sends_disconnect_when_pty_peer_closed` +Notable suites: + +- `command_inventory_test` — `generate_handler!` ↔ guest-js ↔ `permissions/autogenerated/commands` +- `invoke_contract_test` — camelCase serde for watch / exchange / AT / mux +- `acl_smoke_test` — deny-open permission wired; default includes allow-open +- `desktop_api_test` — PTY exchange / drain / disconnect ## Android ```bash cd android && ./gradlew test +# JNI (local): +./scripts/android-integration-ci.sh test ``` diff --git a/tests/exchange-options.test.ts b/tests/exchange-options.test.ts new file mode 100644 index 00000000..123c628d --- /dev/null +++ b/tests/exchange-options.test.ts @@ -0,0 +1,156 @@ +import { createTestSerialPort, setupTestMocks } from './test-utils'; +import { mockExchangeResponse } from './exchange-mock'; + +describe('SerialPort exchange options payload', () => { + beforeEach(() => { + setupTestMocks(); + }); + + function mockOpenAndExchange(mockInvoke: jest.Mock) { + mockInvoke.mockImplementation((cmd: string) => { + if (cmd === 'plugin:serialplugin|open') { + return Promise.resolve('/dev/tty.usbserial'); + } + if (cmd === 'plugin:serialplugin|exchange') { + return Promise.resolve(mockExchangeResponse('OK\r\n')); + } + if (cmd === 'plugin:serialplugin|exchange_binary') { + return Promise.resolve(mockExchangeResponse('>\r\n')); + } + return Promise.resolve(); + }); + } + + it('forwards timeoutMs and completionMode', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchange('AT', { + timeoutMs: 2500, + completionMode: 'atFinalLine', + }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange', + expect.objectContaining({ + options: expect.objectContaining({ + timeoutMs: 2500, + completionMode: 'atFinalLine', + }), + }), + ); + }); + + it('forwards resultFormat and solicitedPrefixes', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchange('AT+CMGS=1', { + resultFormat: 'numeric', + solicitedPrefixes: ['+CMGS:'], + }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange', + expect.objectContaining({ + options: expect.objectContaining({ + resultFormat: 'numeric', + solicitedPrefixes: ['+CMGS:'], + }), + }), + ); + }); + + it('forwards rxPrepare and drain timings', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchange('AT', { + rxPrepare: 'drain', + drainIdleMs: 40, + drainMaxMs: 200, + }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange', + expect.objectContaining({ + options: expect.objectContaining({ + rxPrepare: 'drain', + drainIdleMs: 40, + drainMaxMs: 200, + }), + }), + ); + }); + + it('forwards idleMs and terminators', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchange('AT', { + idleMs: 80, + terminators: ['OK', 'ERROR'], + }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange', + expect.objectContaining({ + options: expect.objectContaining({ + idleMs: 80, + terminators: ['OK', 'ERROR'], + }), + }), + ); + }); + + it('sends empty options object when omitted', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchange('AT'); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange', + expect.objectContaining({ options: {} }), + ); + }); + + it('forwards options on exchangeBinary', async () => { + const { mockInvoke } = setupTestMocks(); + mockOpenAndExchange(mockInvoke); + const port = createTestSerialPort(); + await port.open(); + await port.exchangeBinary(new Uint8Array([0x1a]), { + timeoutMs: 1000, + completionMode: 'atIntermediate', + }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|exchange_binary', + expect.objectContaining({ + options: expect.objectContaining({ + timeoutMs: 1000, + completionMode: 'atIntermediate', + }), + }), + ); + }); + + it('forwards enableMux timeoutMs camelCase', async () => { + const { mockInvoke } = setupTestMocks(); + mockInvoke.mockImplementation((cmd: string) => { + if (cmd === 'plugin:serialplugin|open') { + return Promise.resolve('/dev/tty.usbserial'); + } + return Promise.resolve(); + }); + const port = createTestSerialPort(); + await port.open(); + await port.enableMux({ command: 'AT+CMUX=0', timeoutMs: 3000 }); + expect(mockInvoke).toHaveBeenCalledWith( + 'plugin:serialplugin|enable_mux', + expect.objectContaining({ + options: { command: 'AT+CMUX=0', timeoutMs: 3000 }, + }), + ); + }); +}); From a7a62fa204d2519ab8bc93e0a4e9acf9a053044a Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Sun, 6 Sep 2026 10:08:04 +0400 Subject: [PATCH 02/15] test: harden coverage toward ideal matrix Fix flaky live-URC PTY wait, expand ACL/contracts/JNI exchange, Windows nextest, nightly emulator workflow, hub fixtures/chunking, golden negatives, and publish-surface smoke. Co-authored-by: Cursor --- .github/workflows/nightly-android.yml | 96 ++++++++++ .github/workflows/test.yml | 19 ++ .../app/tauri/serialplugin/MobileBridge.kt | 8 + .../serialplugin/manager/UsbFdBridgeTest.kt | 72 ++++++++ .../android-usb-serial/tests/golden_parity.rs | 27 +++ .../serialport/test/jni/ExchangeChainTest.kt | 32 ++++ .../serialport/test/jni/ExchangeChainTest.kt | 32 ++++ .../serialport/test/jni/UsbDetachChainTest.kt | 30 ++++ .../serialport/test/jni/UsbErrorChainTest.kt | 8 +- jest.config.js | 6 + scripts/check-publish-surface.sh | 38 ++++ scripts/ci-fast.sh | 30 ++++ src/android/registry.rs | 63 ++++++- src/android/test_harness.rs | 36 ++++ src/hub/shared.rs | 168 +++++++++++++++++- src/tests/acl_smoke_test.rs | 42 +++++ src/tests/desktop_api_test.rs | 33 ++-- .../fixtures/hub_scripts/creg_csq_ok.json | 12 ++ src/tests/invoke_contract_test.rs | 33 ++++ tests/README.md | 36 ++-- tests/command-inventory.test.ts | 78 ++++++++ 21 files changed, 875 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/nightly-android.yml create mode 100644 examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt create mode 100644 examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt create mode 100644 examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbDetachChainTest.kt create mode 100755 scripts/check-publish-surface.sh create mode 100755 scripts/ci-fast.sh create mode 100644 src/tests/fixtures/hub_scripts/creg_csq_ok.json create mode 100644 tests/command-inventory.test.ts diff --git a/.github/workflows/nightly-android.yml b/.github/workflows/nightly-android.yml new file mode 100644 index 00000000..a47817be --- /dev/null +++ b/.github/workflows/nightly-android.yml @@ -0,0 +1,96 @@ +# Nightly Android emulator JNI integration tests. +# +# Runs the FakeTransport harness via scripts/android-integration-ci.sh on an +# AVD (x86_64). Manual trigger + daily schedule; keep timeout generous for +# SDK/AVD cold start. + +name: Nightly Android Integration + +on: + schedule: + - cron: '0 4 * * *' + workflow_dispatch: + +jobs: + android-emulator: + runs-on: ubuntu-latest + timeout-minutes: 90 + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - name: Install pnpm + uses: pnpm/action-setup@v2 + with: + version: 9.15.4 + + - name: Setup Java 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + targets: x86_64-linux-android + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install Android SDK packages + run: | + yes | sdkmanager --licenses + sdkmanager \ + "platform-tools" \ + "platforms;android-34" \ + "build-tools;34.0.0" \ + "ndk;27.2.12479018" \ + "emulator" \ + "system-images;android-34;google_apis;x86_64" + + - name: Install cargo-ndk + run: cargo install cargo-ndk --locked + + - name: Install dependencies + run: pnpm install + + - name: Build JS + run: pnpm build + + - name: Relink workspace packages + run: pnpm install + + - name: Prebuild Android integration artifacts + env: + ANDROID_INTEGRATION_NDK_ARCH: x86_64 + ANDROID_NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/27.2.12479018 + NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/27.2.12479018 + run: chmod +x scripts/android-integration-ci.sh && ./scripts/android-integration-ci.sh prebuild + + - name: Run connectedDebugAndroidTest on emulator + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 34 + arch: x86_64 + target: google_apis + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: | + export ANDROID_INTEGRATION_NDK_ARCH=x86_64 + export ANDROID_NDK_HOME="${ANDROID_HOME}/ndk/27.2.12479018" + export NDK_HOME="${ANDROID_NDK_HOME}" + chmod +x scripts/android-integration-ci.sh + ./scripts/android-integration-ci.sh test diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 812d32b4..ffc2f38b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -222,11 +222,30 @@ jobs: with: version: 9.15.4 + - name: Install cargo-nextest + run: cargo install cargo-nextest --locked --force + - name: Install dependencies run: pnpm install - name: TypeScript check run: pnpm check + - name: Run Rust tests (no PTY — unix-only cfg) + env: + NEXTEST_EXPERIMENTAL_LIBTEST_JSON: 1 + run: cargo nextest run --workspace --message-format=libtest-json-plus > test-results.jsonx + - name: Run JavaScript tests run: pnpm test + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-windows + path: | + coverage/ + test-results/ + test-results.jsonx + if-no-files-found: warn diff --git a/android/src/main/kotlin/app/tauri/serialplugin/MobileBridge.kt b/android/src/main/kotlin/app/tauri/serialplugin/MobileBridge.kt index 123be022..3b8ba779 100644 --- a/android/src/main/kotlin/app/tauri/serialplugin/MobileBridge.kt +++ b/android/src/main/kotlin/app/tauri/serialplugin/MobileBridge.kt @@ -56,4 +56,12 @@ object MobileBridge { /** Debug-only: fail the next bulk-IN read (reader → onUsbError). */ @JvmStatic external fun testFakeInjectError(deviceName: String, reason: String): Boolean + + /** Debug-only: install AT exchange waiter on the hub for [path]. */ + @JvmStatic + external fun testExchangeBegin(path: String, command: String): Boolean + + /** Debug-only: wait for harness exchange; returns `OK:…` or `ERR:…`. */ + @JvmStatic + external fun testExchangeWait(path: String, timeoutMs: Long): String } diff --git a/android/src/test/kotlin/app/tauri/serialplugin/manager/UsbFdBridgeTest.kt b/android/src/test/kotlin/app/tauri/serialplugin/manager/UsbFdBridgeTest.kt index bfc59089..68a87071 100644 --- a/android/src/test/kotlin/app/tauri/serialplugin/manager/UsbFdBridgeTest.kt +++ b/android/src/test/kotlin/app/tauri/serialplugin/manager/UsbFdBridgeTest.kt @@ -249,4 +249,76 @@ class UsbFdBridgeTest { assertEquals(55, harness.bridge.openDeviceFd(DEVICE)) verify(harness.usbManager, times(1)).openDevice(device) } + + @Test + fun openDeviceFd_doubleGrantWhileWaiting() { + val harness = usbHarness() + val device = mockDevice() + stubDeviceList(harness.usbManager, device) + whenever(harness.usbManager.hasPermission(device)).thenReturn(false) + val conn = mockConn(77) + whenever(harness.usbManager.openDevice(device)).thenReturn(conn) + doAnswer { + harness.bridge.completePermissionForTest(DEVICE, true) + harness.bridge.completePermissionForTest(DEVICE, true) + null + }.whenever(harness.usbManager).requestPermission(eq(device), any()) + + assertEquals(77, harness.bridge.openDeviceFd(DEVICE)) + } + + @Test + fun openDeviceFd_afterDeny_retrySucceeds() { + val harness = usbHarness() + val device = mockDevice() + stubDeviceList(harness.usbManager, device) + whenever(harness.usbManager.hasPermission(device)).thenReturn(false) + val conn = mockConn(88) + whenever(harness.usbManager.openDevice(device)).thenReturn(conn) + + var grant = false + doAnswer { + harness.bridge.completePermissionForTest(DEVICE, grant) + null + }.whenever(harness.usbManager).requestPermission(eq(device), any()) + + val denied = assertThrows(IOException::class.java) { + harness.bridge.openDeviceFd(DEVICE) + } + assertTrue(denied.message!!.contains("permission denied")) + + grant = true + assertEquals(88, harness.bridge.openDeviceFd(DEVICE)) + } + + @Test + fun openDeviceFd_shutdownDuringPermissionWait() { + val harness = usbHarness() + val device = mockDevice() + stubDeviceList(harness.usbManager, device) + whenever(harness.usbManager.hasPermission(device)).thenReturn(false) + + val err = java.util.concurrent.atomic.AtomicReference() + val started = java.util.concurrent.CountDownLatch(1) + doAnswer { + started.countDown() + null + }.whenever(harness.usbManager).requestPermission(eq(device), any()) + + val t = Thread { + try { + harness.bridge.openDeviceFd(DEVICE) + } catch (e: Throwable) { + err.set(e) + } + } + t.start() + assertTrue(started.await(2, java.util.concurrent.TimeUnit.SECONDS)) + harness.bridge.shutdown() + harness.bridge.completePermissionForTest(DEVICE, false) + t.join(3000) + assertTrue("worker should finish", !t.isAlive) + assertTrue(err.get() is IOException) + assertTrue(err.get()!!.message!!.contains("permission denied")) + } } diff --git a/crates/android-usb-serial/tests/golden_parity.rs b/crates/android-usb-serial/tests/golden_parity.rs index 399d6c82..c7306c8d 100644 --- a/crates/android-usb-serial/tests/golden_parity.rs +++ b/crates/android-usb-serial/tests/golden_parity.rs @@ -445,6 +445,33 @@ fn assert_controls(path: &Path, got: &[RecordedControl], want: &[GoldenControl]) } } +#[test] +fn golden_negative_invalid_fixture_json_errors() { + let err = serde_json::from_str::("{not-valid-json"); + assert!(err.is_err(), "corrupt JSON must fail to parse"); +} + +#[test] +fn golden_negative_corrupt_expected_control_bytes_mismatch() { + let path = fixture_dir().join("ch34x/set_baud_9600.json"); + let text = fs::read_to_string(&path).expect("read fixture"); + let mut fixture: GoldenFixture = serde_json::from_str(&text).expect("parse fixture"); + assert!(!fixture.controls.is_empty()); + // Corrupt expected control payload so parity assertion must fail. + fixture.controls[0].data = "!!!!".to_string(); + let fake = setup_fake(&fixture); + let transport: Arc = Arc::new(fake.clone()); + let mut driver = create_driver(driver_type(&fixture.driver), fixture.port_index); + driver.open(&transport).expect("open"); + let suffix = scenario_suffix(&fixture); + let _ = replay_scenario(driver.as_mut(), &fixture.driver, &suffix); + let _ = driver.close(); + assert!( + !controls_match(&fake.recorded_controls(), &fixture.controls), + "corrupted expected control bytes must not match recorded transfers" + ); +} + fn format_bulk_diff(path: &Path, got: &[RecordedBulkOut], want: &[GoldenBulkOut]) -> String { let mut out = format!( "bulkOut mismatch for {}: got {} want {}\n", diff --git a/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt b/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt new file mode 100644 index 00000000..f40c3723 --- /dev/null +++ b/examples/serialport-test/android-integration/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt @@ -0,0 +1,32 @@ +package com.serialport.test.jni + +import app.tauri.serialplugin.MobileBridge +import org.junit.After +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import androidx.test.ext.junit.runners.AndroidJUnit4 + +@RunWith(AndroidJUnit4::class) +class ExchangeChainTest { + + @Before + fun setUp() = JniChainFixture.setUp() + + @After + fun tearDown() = JniChainFixture.tearDown() + + @Test + fun exchange_at_csq_with_urc_creg_completes_ok() { + assertTrue( + MobileBridge.testExchangeBegin(JniChainFixture.sessionPath, "AT+CSQ"), + ) + MobileBridge.testFakeInjectRx( + JniChainFixture.DEVICE_NAME, + "\r\n+CREG: 0,1\r\n\r\nAT+CSQ\r\n\r\n+CSQ: 10,99\r\n\r\nOK\r\n".toByteArray(), + ) + val result = MobileBridge.testExchangeWait(JniChainFixture.sessionPath, 10_000) + assertTrue("expected OK exchange, got $result", result.startsWith("OK:")) + } +} diff --git a/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt new file mode 100644 index 00000000..f40c3723 --- /dev/null +++ b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/ExchangeChainTest.kt @@ -0,0 +1,32 @@ +package com.serialport.test.jni + +import app.tauri.serialplugin.MobileBridge +import org.junit.After +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import androidx.test.ext.junit.runners.AndroidJUnit4 + +@RunWith(AndroidJUnit4::class) +class ExchangeChainTest { + + @Before + fun setUp() = JniChainFixture.setUp() + + @After + fun tearDown() = JniChainFixture.tearDown() + + @Test + fun exchange_at_csq_with_urc_creg_completes_ok() { + assertTrue( + MobileBridge.testExchangeBegin(JniChainFixture.sessionPath, "AT+CSQ"), + ) + MobileBridge.testFakeInjectRx( + JniChainFixture.DEVICE_NAME, + "\r\n+CREG: 0,1\r\n\r\nAT+CSQ\r\n\r\n+CSQ: 10,99\r\n\r\nOK\r\n".toByteArray(), + ) + val result = MobileBridge.testExchangeWait(JniChainFixture.sessionPath, 10_000) + assertTrue("expected OK exchange, got $result", result.startsWith("OK:")) + } +} diff --git a/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbDetachChainTest.kt b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbDetachChainTest.kt new file mode 100644 index 00000000..40b2ed17 --- /dev/null +++ b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbDetachChainTest.kt @@ -0,0 +1,30 @@ +package com.serialport.test.jni + +import app.tauri.serialplugin.MobileBridge +import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import androidx.test.ext.junit.runners.AndroidJUnit4 + +@RunWith(AndroidJUnit4::class) +class UsbDetachChainTest { + + @Before + fun setUp() = JniChainFixture.setUp() + + @After + fun tearDown() = JniChainFixture.tearDown() + + @Test + fun detach_clears_registry() { + assertTrue(MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath)) + MobileBridge.onDeviceDetached(JniChainFixture.DEVICE_NAME) + assertFalse( + "registry should drop port after USB detach", + MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath), + ) + } +} diff --git a/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt index 09777bd5..990d863d 100644 --- a/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt +++ b/examples/serialport-test/src-tauri/gen/android/app/src/androidTest/kotlin/com/serialport/test/jni/UsbErrorChainTest.kt @@ -22,7 +22,13 @@ class UsbErrorChainTest { fun fake_read_error_clears_registry() { assertTrue(MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath)) MobileBridge.testFakeInjectError(JniChainFixture.DEVICE_NAME, "device exploded") - Thread.sleep(1500) + val deadline = System.nanoTime() + 5_000_000_000L + while (System.nanoTime() < deadline) { + if (!MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath)) { + return + } + Thread.sleep(20) + } assertFalse( "registry should drop port after reader error → onUsbError", MobileBridge.testRegistryHasPort(JniChainFixture.sessionPath), diff --git a/jest.config.js b/jest.config.js index 3cf83cc5..6ace15d3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -12,6 +12,12 @@ export default { collectCoverage: true, coverageDirectory: 'coverage', coverageReporters: ['json', 'lcov', 'text', 'clover'], + collectCoverageFrom: ['guest-js/**/*.{ts,js}', '!guest-js/**/*.d.ts'], + coverageThreshold: { + global: { + lines: 85, + }, + }, coveragePathIgnorePatterns: [ '/node_modules/', '/target/', diff --git a/scripts/check-publish-surface.sh b/scripts/check-publish-surface.sh new file mode 100755 index 00000000..e84750fd --- /dev/null +++ b/scripts/check-publish-surface.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Verify npm publish surface: dist-js is present in the packed tarball. +# Optionally runs `cargo public-api` when installed. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "==> pnpm build" +pnpm build + +TMP="$(mktemp -d)" +cleanup() { rm -rf "$TMP"; } +trap cleanup EXIT + +echo "==> npm pack → $TMP" +npm pack --pack-destination "$TMP" >/dev/null +TGZ="$(ls "$TMP"/*.tgz | head -1)" +test -n "$TGZ" + +echo "==> inspect $(basename "$TGZ")" +tar -tzf "$TGZ" | tee "$TMP/files.txt" >/dev/null + +if ! grep -qE '^package/dist-js/' "$TMP/files.txt"; then + echo "error: packed tarball missing package/dist-js/" >&2 + echo "--- contents ---" >&2 + cat "$TMP/files.txt" >&2 + exit 1 +fi + +echo "ok: dist-js present in pack" + +if command -v cargo-public-api >/dev/null 2>&1 || cargo public-api --help >/dev/null 2>&1; then + echo "==> cargo public-api" + cargo public-api || true +else + echo "skip: cargo-public-api not installed (cargo install cargo-public-api)" +fi diff --git a/scripts/ci-fast.sh b/scripts/ci-fast.sh new file mode 100755 index 00000000..629f6176 --- /dev/null +++ b/scripts/ci-fast.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# Fast PR-oriented gate (no Android emulator / Robolectric / aarch64 cross). +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +echo "==> cargo fmt" +cargo fmt --all -- --check + +echo "==> cargo clippy (host)" +cargo clippy --workspace --all-targets -- -D warnings + +echo "==> android-usb-serial golden (fake-transport)" +cargo test -p android-usb-serial --features fake-transport + +echo "==> workspace tests" +if command -v cargo-nextest >/dev/null 2>&1; then + cargo nextest run --workspace +else + cargo test --workspace +fi + +echo "==> command inventory + ACL smoke" +cargo test --lib -- command_inventory acl_smoke + +echo "==> JS" +pnpm check && pnpm test + +echo "CI-FAST GATES PASSED" diff --git a/src/android/registry.rs b/src/android/registry.rs index db703de0..4843110a 100644 --- a/src/android/registry.rs +++ b/src/android/registry.rs @@ -130,11 +130,22 @@ pub mod test_harness { use crate::mock_serial::MockSerialPort; use crate::state::ConnectedPort; use serialport::SerialPort; - use std::sync::Arc; + use std::collections::HashMap; + use std::sync::{Arc, Mutex, OnceLock}; + + type WaiterMap = Mutex>>; + + fn exchange_waiters() -> &'static WaiterMap { + static WAITERS: OnceLock = OnceLock::new(); + WAITERS.get_or_init(|| Mutex::new(HashMap::new())) + } pub fn reset() { let _ = crate::android::driver_host::global_host().close(None); global_registry().close_all(); + if let Ok(mut map) = exchange_waiters().lock() { + map.clear(); + } } pub fn register_port(path: &str) { @@ -172,6 +183,56 @@ pub mod test_harness { crate::android::driver_host::global_host().write(path, data) } + /// Install an AT exchange waiter on the hub for [path] (debug JNI harness). + pub fn exchange_begin(path: &str, command: &str) -> Result<(), String> { + use crate::events::{AtResultFormat, ExchangeCompletionMode, RxPrepareMode}; + use crate::exchange::options::ResolvedExchangeOptions; + use crate::hub::ExchangeWaiter; + use std::sync::atomic::AtomicBool; + + let hub = hub_for(path).ok_or_else(|| format!("no hub for {path}"))?; + let _ = hub.shared().take_idle_bytes(); + let cancel = Arc::new(AtomicBool::new(false)); + let options = ResolvedExchangeOptions { + timeout_ms: 10_000, + max_bytes: 4096, + terminators: vec![], + idle_ms: None, + rx_prepare: RxPrepareMode::None, + drain_idle_ms: 50, + drain_max_ms: 200, + completion_mode: ExchangeCompletionMode::AtFinalLine, + result_format: AtResultFormat::Verbose, + command: Some(command.to_string()), + solicited_prefixes: vec![], + }; + let waiter = ExchangeWaiter::new(options, cancel); + hub.set_exchange_waiter(waiter.clone()); + exchange_waiters() + .lock() + .map_err(|e| e.to_string())? + .insert(path.to_string(), waiter); + Ok(()) + } + + /// Wait for the harness exchange started by [`exchange_begin`]. Returns `OK:…` / `ERR:…`. + pub fn exchange_wait(path: &str, timeout_ms: u64) -> String { + use crate::at::parse::ExchangeMatch; + + let waiter = match exchange_waiters().lock() { + Ok(mut map) => map.remove(path), + Err(e) => return format!("ERR:{e}"), + }; + let Some(waiter) = waiter else { + return format!("ERR:no exchange waiter for {path}"); + }; + match waiter.wait(timeout_ms) { + Ok((_, ExchangeMatch::Ok)) => "OK:ok".to_string(), + Ok((_, m)) => format!("OK:{m:?}"), + Err(e) => format!("ERR:{e}"), + } + } + #[cfg(feature = "android-test-harness")] fn cdc_dual_iface_fake() -> android_usb_serial::FakeTransport { use android_usb_serial::transport::{EndpointInfo, InterfaceInfo}; diff --git a/src/android/test_harness.rs b/src/android/test_harness.rs index 75f7ea77..8ab93b60 100644 --- a/src/android/test_harness.rs +++ b/src/android/test_harness.rs @@ -175,3 +175,39 @@ pub extern "system" fn Java_app_tauri_serialplugin_MobileBridge_testFakeInjectEr }; test_harness::fake_inject_error(&device_name, &reason) as jboolean } + +#[cfg(all(debug_assertions, target_os = "android"))] +#[no_mangle] +pub extern "system" fn Java_app_tauri_serialplugin_MobileBridge_testExchangeBegin( + mut env: JNIEnv, + _class: JClass, + path: JString, + command: JString, +) -> jboolean { + let Some(path) = jstring_to_rust(&mut env, &path) else { + return 0; + }; + let Some(command) = jstring_to_rust(&mut env, &command) else { + return 0; + }; + match test_harness::exchange_begin(&path, &command) { + Ok(()) => 1, + Err(_) => 0, + } +} + +#[cfg(all(debug_assertions, target_os = "android"))] +#[no_mangle] +pub extern "system" fn Java_app_tauri_serialplugin_MobileBridge_testExchangeWait<'local>( + mut env: JNIEnv<'local>, + _class: JClass<'local>, + path: JString<'local>, + timeout_ms: jlong, +) -> JString<'local> { + let Some(path) = jstring_to_rust(&mut env, &path) else { + return env.new_string("ERR:bad path").unwrap_or_default(); + }; + let timeout_ms = if timeout_ms < 0 { 0 } else { timeout_ms as u64 }; + let result = test_harness::exchange_wait(&path, timeout_ms); + env.new_string(result).unwrap_or_default() +} diff --git a/src/hub/shared.rs b/src/hub/shared.rs index d4c8146b..65e0806e 100644 --- a/src/hub/shared.rs +++ b/src/hub/shared.rs @@ -722,8 +722,11 @@ pub(crate) fn flush_watch_data( #[cfg(test)] mod tests { use super::*; + use crate::at::parse::ExchangeMatch; use crate::events::{AtResultFormat, ExchangeCompletionMode, RxPrepareMode}; + use std::path::PathBuf; use std::thread; + use tauri::ipc::Channel; #[test] fn exchange_waiter_completes_on_final_ok_line() { @@ -756,6 +759,51 @@ mod tests { .any(|a| matches!(a, RxRouteAction::UrcLine(s) if s.starts_with("^CARDLOCK")))); } + #[test] + fn feed_bytes_exchange_with_watch_emits_live_urc_pending() { + let shared = RxHubShared::new(); + let channel = Channel::::new(|_| Ok(())); + shared.attach_watch(channel, 100, 1024); + + let cancel = Arc::new(AtomicBool::new(false)); + let options = ResolvedExchangeOptions { + timeout_ms: 5000, + max_bytes: 4096, + terminators: vec![], + idle_ms: None, + rx_prepare: RxPrepareMode::None, + drain_idle_ms: 50, + drain_max_ms: 200, + completion_mode: ExchangeCompletionMode::AtFinalLine, + result_format: AtResultFormat::Verbose, + command: Some("AT+CSQ".into()), + solicited_prefixes: vec![], + }; + let waiter = ExchangeWaiter::new(options, cancel); + shared.set_exchange_waiter(waiter.clone()); + + let mut routing = HubRoutingState::new("p".into()); + shared.feed_bytes( + b"\r\n+CREG: 0,1\r\n\r\nAT+CSQ\r\n\r\n+CSQ: 10,99\r\n\r\nOK\r\n", + &mut routing, + ); + + let urcs: Vec<_> = routing + .pending_events + .iter() + .filter_map(|e| match e { + SerialEvent::Urc { line, .. } => Some(line.as_str()), + _ => None, + }) + .collect(); + assert!( + urcs.iter().any(|l| l.contains("+CREG:")), + "expected +CREG in pending URC, got {:?}", + urcs + ); + assert!(waiter.wait(100).is_ok()); + } + #[test] fn fail_all_waiters_completes_exchange_immediately() { let cancel = Arc::new(AtomicBool::new(false)); @@ -867,7 +915,6 @@ mod tests { #[test] fn read_request_rejects_when_watch_active() { - use tauri::ipc::Channel; let shared = Arc::new(RxHubShared::new()); let channel = Channel::::new(|_| Ok(())); shared.attach_watch(channel, 100, 1024); @@ -891,7 +938,6 @@ mod tests { #[test] fn attach_watch_clears_idle() { - use tauri::ipc::Channel; let shared = Arc::new(RxHubShared::new()); shared.feed_bytes(b"stale", &mut HubRoutingState::new("p".into())); assert!(!crate::sync_util::lock_or_recover(&shared.idle).is_empty()); @@ -1115,4 +1161,122 @@ mod tests { finish_read_slot(&shared, Ok(b"late".to_vec())); assert_eq!(handle.join().unwrap().expect("recovered"), b"late"); } + + fn at_csq_options() -> ResolvedExchangeOptions { + ResolvedExchangeOptions { + timeout_ms: 5000, + max_bytes: 4096, + terminators: vec![], + idle_ms: None, + rx_prepare: RxPrepareMode::None, + drain_idle_ms: 50, + drain_max_ms: 200, + completion_mode: ExchangeCompletionMode::AtFinalLine, + result_format: AtResultFormat::Verbose, + command: Some("AT+CSQ".into()), + solicited_prefixes: vec![], + } + } + + fn decode_hex(s: &str) -> Vec { + (0..s.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("hex")) + .collect() + } + + #[test] + fn hub_script_creg_csq_ok_fixture_feeds_urc_and_completes() { + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src/tests/fixtures/hub_scripts/creg_csq_ok.json"); + let text = std::fs::read_to_string(&path).expect("fixture"); + let fixture: serde_json::Value = serde_json::from_str(&text).expect("json"); + let command = fixture["command"].as_str().unwrap(); + let chunks: Vec> = fixture["chunks_hex"] + .as_array() + .unwrap() + .iter() + .map(|v| decode_hex(v.as_str().unwrap())) + .collect(); + let expected_urc = fixture["expected_urc_contains"].as_str().unwrap(); + let expected_match = fixture["expected_match"].as_str().unwrap(); + + let shared = RxHubShared::new(); + let channel = Channel::::new(|_| Ok(())); + shared.attach_watch(channel, 100, 1024); + let mut options = at_csq_options(); + options.command = Some(command.to_string()); + let waiter = ExchangeWaiter::new(options, Arc::new(AtomicBool::new(false))); + shared.set_exchange_waiter(waiter.clone()); + + let mut routing = HubRoutingState::new("p".into()); + for chunk in &chunks { + shared.feed_bytes(chunk, &mut routing); + } + + let urcs: Vec<_> = routing + .pending_events + .iter() + .filter_map(|e| match e { + SerialEvent::Urc { line, .. } => Some(line.clone()), + _ => None, + }) + .collect(); + assert!( + urcs.iter().any(|l| l.contains(expected_urc)), + "expected {expected_urc} in {:?}", + urcs + ); + let (_, matched) = waiter.wait(100).expect("complete"); + assert!(matches!(matched, ExchangeMatch::Ok)); + assert_eq!(expected_match, "ok"); + } + + #[test] + fn feed_bytes_chunked_vs_oneshot_same_exchange_match() { + let transcript = b"\r\n+CREG: 0,1\r\n\r\nAT+CSQ\r\n\r\n+CSQ: 10,99\r\n\r\nOK\r\n"; + + let run = |chunks: Vec<&[u8]>| { + let shared = RxHubShared::new(); + let waiter = ExchangeWaiter::new(at_csq_options(), Arc::new(AtomicBool::new(false))); + shared.set_exchange_waiter(waiter.clone()); + let mut routing = HubRoutingState::new("p".into()); + for chunk in chunks { + shared.feed_bytes(chunk, &mut routing); + } + waiter.wait(100).expect("complete").1 + }; + + let oneshot = run(vec![&transcript[..]]); + let bytewise = run(transcript.chunks(1).collect()); + assert_eq!(oneshot, bytewise); + assert!(matches!(oneshot, ExchangeMatch::Ok)); + } + + #[test] + fn fail_all_waiters_during_active_drain_completes_with_error() { + let shared = Arc::new(RxHubShared::new()); + let shared_bg = shared.clone(); + let handle = thread::spawn(move || { + shared_bg.drain(10_000, 5_000, Arc::new(AtomicBool::new(false)), vec![]) + }); + wait_until_drain_slot(&shared); + shared.fail_all_waiters("usb error"); + let err = handle.join().unwrap().expect_err("drain must fail"); + assert!(err.contains("usb error"), "unexpected: {err}"); + } + + #[test] + fn cancel_during_active_drain_completes_with_error() { + let shared = Arc::new(RxHubShared::new()); + let cancel = Arc::new(AtomicBool::new(false)); + let shared_bg = shared.clone(); + let cancel_bg = cancel.clone(); + let handle = thread::spawn(move || shared_bg.drain(10_000, 5_000, cancel_bg, vec![])); + wait_until_drain_slot(&shared); + cancel.store(true, Ordering::SeqCst); + shared.tick("p", &mut HubRoutingState::new("p".into())); + let err = handle.join().unwrap().expect_err("drain must cancel"); + assert!(err.contains("cancel"), "unexpected: {err}"); + } } diff --git a/src/tests/acl_smoke_test.rs b/src/tests/acl_smoke_test.rs index ad571bd6..c2061514 100644 --- a/src/tests/acl_smoke_test.rs +++ b/src/tests/acl_smoke_test.rs @@ -59,4 +59,46 @@ mod tests { .iter() .any(|p| *p == "serialplugin:allow-open" || *p == "serialplugin:default")); } + + #[test] + fn example_app_capability_grants_serialplugin_default_or_allow_open() { + let json = fs::read_to_string( + repo_root().join("examples/serialport-test/src-tauri/capabilities/default.json"), + ) + .expect("example capability"); + let value: serde_json::Value = serde_json::from_str(&json).expect("parse capability"); + let perms = value["permissions"] + .as_array() + .expect("permissions array") + .iter() + .filter_map(|v| v.as_str()) + .collect::>(); + assert!( + perms + .iter() + .any(|p| *p == "serialplugin:default" || *p == "serialplugin:allow-open"), + "example capability must include serialplugin:default or allow-open, got {perms:?}" + ); + } + + #[test] + fn synthetic_available_ports_only_capability_does_not_grant_open() { + let json = serde_json::json!({ + "identifier": "ports-only", + "permissions": ["serialplugin:allow-available-ports"] + }); + let perms = json["permissions"] + .as_array() + .expect("permissions array") + .iter() + .filter_map(|v| v.as_str()) + .collect::>(); + assert!( + !perms + .iter() + .any(|p| *p == "serialplugin:allow-open" || *p == "serialplugin:default"), + "ports-only capability must not grant open" + ); + assert!(!perms.iter().any(|p| p.contains("allow-open"))); + } } diff --git a/src/tests/desktop_api_test.rs b/src/tests/desktop_api_test.rs index f42564fa..dde2fe36 100644 --- a/src/tests/desktop_api_test.rs +++ b/src/tests/desktop_api_test.rs @@ -930,7 +930,7 @@ mod tests { use std::io::{Read, Write}; use std::sync::{Arc, Mutex}; use std::thread; - use std::time::Duration; + use std::time::{Duration, Instant}; use tauri::ipc::Channel; use tauri::ipc::InvokeResponseBody; @@ -1017,15 +1017,28 @@ mod tests { response.solicited_body ); - let urc_lines: Vec = events - .lock() - .unwrap() - .iter() - .filter_map(|e| match e { - SerialEvent::Urc { line, .. } => Some(line.clone()), - _ => None, - }) - .collect(); + // Channel delivery can lag the exchange return under parallel load — wait for URC. + let deadline = Instant::now() + Duration::from_secs(2); + let urc_lines = loop { + let lines: Vec = events + .lock() + .unwrap() + .iter() + .filter_map(|e| match e { + SerialEvent::Urc { line, .. } => Some(line.clone()), + _ => None, + }) + .collect(); + if lines.iter().any(|l| l.contains("+CREG:")) { + break lines; + } + assert!( + Instant::now() < deadline, + "expected live +CREG URC on watch during exchange, got {:?}", + lines + ); + thread::sleep(Duration::from_millis(5)); + }; assert!( urc_lines.iter().any(|l| l.contains("+CREG:")), "expected live +CREG URC on watch during exchange, got {:?}", diff --git a/src/tests/fixtures/hub_scripts/creg_csq_ok.json b/src/tests/fixtures/hub_scripts/creg_csq_ok.json new file mode 100644 index 00000000..529f1228 --- /dev/null +++ b/src/tests/fixtures/hub_scripts/creg_csq_ok.json @@ -0,0 +1,12 @@ +{ + "name": "creg_csq_ok", + "command": "AT+CSQ", + "chunks_hex": [ + "0d0a2b435245473a20302c310d0a0d0a", + "41542b4353510d0a0d0a", + "2b4353513a2031302c39390d0a0d0a", + "4f4b0d0a" + ], + "expected_urc_contains": "+CREG", + "expected_match": "ok" +} diff --git a/src/tests/invoke_contract_test.rs b/src/tests/invoke_contract_test.rs index 2a179c61..f7427ed3 100644 --- a/src/tests/invoke_contract_test.rs +++ b/src/tests/invoke_contract_test.rs @@ -227,4 +227,37 @@ mod tests { assert_eq!(sms.timeout_ms, Some(9000)); assert_eq!(sms.result_format, Some(AtResultFormat::Numeric)); } + + #[test] + fn watch_ports_options_deserialize_camel_case() { + use crate::events::WatchPortsOptions; + + let json = serde_json::json!({ + "singlePortPerDevice": true, + "pollIntervalMs": 1500 + }); + let opts: WatchPortsOptions = serde_json::from_value(json).unwrap(); + assert_eq!(opts.single_port_per_device, Some(true)); + assert_eq!(opts.poll_interval_ms, Some(1500)); + } + + #[test] + fn clear_buffer_args_deserialize_camel_case() { + use crate::state::ClearBuffer; + + #[derive(Deserialize)] + struct ClearBufferArgs { + path: String, + #[serde(rename = "bufferType")] + buffer_type: ClearBuffer, + } + + let json = serde_json::json!({ + "path": "/dev/ttyUSB0", + "bufferType": "Input" + }); + let args: ClearBufferArgs = serde_json::from_value(json).unwrap(); + assert_eq!(args.path, "/dev/ttyUSB0"); + assert_eq!(args.buffer_type, ClearBuffer::Input); + } } diff --git a/tests/README.md b/tests/README.md index b1b24458..4d2aacd6 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,15 +2,19 @@ ## Trust matrix -| Layer | What it proves | Where | -|-------|----------------|-------| -| Jest | JS wrapper → `invoke` payload/shape | `tests/*.test.ts` | -| nextest desktop | PTY / hub / exchange / watch behavior | `src/tests/*` | -| golden | USB chipset byte parity | `crates/android-usb-serial` | -| Robolectric | Android fd / permission glue | `android/` | -| JNI | Full native bridge (local / nightly) | `android-integration-ci.sh test` | +| Layer | What it proves | Where | CI job | +|-------|----------------|-------|--------| +| Jest | JS wrapper → `invoke` payload/shape | `tests/*.test.ts` | `test` (Ubuntu/macOS), `windows` | +| nextest desktop | PTY / hub / exchange / watch | `src/tests/*` | `test` (Ubuntu/macOS); Windows: `cargo test --lib` (PTY `cfg(unix)` skipped) | +| golden | USB chipset byte parity | `crates/android-usb-serial` | `test` (Ubuntu/macOS) | +| Robolectric | Android fd / permission glue | `android/` | `test` Ubuntu only — **requires JDK 17** (`JAVA_HOME`) | +| JNI prebuild | NDK + sync androidTest sources | `android-integration-ci.sh prebuild` | `android-integration` | +| JNI emulator | FakeTransport Rx/Tx/Detach/Error (+ AT) | `android-integration-ci.sh test` | **nightly** / local — not every PR | -Emulator / JNI is **not** on every PR — keep it local or nightly. +Emulator / JNI connected tests are **not** on every PR. + +Local fast gate: `./scripts/ci-fast.sh` +Full migration gate: `./scripts/verify-android-usb-migration.sh` ## Jest (guest-js) @@ -24,9 +28,12 @@ Key suites: - `port-operations.test.ts`, `encoding-operations.test.ts` - `exchange.test.ts`, `exchange-options.test.ts` — native exchange payloads - `auto-reconnect.test.ts` — reconnect on `watch` disconnect +- `command-inventory.test.ts` — invoke names match Rust handler set Mocks: `@tauri-apps/api/core` (`invoke`, `Channel`) in `tests/setup.ts`. +Coverage: Jest fails the suite if guest-js line coverage drops below 85%. + ## Rust ```bash @@ -40,12 +47,21 @@ Notable suites: - `command_inventory_test` — `generate_handler!` ↔ guest-js ↔ `permissions/autogenerated/commands` - `invoke_contract_test` — camelCase serde for watch / exchange / AT / mux - `acl_smoke_test` — deny-open permission wired; default includes allow-open -- `desktop_api_test` — PTY exchange / drain / disconnect +- `desktop_api_test` — PTY exchange / drain / disconnect / live URC ## Android ```bash +# JDK 17 required for Robolectric / Gradle 8.9 +export JAVA_HOME="$(/usr/libexec/java_home -v 17 2>/dev/null || echo "$JAVA_HOME")" cd android && ./gradlew test -# JNI (local): + +# JNI (local or nightly): ./scripts/android-integration-ci.sh test ``` + +## Hardware (local only) + +- Playground AT quick buttons: `pnpm playground` +- `examples/usb-driver-tester` — real chips +- `spike_fd` — ignored without hardware diff --git a/tests/command-inventory.test.ts b/tests/command-inventory.test.ts new file mode 100644 index 00000000..efea4b73 --- /dev/null +++ b/tests/command-inventory.test.ts @@ -0,0 +1,78 @@ +import * as fs from 'fs'; +import * as path from 'path'; + +/** Keep in sync with `HANDLER_COMMANDS` in `src/tests/command_inventory_test.rs`. */ +const HANDLER_COMMANDS = [ + 'available_ports', + 'managed_ports', + 'cancel_read', + 'close', + 'close_all', + 'force_close', + 'open', + 'capabilities', + 'watch', + 'unwatch', + 'watch_ports', + 'unwatch_ports', + 'read', + 'read_binary', + 'write', + 'write_binary', + 'set_baud_rate', + 'set_data_bits', + 'set_flow_control', + 'set_parity', + 'set_stop_bits', + 'set_timeout', + 'write_request_to_send', + 'write_data_terminal_ready', + 'read_clear_to_send', + 'read_data_set_ready', + 'read_ring_indicator', + 'read_carrier_detect', + 'bytes_to_read', + 'bytes_to_write', + 'clear_buffer', + 'set_break', + 'clear_break', + 'set_log_level', + 'get_log_level', + 'exchange', + 'exchange_binary', + 'cancel_exchange', + 'at', + 'at_phases', + 'send_sms_pdu', + 'configure_at_session', + 'enable_mux', + 'open_mux_channel', + 'disable_mux', +] as const; + +function guestJsInvokeCommands(source: string): Set { + const needle = 'plugin:serialplugin|'; + const out = new Set(); + let rest = source; + while (true) { + const i = rest.indexOf(needle); + if (i < 0) break; + const after = rest.slice(i + needle.length); + const end = after.search(/[^A-Za-z0-9_]/); + const name = end < 0 ? after : after.slice(0, end); + out.add(name); + rest = after.slice(name.length); + } + return out; +} + +describe('command inventory (guest-js)', () => { + it('extracts plugin:serialplugin|NAME invokes matching handler list', () => { + const file = path.join(__dirname, '..', 'guest-js', 'serial-port.ts'); + const source = fs.readFileSync(file, 'utf8'); + const found = guestJsInvokeCommands(source); + const expected = new Set(HANDLER_COMMANDS); + expect([...found].sort()).toEqual([...expected].sort()); + expect(found.size).toBe(HANDLER_COMMANDS.length); + }); +}); From a7a8092023aad85e29ac3efb8c7632be8d28d4b0 Mon Sep 17 00:00:00 2001 From: Pavel Kuzmin Date: Sun, 6 Sep 2026 10:12:44 +0400 Subject: [PATCH 03/15] fix: address Cubic review on PR #40 Return open() canonical path, restore deprecated PortBackend, cover read/drain reclaim race, and tighten inventory/AT tests. Co-authored-by: Cursor --- .../src/components/TerminalPanel.vue | 14 ++++------ examples/serialport-test/src/quickAt.ts | 27 +++++++++++++++++++ guest-js/serial-port.ts | 5 ++-- src/api/backend.rs | 3 ++- src/exchange/io.rs | 10 +++++++ src/hub/shared.rs | 12 +++++---- src/tests/acl_smoke_test.rs | 11 -------- src/tests/command_inventory_test.rs | 9 ++++--- tests/api-error-matrix.test.ts | 6 ++--- tests/port-operations.test.ts | 13 +++++++-- tests/quick-at.test.ts | 22 +++++++++++++++ 11 files changed, 95 insertions(+), 37 deletions(-) create mode 100644 examples/serialport-test/src/quickAt.ts create mode 100644 tests/quick-at.test.ts diff --git a/examples/serialport-test/src/components/TerminalPanel.vue b/examples/serialport-test/src/components/TerminalPanel.vue index d10ad5bc..2fa7be33 100644 --- a/examples/serialport-test/src/components/TerminalPanel.vue +++ b/examples/serialport-test/src/components/TerminalPanel.vue @@ -1,5 +1,6 @@