commit dc9fd31c5e3c5e4066ae73140a1c85fce7396fc2 Author: Chengdong Zhang Date: Thu Sep 17 12:43:22 2026 +0800 feat: backend MVP (auth/rbac, catalog, orders, fulfillment, invoices) + specs + scaffolds diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe96a20 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +target/ +.nuxt/ +.output/ +.data/ +dist/ +*.log +.env +.env.local +.DS_Store diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4389f31 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3255 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "axum-macros", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[package]] +name = "encoding_rs" +version = "0.8.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5ef0006ac9ab233c38522f5ae99cae3625151de8f706cacee1cba4b8e2832a" +dependencies = [ + "cfg-if", + "core_detect", + "multiversion", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "h2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.5", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6480ccc157a1389bb2e4891b24751b0f798ba640d22386f23143fbcc89da195a" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.9.4", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "multiversion" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ca4bea16ffc3f443cf7d866912118196bfef4c6a1556ca00f9f9b00bb43f7c" +dependencies = [ + "multiversion-macros", +] + +[[package]] +name = "multiversion-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d416831a7317ef4b08bee00b69cbbb9c8763da7959a7026244d6266869f9c83" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 3.0.6", +] + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.8", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +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 = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[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_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "redis" +version = "0.27.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" +dependencies = [ + "arc-swap", + "async-trait", + "backon", + "bytes", + "combine", + "futures", + "futures-util", + "itertools", + "itoa", + "num-bigint", + "percent-encoding", + "pin-project-lite", + "ryu", + "sha1_smol", + "socket2 0.5.10", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_decimal" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7653272e75dcac41dc199fbea6f5797633994fafd339943c06c9af16bf29cd3a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.8", + "rand 0.9.5", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rust_decimal_macros" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74a5a6f027e892c7a035c6fddb50435a1fbf5a734ffc0c2a9fed4d0221440519" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[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.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rust_decimal", + "rustls", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", + "webpki-roots 0.26.11", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.8", + "rsa", + "rust_decimal", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.8", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.5", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[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.25.15+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[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", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vmall-api" +version = "0.1.0" +dependencies = [ + "anyhow", + "argon2", + "axum", + "chrono", + "jsonwebtoken", + "redis", + "reqwest", + "rust_decimal", + "rust_decimal_macros", + "serde", + "serde_json", + "serial_test", + "sqlx", + "thiserror", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "serde", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef4c5d3d2cdf5c54f4231181768f5510842e350db025faf1f7163b1030ed928" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbddc4a036f00ec4f18c83445bd3115cb306a91da554919a099d9222fe4a7f8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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 new file mode 100644 index 0000000..d223d8b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "2" +members = ["apps/api"] diff --git a/apps/admin/app.d.ts b/apps/admin/app.d.ts new file mode 100644 index 0000000..4e21577 --- /dev/null +++ b/apps/admin/app.d.ts @@ -0,0 +1,9 @@ +import type { ApiClient } from "@vmall/shared"; + +declare module "#app" { + interface NuxtApp { + $api: ApiClient; + } +} + +export {}; diff --git a/apps/admin/app.vue b/apps/admin/app.vue new file mode 100644 index 0000000..6d5c9fa --- /dev/null +++ b/apps/admin/app.vue @@ -0,0 +1,42 @@ + + + diff --git a/apps/admin/composables/usePrefs.ts b/apps/admin/composables/usePrefs.ts new file mode 100644 index 0000000..03412fa --- /dev/null +++ b/apps/admin/composables/usePrefs.ts @@ -0,0 +1,5 @@ +/** Shopper preferences: display currency, persisted in a cookie (SSR-safe). */ +export function usePrefs() { + const currency = useCookie("vmall.currency", { default: () => "USD" }); + return { currency }; +} diff --git a/apps/admin/i18n.config.ts b/apps/admin/i18n.config.ts new file mode 100644 index 0000000..bcfb01f --- /dev/null +++ b/apps/admin/i18n.config.ts @@ -0,0 +1,8 @@ +import { en, zh } from "@vmall/shared/locales"; + +export default defineI18nConfig(() => ({ + legacy: false, + locale: "en", + fallbackLocale: "en", + messages: { en, zh }, +})); diff --git a/apps/admin/nuxt.config.ts b/apps/admin/nuxt.config.ts new file mode 100644 index 0000000..e4657d1 --- /dev/null +++ b/apps/admin/nuxt.config.ts @@ -0,0 +1,22 @@ +export default defineNuxtConfig({ + modules: ["@pinia/nuxt", "@nuxtjs/i18n"], + css: ["@vmall/shared/ui.css"], + devtools: { enabled: false }, + devServer: { port: 3002 }, + runtimeConfig: { + public: { + apiBase: "http://localhost:8080/api", + appName: "admin", + }, + }, + i18n: { + strategy: "no_prefix", + defaultLocale: "en", + locales: [ + { code: "en", name: "English" }, + { code: "zh", name: "中文" }, + ], + vueI18n: "./i18n.config.ts", + }, + compatibilityDate: "2025-01-01", +}); diff --git a/apps/admin/package.json b/apps/admin/package.json new file mode 100644 index 0000000..e096357 --- /dev/null +++ b/apps/admin/package.json @@ -0,0 +1,19 @@ +{ + "name": "@vmall/admin", + "private": true, + "type": "module", + "scripts": { + "dev": "nuxt dev", + "build": "nuxt build", + "preview": "nuxt preview" + }, + "dependencies": { + "@nuxtjs/i18n": "^9.5.3", + "@pinia/nuxt": "^0.10.1", + "@vmall/shared": "workspace:*", + "nuxt": "^3.15.4", + "pinia": "^2.3.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + } +} diff --git a/apps/admin/pages/index.vue b/apps/admin/pages/index.vue new file mode 100644 index 0000000..d286cfd --- /dev/null +++ b/apps/admin/pages/index.vue @@ -0,0 +1,6 @@ + diff --git a/apps/admin/plugins/api.ts b/apps/admin/plugins/api.ts new file mode 100644 index 0000000..1678a49 --- /dev/null +++ b/apps/admin/plugins/api.ts @@ -0,0 +1,10 @@ +import { createApi } from "@vmall/shared"; + +export default defineNuxtPlugin(() => { + const config = useRuntimeConfig(); + const api = createApi({ + baseUrl: config.public.apiBase as string, + getToken: () => (import.meta.client ? localStorage.getItem("vmall.token") : null), + }); + return { provide: { api } }; +}); diff --git a/apps/admin/stores/session.ts b/apps/admin/stores/session.ts new file mode 100644 index 0000000..286bda2 --- /dev/null +++ b/apps/admin/stores/session.ts @@ -0,0 +1,64 @@ +import { defineStore } from "pinia"; +import type { AuthTokens, User } from "@vmall/shared"; + +const USER_KEY = "vmall.user"; +const TOKEN_KEY = "vmall.token"; + +function isUser(v: unknown): v is User { + if (!v || typeof v !== "object") return false; + const o = v as Record; + return ( + typeof o.id === "string" && + typeof o.email === "string" && + typeof o.display_name === "string" && + typeof o.role === "string" + ); +} + +export function readStoredUser(): User | null { + if (!import.meta.client) return null; + try { + const raw = localStorage.getItem(USER_KEY); + if (!raw) return null; + const parsed: unknown = JSON.parse(raw); + return isUser(parsed) ? parsed : null; + } catch { + return null; + } +} + +interface SessionState { + user: User | null; + token: string | null; +} + +export const useSessionStore = defineStore("session", { + state: (): SessionState => ({ user: null, token: null }), + getters: { + isLoggedIn: (s): boolean => s.token !== null, + }, + actions: { + hydrate(): void { + if (!import.meta.client) return; + this.token = localStorage.getItem(TOKEN_KEY); + this.user = readStoredUser(); + }, + setAuth(auth: AuthTokens): void { + this.token = auth.token; + this.user = auth.user; + if (import.meta.client) { + localStorage.setItem(TOKEN_KEY, auth.token); + localStorage.setItem(USER_KEY, JSON.stringify(auth.user)); + } + }, + logout(): void { + this.token = null; + this.user = null; + if (import.meta.client) { + localStorage.removeItem(TOKEN_KEY); + localStorage.removeItem(USER_KEY); + } + navigateTo("/login"); + }, + }, +}); diff --git a/apps/api/Cargo.toml b/apps/api/Cargo.toml new file mode 100644 index 0000000..bc944a8 --- /dev/null +++ b/apps/api/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "vmall-api" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = { version = "0.8", features = ["macros"] } +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sqlx = { version = "0.8", default-features = false, features = [ + "runtime-tokio-rustls", + "postgres", + "uuid", + "chrono", + "rust_decimal", + "macros", + "migrate", + "json", +] } +redis = { version = "0.27", features = ["tokio-comp", "connection-manager"] } +uuid = { version = "1", features = ["v4", "serde"] } +chrono = { version = "0.4", features = ["serde"] } +rust_decimal = { version = "1", features = ["serde-with-str"] } +rust_decimal_macros = "1" +jsonwebtoken = "9" +argon2 = "0.5" +tower-http = { version = "0.6", features = ["cors", "trace"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +anyhow = "1" +thiserror = "2" + +[dev-dependencies] +reqwest = { version = "0.12", features = ["json"] } +serial_test = "3" diff --git a/apps/api/migrations/0001_init.sql b/apps/api/migrations/0001_init.sql new file mode 100644 index 0000000..7ca3626 --- /dev/null +++ b/apps/api/migrations/0001_init.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; diff --git a/apps/api/migrations/0002_identity.sql b/apps/api/migrations/0002_identity.sql new file mode 100644 index 0000000..9ac266d --- /dev/null +++ b/apps/api/migrations/0002_identity.sql @@ -0,0 +1,28 @@ +CREATE TYPE user_role AS ENUM ('platform_admin', 'shop_owner', 'shop_staff', 'customer'); + +CREATE TYPE shop_status AS ENUM ('active', 'suspended'); + +CREATE TABLE shops ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name JSONB NOT NULL, + slug TEXT NOT NULL UNIQUE, + status shop_status NOT NULL DEFAULT 'active', + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + email TEXT NOT NULL UNIQUE, + password_hash TEXT NOT NULL, + display_name TEXT NOT NULL, + role user_role NOT NULL DEFAULT 'customer', + shop_id UUID REFERENCES shops (id), + locale TEXT NOT NULL DEFAULT 'en', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + CONSTRAINT shop_role_requires_shop CHECK ( + role IN ('customer', 'platform_admin') + OR shop_id IS NOT NULL + ) +); + +CREATE INDEX idx_users_shop ON users (shop_id); diff --git a/apps/api/migrations/0003_catalog.sql b/apps/api/migrations/0003_catalog.sql new file mode 100644 index 0000000..f80bca6 --- /dev/null +++ b/apps/api/migrations/0003_catalog.sql @@ -0,0 +1,65 @@ +CREATE TYPE product_status AS ENUM ('draft', 'published', 'unpublished'); + +-- rate_to_base: units of this currency per 1 unit of the base currency +-- (USD base: CNY 7.2 means 1 USD = 7.2 CNY). +CREATE TABLE currencies ( + code CHAR(3) PRIMARY KEY, + name JSONB NOT NULL, + symbol TEXT NOT NULL, + exponent SMALLINT NOT NULL, + is_base BOOLEAN NOT NULL DEFAULT FALSE, + rate_to_base NUMERIC(20, 8) NOT NULL CHECK (rate_to_base > 0), + enabled BOOLEAN NOT NULL DEFAULT TRUE +); + +INSERT INTO currencies (code, name, symbol, exponent, is_base, rate_to_base) +VALUES + ('USD', '{"en": "US Dollar", "zh": "美元"}', '$', 2, TRUE, 1), + ('CNY', '{"en": "Chinese Yuan", "zh": "人民币"}', '¥', 2, FALSE, 7.2), + ('EUR', '{"en": "Euro", "zh": "欧元"}', '€', 2, FALSE, 0.92), + ('JPY', '{"en": "Japanese Yen", "zh": "日元"}', '¥', 0, FALSE, 150); + +CREATE TABLE categories ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + parent_id UUID REFERENCES categories (id), + name JSONB NOT NULL, + slug TEXT NOT NULL UNIQUE, + position INT NOT NULL DEFAULT 0 +); + +INSERT INTO categories (name, slug, position) +VALUES + ('{"en": "Electronics", "zh": "电子产品"}', 'electronics', 1), + ('{"en": "Fashion", "zh": "时尚服饰"}', 'fashion', 2), + ('{"en": "Home & Living", "zh": "家居生活"}', 'home-living', 3); + +CREATE TABLE products ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + shop_id UUID NOT NULL REFERENCES shops (id), + category_id UUID REFERENCES categories (id), + slug TEXT NOT NULL, + name JSONB NOT NULL, + description JSONB NOT NULL DEFAULT '{}', + images JSONB NOT NULL DEFAULT '[]', + status product_status NOT NULL DEFAULT 'draft', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + UNIQUE (shop_id, slug) +); + +CREATE INDEX idx_products_status ON products (status); +CREATE INDEX idx_products_category ON products (category_id); + +CREATE TABLE skus ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + product_id UUID NOT NULL REFERENCES products (id) ON DELETE CASCADE, + sku_code TEXT NOT NULL, + attributes JSONB NOT NULL DEFAULT '{}', + price_minor BIGINT NOT NULL CHECK (price_minor >= 0), + currency CHAR(3) NOT NULL REFERENCES currencies (code), + stock INT NOT NULL DEFAULT 0 CHECK (stock >= 0), + active BOOLEAN NOT NULL DEFAULT TRUE, + UNIQUE (product_id, sku_code) +); + +CREATE INDEX idx_skus_product ON skus (product_id); diff --git a/apps/api/migrations/0004_orders.sql b/apps/api/migrations/0004_orders.sql new file mode 100644 index 0000000..0379ccb --- /dev/null +++ b/apps/api/migrations/0004_orders.sql @@ -0,0 +1,89 @@ +CREATE TYPE order_status AS ENUM ( + 'pending_payment', + 'paid', + 'fulfilling', + 'shipped', + 'completed', + 'cancelled' +); + +CREATE TYPE shipment_status AS ENUM ('pending', 'shipped', 'delivered'); + +CREATE TYPE invoice_status AS ENUM ('requested', 'issued', 'cancelled'); + +CREATE TYPE invoice_kind AS ENUM ('personal', 'company'); + +CREATE SEQUENCE order_no_seq; +CREATE SEQUENCE shipment_no_seq; +CREATE SEQUENCE invoice_no_seq; + +CREATE TABLE orders ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + order_no TEXT NOT NULL UNIQUE, + shop_id UUID NOT NULL REFERENCES shops (id), + user_id UUID NOT NULL REFERENCES users (id), + status order_status NOT NULL DEFAULT 'pending_payment', + currency CHAR(3) NOT NULL REFERENCES currencies (code), + total_minor BIGINT NOT NULL CHECK (total_minor >= 0), + shipping_address JSONB NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX idx_orders_user ON orders (user_id); +CREATE INDEX idx_orders_shop ON orders (shop_id); + +CREATE TABLE order_items ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + order_id UUID NOT NULL REFERENCES orders (id) ON DELETE CASCADE, + sku_id UUID NOT NULL REFERENCES skus (id), + product_name JSONB NOT NULL, + sku_code TEXT NOT NULL, + image TEXT, + unit_price_minor BIGINT NOT NULL CHECK (unit_price_minor >= 0), + qty INT NOT NULL CHECK (qty > 0) +); + +CREATE INDEX idx_order_items_order ON order_items (order_id); + +CREATE TABLE shipments ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + shipment_no TEXT NOT NULL UNIQUE, + order_id UUID NOT NULL REFERENCES orders (id), + carrier TEXT NOT NULL, + tracking_no TEXT NOT NULL, + status shipment_status NOT NULL DEFAULT 'pending', + shipped_at TIMESTAMPTZ, + delivered_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE INDEX idx_shipments_order ON shipments (order_id); + +CREATE TABLE shipment_items ( + shipment_id UUID NOT NULL REFERENCES shipments (id) ON DELETE CASCADE, + order_item_id UUID NOT NULL REFERENCES order_items (id), + qty INT NOT NULL CHECK (qty > 0), + PRIMARY KEY (shipment_id, order_item_id) +); + +CREATE TABLE invoices ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + invoice_no TEXT UNIQUE, + order_id UUID NOT NULL REFERENCES orders (id), + user_id UUID NOT NULL REFERENCES users (id), + title TEXT NOT NULL, + tax_no TEXT, + kind invoice_kind NOT NULL, + amount_minor BIGINT NOT NULL CHECK (amount_minor >= 0), + currency CHAR(3) NOT NULL, + status invoice_status NOT NULL DEFAULT 'requested', + issued_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- at most one open (requested/issued) invoice per order +CREATE UNIQUE INDEX one_open_invoice_per_order ON invoices (order_id) +WHERE status IN ('requested', 'issued'); + +CREATE INDEX idx_invoices_user ON invoices (user_id); diff --git a/apps/api/src/auth.rs b/apps/api/src/auth.rs new file mode 100644 index 0000000..aa0c6f4 --- /dev/null +++ b/apps/api/src/auth.rs @@ -0,0 +1,118 @@ +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; +use axum::{ + extract::FromRequestParts, + http::{header::AUTHORIZATION, request::Parts}, +}; +use chrono::{Duration, Utc}; +use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::error::ApiError; +use crate::models::UserRole; +use crate::state::AppState; + +pub fn hash_password(password: &str) -> Result { + let salt = SaltString::generate(&mut OsRng); + Argon2::default() + .hash_password(password.as_bytes(), &salt) + .map(|h| h.to_string()) + .map_err(|e| ApiError::BadRequest(format!("password hashing failed: {e}"))) +} + +pub fn verify_password(password: &str, hash: &str) -> bool { + PasswordHash::new(hash) + .map(|h| Argon2::default().verify_password(password.as_bytes(), &h).is_ok()) + .unwrap_or(false) +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub sub: Uuid, + pub role: UserRole, + pub shop_id: Option, + pub exp: i64, +} + +pub fn issue_token( + secret: &str, + ttl_secs: i64, + user_id: Uuid, + role: UserRole, + shop_id: Option, +) -> Result { + let claims = Claims { + sub: user_id, + role, + shop_id, + exp: (Utc::now() + Duration::seconds(ttl_secs)).timestamp(), + }; + encode( + &Header::default(), + &claims, + &EncodingKey::from_secret(secret.as_bytes()), + ) + .map_err(ApiError::internal) +} + +/// Authenticated principal extracted from the Bearer token. +#[derive(Debug, Clone)] +pub struct AuthUser { + pub id: Uuid, + pub role: UserRole, + pub shop_id: Option, +} + +impl AuthUser { + /// 403 unless the principal holds one of `roles`. Shop roles are further + /// scoped to their own shop via [`AuthUser::own_shop`]. + pub fn require(&self, roles: &[UserRole]) -> Result<(), ApiError> { + if roles.contains(&self.role) { + Ok(()) + } else { + Err(ApiError::Forbidden("insufficient role".into())) + } + } + + /// The shop this principal may operate on; 403 for non-shop roles. + pub fn own_shop(&self) -> Result { + if self.role.is_shop_role() { + self.shop_id + .ok_or_else(|| ApiError::Forbidden("account has no shop".into())) + } else { + Err(ApiError::Forbidden("shop role required".into())) + } + } +} + +impl FromRequestParts for AuthUser { + type Rejection = ApiError; + + async fn from_request_parts( + parts: &mut Parts, + state: &AppState, + ) -> Result { + let header = parts + .headers + .get(AUTHORIZATION) + .and_then(|v| v.to_str().ok()) + .ok_or_else(|| ApiError::Unauthorized("missing bearer token".into()))?; + let token = header + .strip_prefix("Bearer ") + .ok_or_else(|| ApiError::Unauthorized("malformed authorization header".into()))?; + let data = decode::( + token, + &DecodingKey::from_secret(state.config.jwt_secret.as_bytes()), + &Validation::default(), + ) + .map_err(|_| ApiError::Unauthorized("invalid or expired token".into()))?; + Ok(AuthUser { + id: data.claims.sub, + role: data.claims.role, + shop_id: data.claims.shop_id, + }) + } +} diff --git a/apps/api/src/cart.rs b/apps/api/src/cart.rs new file mode 100644 index 0000000..7e9c89a --- /dev/null +++ b/apps/api/src/cart.rs @@ -0,0 +1,110 @@ +use redis::AsyncCommands; +use serde::Serialize; +use uuid::Uuid; + +use crate::error::{ApiError, ApiResult}; +use crate::state::AppState; + +fn key(user_id: Uuid) -> String { + format!("vmall:cart:{user_id}") +} + +/// Raw cart: sku_id -> qty (positive only). +pub async fn read_cart(state: &AppState, user_id: Uuid) -> ApiResult> { + let mut conn = state.redis.clone(); + let raw: Vec<(String, i32)> = conn.hgetall(key(user_id)).await.map_err(ApiError::from)?; + Ok(raw + .into_iter() + .filter_map(|(k, qty)| Uuid::parse_str(&k).ok().map(|id| (id, qty))) + .filter(|(_, qty)| *qty > 0) + .collect()) +} + +pub async fn set_qty(state: &AppState, user_id: Uuid, sku_id: Uuid, qty: i32) -> ApiResult<()> { + let mut conn = state.redis.clone(); + if qty <= 0 { + conn.hdel::<_, _, ()>(key(user_id), sku_id.to_string()) + .await + .map_err(ApiError::from)?; + } else { + conn.hset::<_, _, _, ()>(key(user_id), sku_id.to_string(), qty) + .await + .map_err(ApiError::from)?; + } + Ok(()) +} + +pub async fn clear_cart(state: &AppState, user_id: Uuid) -> ApiResult<()> { + let mut conn = state.redis.clone(); + conn.del::<_, ()>(key(user_id)).await.map_err(ApiError::from)?; + Ok(()) +} + +#[derive(Debug, Serialize)] +pub struct CartItemView { + pub sku_id: Uuid, + pub product_id: Uuid, + pub product_name: serde_json::Value, + pub sku_code: String, + pub image: Option, + pub unit_price_minor: i64, + pub currency: String, + pub qty: i32, +} + +#[derive(Debug, Serialize)] +pub struct CartView { + pub items: Vec, +} + +/// Cart read model: joins Redis entries with purchasable SKU snapshots. +/// Entries whose SKU vanished or became unpurchasable are dropped from the view. +pub async fn cart_view(state: &AppState, user_id: Uuid) -> ApiResult { + let entries = read_cart(state, user_id).await?; + if entries.is_empty() { + return Ok(CartView { items: vec![] }); + } + let sku_ids: Vec = entries.iter().map(|(id, _)| *id).collect(); + let rows = sqlx::query_as::<_, CartRow>( + "SELECT s.id AS sku_id, p.id AS product_id, p.name AS product_name, s.sku_code, + (p.images ->> 0) AS image, s.price_minor, s.currency + FROM skus s + JOIN products p ON p.id = s.product_id + JOIN shops sh ON sh.id = p.shop_id + WHERE s.id = ANY($1) AND s.active = TRUE + AND p.status = 'published' AND sh.status = 'active'", + ) + .bind(&sku_ids) + .fetch_all(&state.db) + .await?; + let items = rows + .into_iter() + .filter_map(|r| { + entries + .iter() + .find(|(id, _)| *id == r.sku_id) + .map(|(_, qty)| CartItemView { + sku_id: r.sku_id, + product_id: r.product_id, + product_name: r.product_name, + sku_code: r.sku_code, + image: r.image, + unit_price_minor: r.price_minor, + currency: r.currency, + qty: *qty, + }) + }) + .collect(); + Ok(CartView { items }) +} + +#[derive(sqlx::FromRow)] +struct CartRow { + sku_id: Uuid, + product_id: Uuid, + product_name: serde_json::Value, + sku_code: String, + image: Option, + price_minor: i64, + currency: String, +} diff --git a/apps/api/src/config.rs b/apps/api/src/config.rs new file mode 100644 index 0000000..30b2087 --- /dev/null +++ b/apps/api/src/config.rs @@ -0,0 +1,45 @@ +use anyhow::Context; + +#[derive(Clone, Debug)] +pub struct Config { + pub database_url: String, + pub redis_url: String, + pub jwt_secret: String, + pub port: u16, + /// token TTL in seconds + pub jwt_ttl_secs: i64, +} + +impl Config { + pub fn from_env() -> anyhow::Result { + let database_url = std::env::var("DATABASE_URL") + .unwrap_or_else(|_| "postgres://postgres:postgres@127.0.0.1:5432/vmall".into()); + let redis_url = + std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://127.0.0.1:6379/".into()); + let jwt_secret = std::env::var("JWT_SECRET") + .unwrap_or_else(|_| "vmall-dev-secret-change-me".to_string()); + let port: u16 = std::env::var("PORT") + .ok() + .and_then(|p| p.parse().ok()) + .unwrap_or(8080); + let jwt_ttl_secs: i64 = std::env::var("JWT_TTL_SECS") + .ok() + .and_then(|p| p.parse().ok()) + .unwrap_or(86_400); + let cfg = Self { + database_url, + redis_url, + jwt_secret, + port, + jwt_ttl_secs, + }; + tracing::info!(port = cfg.port, "config loaded"); + Ok(cfg) + } +} + +pub fn database_url_for(db: &str) -> anyhow::Result { + let base = + std::env::var("DATABASE_URL").context("DATABASE_URL must be set for tests")?; + Ok(format!("{base}/{db}")) +} diff --git a/apps/api/src/error.rs b/apps/api/src/error.rs new file mode 100644 index 0000000..53170f7 --- /dev/null +++ b/apps/api/src/error.rs @@ -0,0 +1,59 @@ +use axum::{http::StatusCode, response::{IntoResponse, Response}, Json}; +use serde_json::json; + +#[derive(Debug, thiserror::Error)] +pub enum ApiError { + #[error("not found: {0}")] + NotFound(String), + #[error("bad request: {0}")] + BadRequest(String), + #[error("unauthorized: {0}")] + Unauthorized(String), + #[error("forbidden: {0}")] + Forbidden(String), + #[error("conflict: {0}")] + Conflict(String), + #[error("internal error")] + Internal(#[from] anyhow::Error), +} + +impl ApiError { + pub fn internal(e: E) -> Self { + ApiError::Internal(anyhow::Error::new(e)) + } +} + +impl IntoResponse for ApiError { + fn into_response(self) -> Response { + let (status, code, message) = match &self { + ApiError::NotFound(m) => (StatusCode::NOT_FOUND, "NOT_FOUND", m.clone()), + ApiError::BadRequest(m) => (StatusCode::BAD_REQUEST, "BAD_REQUEST", m.clone()), + ApiError::Unauthorized(m) => (StatusCode::UNAUTHORIZED, "UNAUTHORIZED", m.clone()), + ApiError::Forbidden(m) => (StatusCode::FORBIDDEN, "FORBIDDEN", m.clone()), + ApiError::Conflict(m) => (StatusCode::CONFLICT, "CONFLICT", m.clone()), + ApiError::Internal(e) => { + tracing::error!(error = %e, "internal error"); + ( + StatusCode::INTERNAL_SERVER_ERROR, + "INTERNAL", + "internal server error".to_string(), + ) + } + }; + (status, Json(json!({ "error": { "code": code, "message": message } }))).into_response() + } +} + +impl From for ApiError { + fn from(e: sqlx::Error) -> Self { + ApiError::Internal(anyhow::Error::new(e)) + } +} + +impl From for ApiError { + fn from(e: redis::RedisError) -> Self { + ApiError::Internal(anyhow::Error::new(e)) + } +} + +pub type ApiResult = Result; diff --git a/apps/api/src/lib.rs b/apps/api/src/lib.rs new file mode 100644 index 0000000..e674228 --- /dev/null +++ b/apps/api/src/lib.rs @@ -0,0 +1,24 @@ +pub mod auth; +pub mod cart; +pub mod config; +pub mod error; +pub mod models; +pub mod money; +pub mod pagination; +pub mod routes; +pub mod seed; +pub mod state; + +use axum::{routing::get, Router}; +use tower_http::{cors::CorsLayer, trace::TraceLayer}; + +use crate::state::AppState; + +pub fn build_router(state: AppState) -> Router { + Router::new() + .route("/api/health", get(routes::health::health)) + .nest("/api", routes::api_router(state.clone())) + .layer(TraceLayer::new_for_http()) + .layer(CorsLayer::permissive()) + .with_state(state) +} diff --git a/apps/api/src/main.rs b/apps/api/src/main.rs new file mode 100644 index 0000000..294920a --- /dev/null +++ b/apps/api/src/main.rs @@ -0,0 +1,24 @@ +use vmall_api::{build_router, config::Config, seed::ensure_platform_admin, state::build_state}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| "vmall_api=info,tower_http=info".into()), + ) + .init(); + + let config = Config::from_env()?; + sqlx::migrate!("./migrations") + .run(&sqlx::PgPool::connect(&config.database_url).await?) + .await?; + let state = build_state(&config).await?; + ensure_platform_admin(&state).await?; + let app = build_router(state); + + let listener = tokio::net::TcpListener::bind(("0.0.0.0", config.port)).await?; + tracing::info!(port = config.port, "vmall-api listening"); + axum::serve(listener, app).await?; + Ok(()) +} diff --git a/apps/api/src/models.rs b/apps/api/src/models.rs new file mode 100644 index 0000000..7aa90ea --- /dev/null +++ b/apps/api/src/models.rs @@ -0,0 +1,205 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; +use sqlx::Type; +use uuid::Uuid; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "user_role", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum UserRole { + PlatformAdmin, + ShopOwner, + ShopStaff, + Customer, +} + +impl UserRole { + pub fn is_shop_role(self) -> bool { + matches!(self, UserRole::ShopOwner | UserRole::ShopStaff) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "shop_status", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum ShopStatus { + Active, + Suspended, +} + +#[derive(Debug, Serialize, sqlx::FromRow)] +pub struct User { + pub id: Uuid, + pub email: String, + #[serde(skip_serializing)] + pub password_hash: String, + pub display_name: String, + pub role: UserRole, + pub shop_id: Option, + pub locale: String, + pub created_at: DateTime, +} + +#[derive(Debug, Serialize, sqlx::FromRow)] +pub struct Shop { + pub id: Uuid, + pub name: serde_json::Value, + pub slug: String, + pub status: ShopStatus, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "product_status", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum ProductStatus { + Draft, + Published, + Unpublished, +} + +#[derive(Debug, Serialize, sqlx::FromRow)] +pub struct Category { + pub id: Uuid, + pub parent_id: Option, + pub name: serde_json::Value, + pub slug: String, + pub position: i32, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct Product { + pub id: Uuid, + pub shop_id: Uuid, + pub category_id: Option, + pub slug: String, + pub name: serde_json::Value, + pub description: serde_json::Value, + pub images: serde_json::Value, + pub status: ProductStatus, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct Sku { + pub id: Uuid, + pub product_id: Uuid, + pub sku_code: String, + pub attributes: serde_json::Value, + pub price_minor: i64, + pub currency: String, + pub stock: i32, + pub active: bool, +} + +#[derive(Debug, Serialize, sqlx::FromRow)] +pub struct Currency { + pub code: String, + pub name: serde_json::Value, + pub symbol: String, + pub exponent: i16, + pub is_base: bool, + pub rate_to_base: rust_decimal::Decimal, + pub enabled: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "order_status", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum OrderStatus { + PendingPayment, + Paid, + Fulfilling, + Shipped, + Completed, + Cancelled, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "shipment_status", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum ShipmentStatus { + Pending, + Shipped, + Delivered, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "invoice_status", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum InvoiceStatus { + Requested, + Issued, + Cancelled, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)] +#[sqlx(type_name = "invoice_kind", rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum InvoiceKind { + Personal, + Company, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct Order { + pub id: Uuid, + pub order_no: String, + pub shop_id: Uuid, + pub user_id: Uuid, + pub status: OrderStatus, + pub currency: String, + pub total_minor: i64, + pub shipping_address: serde_json::Value, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct OrderItem { + pub id: Uuid, + pub order_id: Uuid, + pub sku_id: Uuid, + pub product_name: serde_json::Value, + pub sku_code: String, + pub image: Option, + pub unit_price_minor: i64, + pub qty: i32, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct Shipment { + pub id: Uuid, + pub shipment_no: String, + pub order_id: Uuid, + pub carrier: String, + pub tracking_no: String, + pub status: ShipmentStatus, + pub shipped_at: Option>, + pub delivered_at: Option>, + pub created_at: DateTime, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct ShipmentItem { + pub shipment_id: Uuid, + pub order_item_id: Uuid, + pub qty: i32, +} + +#[derive(Debug, Clone, Serialize, sqlx::FromRow)] +pub struct Invoice { + pub id: Uuid, + pub invoice_no: Option, + pub order_id: Uuid, + pub user_id: Uuid, + pub title: String, + pub tax_no: Option, + pub kind: InvoiceKind, + pub amount_minor: i64, + pub currency: String, + pub status: InvoiceStatus, + pub issued_at: Option>, + pub created_at: DateTime, +} diff --git a/apps/api/src/money.rs b/apps/api/src/money.rs new file mode 100644 index 0000000..8e3c5e9 --- /dev/null +++ b/apps/api/src/money.rs @@ -0,0 +1,23 @@ +use rust_decimal::prelude::*; +use rust_decimal::Decimal; + +use crate::error::ApiError; +use crate::models::Currency; + +/// Convert integer minor units between currencies via base rates. +/// rate_to_base = units of currency per 1 unit of base. Rounds half-up +/// to whole minor units of the target currency. +pub fn convert_minor(amount_minor: i64, from: &Currency, to: &Currency) -> Result { + if amount_minor < 0 { + return Err(ApiError::BadRequest("amount_minor must be >= 0".into())); + } + let amount = Decimal::from(amount_minor); + let from_scale = Decimal::from(10i64.pow(from.exponent as u32)); + let to_scale = Decimal::from(10i64.pow(to.exponent as u32)); + // minor(from) -> major(from) -> major(base) -> minor(to) + let base_major = amount / from_scale / from.rate_to_base; + let target = (base_major * to.rate_to_base * to_scale).round_dp(0); + target + .to_i64() + .ok_or_else(|| ApiError::BadRequest("amount out of range".into())) +} diff --git a/apps/api/src/pagination.rs b/apps/api/src/pagination.rs new file mode 100644 index 0000000..0818741 --- /dev/null +++ b/apps/api/src/pagination.rs @@ -0,0 +1,17 @@ +use serde::Serialize; + +#[derive(Debug, Serialize)] +pub struct Paged { + pub items: Vec, + pub total: i64, + pub page: i64, + pub per_page: i64, +} + +pub fn clamp_page(page: Option) -> i64 { + page.unwrap_or(1).max(1) +} + +pub fn clamp_per_page(per_page: Option) -> i64 { + per_page.unwrap_or(20).clamp(1, 100) +} diff --git a/apps/api/src/routes/admin.rs b/apps/api/src/routes/admin.rs new file mode 100644 index 0000000..a806cc4 --- /dev/null +++ b/apps/api/src/routes/admin.rs @@ -0,0 +1,290 @@ +use axum::{ + extract::{Path, Query, State}, + http::StatusCode, + routing::{get, put}, + Json, Router, +}; +use serde::Deserialize; +use serde_json::Value; +use uuid::Uuid; + +use crate::auth::AuthUser; +use crate::error::{ApiError, ApiResult}; +use crate::models::{Currency, Order, Shop, ShopStatus, User, UserRole}; +use crate::routes::order_common::{attach_items, OrderView}; +use crate::pagination::{clamp_page, clamp_per_page, Paged}; +use crate::routes::currency::load_currencies; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/admin/users", get(list_users)) + .route("/admin/users/{id}/role", put(set_user_role)) + .route("/admin/shops", get(list_shops).post(create_shop)) + .route("/admin/shops/{id}/status", put(set_shop_status)) + .route( + "/admin/currencies", + get(list_all_currencies).post(upsert_currency), + ) + .route("/admin/currencies/{code}/rate", put(set_rate)) + .route("/admin/orders", get(list_orders)) +} + +fn require_admin(auth: &AuthUser) -> ApiResult<()> { + auth.require(&[UserRole::PlatformAdmin]) +} + +#[derive(Deserialize)] +struct PageQuery { + page: Option, + per_page: Option, +} + +async fn list_users( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> ApiResult>> { + require_admin(&auth)?; + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let total: i64 = sqlx::query_scalar("SELECT count(*) FROM users") + .fetch_one(&state.db) + .await?; + let items = sqlx::query_as::<_, User>( + "SELECT * FROM users ORDER BY created_at DESC LIMIT $1 OFFSET $2", + ) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} + +#[derive(Deserialize)] +struct SetRoleBody { + role: UserRole, + shop_id: Option, +} + +async fn set_user_role( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult> { + require_admin(&auth)?; + if body.role.is_shop_role() { + let shop_id = body + .shop_id + .ok_or_else(|| ApiError::BadRequest("shop_id required for shop roles".into()))?; + let shop_exists: bool = + sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM shops WHERE id = $1)") + .bind(shop_id) + .fetch_one(&state.db) + .await?; + if !shop_exists { + return Err(ApiError::BadRequest("shop not found".into())); + } + } else if body.shop_id.is_some() { + return Err(ApiError::BadRequest( + "shop_id only allowed for shop roles".into(), + )); + } + let user = sqlx::query_as::<_, User>( + "UPDATE users SET role = $2, shop_id = $3 WHERE id = $1 RETURNING *", + ) + .bind(id) + .bind(body.role) + .bind(body.shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("user".into()))?; + Ok(Json(user)) +} + +async fn list_shops(State(state): State, auth: AuthUser) -> ApiResult>> { + require_admin(&auth)?; + let shops = sqlx::query_as::<_, Shop>("SELECT * FROM shops ORDER BY created_at") + .fetch_all(&state.db) + .await?; + Ok(Json(shops)) +} + +#[derive(Deserialize)] +struct CreateShopBody { + name: Value, + slug: String, +} + +async fn create_shop( + State(state): State, + auth: AuthUser, + Json(body): Json, +) -> ApiResult<(StatusCode, Json)> { + require_admin(&auth)?; + let name_en = body.name.get("en").and_then(|v| v.as_str()).unwrap_or(""); + if name_en.trim().is_empty() { + return Err(ApiError::BadRequest("name.en is required".into())); + } + if body.slug.trim().is_empty() + || !body.slug.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') + { + return Err(ApiError::BadRequest("invalid slug".into())); + } + let shop = sqlx::query_as::<_, Shop>( + "INSERT INTO shops (name, slug) VALUES ($1, $2) RETURNING *", + ) + .bind(&body.name) + .bind(body.slug.trim()) + .fetch_one(&state.db) + .await + .map_err(|e| match e { + sqlx::Error::Database(d) if d.is_unique_violation() => { + ApiError::Conflict("slug already exists".into()) + } + other => ApiError::from(other), + })?; + Ok((StatusCode::CREATED, Json(shop))) +} + +#[derive(Deserialize)] +struct SetStatusBody { + status: ShopStatus, +} + +async fn set_shop_status( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult> { + require_admin(&auth)?; + let shop = sqlx::query_as::<_, Shop>( + "UPDATE shops SET status = $2 WHERE id = $1 RETURNING *", + ) + .bind(id) + .bind(body.status) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("shop".into()))?; + Ok(Json(shop)) +} + +async fn list_all_currencies( + State(state): State, + auth: AuthUser, +) -> ApiResult>> { + require_admin(&auth)?; + Ok(Json(load_currencies(&state, false).await?)) +} + +#[derive(Deserialize)] +struct CurrencyBody { + code: String, + name: Value, + symbol: String, + exponent: i16, + rate_to_base: String, + enabled: bool, +} + +async fn upsert_currency( + State(state): State, + auth: AuthUser, + Json(body): Json, +) -> ApiResult> { + require_admin(&auth)?; + let code = body.code.to_uppercase(); + if code.len() != 3 || !code.chars().all(|c| c.is_ascii_uppercase()) { + return Err(ApiError::BadRequest("code must be a 3-letter ISO code".into())); + } + let rate: rust_decimal::Decimal = body + .rate_to_base + .parse() + .map_err(|_| ApiError::BadRequest("rate_to_base must be numeric".into()))?; + if rate <= rust_decimal::Decimal::ZERO { + return Err(ApiError::BadRequest("rate_to_base must be > 0".into())); + } + if !(0..=6).contains(&body.exponent) { + return Err(ApiError::BadRequest("exponent must be 0..=6".into())); + } + let currency = sqlx::query_as::<_, Currency>( + "INSERT INTO currencies (code, name, symbol, exponent, rate_to_base, enabled) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (code) DO UPDATE + SET name = $2, symbol = $3, exponent = $4, rate_to_base = $5, enabled = $6 + RETURNING *", + ) + .bind(&code) + .bind(&body.name) + .bind(&body.symbol) + .bind(body.exponent) + .bind(rate) + .bind(body.enabled) + .fetch_one(&state.db) + .await?; + Ok(Json(currency)) +} + +#[derive(Deserialize)] +struct SetRateBody { + rate_to_base: String, +} + +async fn set_rate( + State(state): State, + auth: AuthUser, + Path(code): Path, + Json(body): Json, +) -> ApiResult> { + require_admin(&auth)?; + let rate: rust_decimal::Decimal = body + .rate_to_base + .parse() + .map_err(|_| ApiError::BadRequest("rate_to_base must be numeric".into()))?; + if rate <= rust_decimal::Decimal::ZERO { + return Err(ApiError::BadRequest("rate_to_base must be > 0".into())); + } + let currency = sqlx::query_as::<_, Currency>( + "UPDATE currencies SET rate_to_base = $2 WHERE code = $1 RETURNING *", + ) + .bind(code.to_uppercase()) + .bind(rate) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("currency".into()))?; + Ok(Json(currency)) +} + +async fn list_orders( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> ApiResult>> { + require_admin(&auth)?; + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let total: i64 = sqlx::query_scalar("SELECT count(*) FROM orders") + .fetch_one(&state.db) + .await?; + let orders = sqlx::query_as::<_, Order>( + "SELECT * FROM orders ORDER BY created_at DESC LIMIT $1 OFFSET $2", + ) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + let items = attach_items(&state.db, orders).await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} diff --git a/apps/api/src/routes/auth.rs b/apps/api/src/routes/auth.rs new file mode 100644 index 0000000..0d155b9 --- /dev/null +++ b/apps/api/src/routes/auth.rs @@ -0,0 +1,97 @@ +use axum::{extract::State, http::StatusCode, routing::{get, post}, Json, Router}; +use serde::Deserialize; +use serde_json::{json, Value}; + +use crate::auth::{hash_password, issue_token, verify_password, AuthUser}; +use crate::error::{ApiError, ApiResult}; +use crate::models::User; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/auth/register", post(register)) + .route("/auth/login", post(login)) + .route("/auth/me", get(me)) +} + +#[derive(Deserialize)] +pub struct RegisterBody { + email: String, + password: String, + display_name: String, +} + +async fn register( + State(state): State, + Json(body): Json, +) -> ApiResult<(StatusCode, Json)> { + let email = body.email.trim().to_lowercase(); + if !email.contains('@') { + return Err(ApiError::BadRequest("invalid email".into())); + } + if body.password.len() < 8 { + return Err(ApiError::BadRequest("password must be at least 8 characters".into())); + } + if body.display_name.trim().is_empty() { + return Err(ApiError::BadRequest("display_name is required".into())); + } + let hash = hash_password(&body.password)?; + let user = sqlx::query_as::<_, User>( + "INSERT INTO users (email, password_hash, display_name, role) + VALUES ($1, $2, $3, 'customer') RETURNING *", + ) + .bind(&email) + .bind(&hash) + .bind(body.display_name.trim()) + .fetch_one(&state.db) + .await + .map_err(|e| match e { + sqlx::Error::Database(d) if d.is_unique_violation() => { + ApiError::Conflict("email already registered".into()) + } + other => ApiError::from(other), + })?; + Ok((StatusCode::CREATED, Json(auth_payload(&state, &user)?))) +} + +#[derive(Deserialize)] +pub struct LoginBody { + email: String, + password: String, +} + +async fn login( + State(state): State, + Json(body): Json, +) -> ApiResult> { + let email = body.email.trim().to_lowercase(); + let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = $1") + .bind(&email) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::Unauthorized("invalid email or password".into()))?; + if !verify_password(&body.password, &user.password_hash) { + return Err(ApiError::Unauthorized("invalid email or password".into())); + } + Ok(Json(auth_payload(&state, &user)?)) +} + +async fn me(State(state): State, auth: AuthUser) -> ApiResult> { + let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE id = $1") + .bind(auth.id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("user".into()))?; + Ok(Json(user)) +} + +fn auth_payload(state: &AppState, user: &User) -> ApiResult { + let token = issue_token( + &state.config.jwt_secret, + state.config.jwt_ttl_secs, + user.id, + user.role, + user.shop_id, + )?; + Ok(json!({ "token": token, "user": user })) +} diff --git a/apps/api/src/routes/cart.rs b/apps/api/src/routes/cart.rs new file mode 100644 index 0000000..d711a79 --- /dev/null +++ b/apps/api/src/routes/cart.rs @@ -0,0 +1,94 @@ +use axum::{ + extract::{Path, State}, + routing::{get, post, put}, + Json, Router, +}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::auth::AuthUser; +use crate::cart::{self, CartView}; +use crate::error::{ApiError, ApiResult}; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/cart", get(get_cart)) + .route("/cart/items", post(add_item)) + .route("/cart/items/{sku_id}", put(set_item).delete(remove_item)) +} + +async fn get_cart(State(state): State, auth: AuthUser) -> ApiResult> { + Ok(Json(cart::cart_view(&state, auth.id).await?)) +} + +#[derive(Deserialize)] +struct AddBody { + sku_id: Uuid, + qty: i32, +} + +async fn ensure_purchasable(state: &AppState, sku_id: Uuid) -> ApiResult<()> { + let ok: bool = sqlx::query_scalar( + "SELECT EXISTS( + SELECT 1 FROM skus s + JOIN products p ON p.id = s.product_id + JOIN shops sh ON sh.id = p.shop_id + WHERE s.id = $1 AND s.active = TRUE + AND p.status = 'published' AND sh.status = 'active')", + ) + .bind(sku_id) + .fetch_one(&state.db) + .await?; + if !ok { + return Err(ApiError::BadRequest("sku is not purchasable".into())); + } + Ok(()) +} + +async fn add_item( + State(state): State, + auth: AuthUser, + Json(body): Json, +) -> ApiResult> { + if body.qty <= 0 { + return Err(ApiError::BadRequest("qty must be > 0".into())); + } + ensure_purchasable(&state, body.sku_id).await?; + let current = cart::read_cart(&state, auth.id).await?; + let existing = current + .iter() + .find(|(id, _)| *id == body.sku_id) + .map(|(_, q)| *q) + .unwrap_or(0); + cart::set_qty(&state, auth.id, body.sku_id, existing + body.qty).await?; + Ok(Json(cart::cart_view(&state, auth.id).await?)) +} + +#[derive(Deserialize)] +struct SetBody { + qty: i32, +} + +async fn set_item( + State(state): State, + auth: AuthUser, + Path(sku_id): Path, + Json(body): Json, +) -> ApiResult> { + if body.qty <= 0 { + return Err(ApiError::BadRequest("qty must be > 0; use DELETE to remove".into())); + } + ensure_purchasable(&state, sku_id).await?; + cart::set_qty(&state, auth.id, sku_id, body.qty).await?; + Ok(Json(cart::cart_view(&state, auth.id).await?)) +} + +async fn remove_item( + State(state): State, + auth: AuthUser, + Path(sku_id): Path, +) -> ApiResult> { + cart::set_qty(&state, auth.id, sku_id, 0).await?; + Ok(Json(cart::cart_view(&state, auth.id).await?)) +} diff --git a/apps/api/src/routes/catalog.rs b/apps/api/src/routes/catalog.rs new file mode 100644 index 0000000..ff29672 --- /dev/null +++ b/apps/api/src/routes/catalog.rs @@ -0,0 +1,147 @@ +use axum::{ + extract::{Path, Query, State}, + routing::get, + Json, Router, +}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::error::{ApiError, ApiResult}; +use crate::models::{Category, Product, Sku}; +use crate::pagination::{clamp_page, clamp_per_page, Paged}; +use crate::state::AppState; + +#[derive(Debug, Serialize)] +pub struct ProductWithSkus { + #[serde(flatten)] + pub product: Product, + pub skus: Vec, +} + +pub async fn attach_skus( + db: &sqlx::PgPool, + products: Vec, + public_only: bool, +) -> ApiResult> { + let ids: Vec = products.iter().map(|p| p.id).collect(); + let skus = if ids.is_empty() { + Vec::new() + } else if public_only { + sqlx::query_as::<_, Sku>( + "SELECT * FROM skus WHERE product_id = ANY($1) AND active = TRUE ORDER BY sku_code", + ) + .bind(&ids) + .fetch_all(db) + .await? + } else { + sqlx::query_as::<_, Sku>( + "SELECT * FROM skus WHERE product_id = ANY($1) ORDER BY sku_code", + ) + .bind(&ids) + .fetch_all(db) + .await? + }; + Ok(products + .into_iter() + .map(|p| ProductWithSkus { + skus: skus.iter().filter(|s| s.product_id == p.id).cloned().collect(), + product: p, + }) + .collect()) +} + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/products", get(list_products)) + .route("/products/{id_or_slug}", get(get_product)) + .route("/categories", get(list_categories)) +} + +#[derive(Deserialize)] +struct ListQuery { + page: Option, + per_page: Option, + category_id: Option, + shop_id: Option, + q: Option, +} + +/// Public catalog: only published products of active shops. +async fn list_products( + State(state): State, + Query(q): Query, +) -> ApiResult>> { + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let pattern = q.q.as_ref().map(|s| format!("%{s}%")); + let total: i64 = sqlx::query_scalar( + "SELECT count(*) FROM products p JOIN shops s ON s.id = p.shop_id + WHERE p.status = 'published' AND s.status = 'active' + AND ($1::uuid IS NULL OR p.category_id = $1) + AND ($2::uuid IS NULL OR p.shop_id = $2) + AND ($3::text IS NULL OR p.name::text ILIKE $3)", + ) + .bind(q.category_id) + .bind(q.shop_id) + .bind(&pattern) + .fetch_one(&state.db) + .await?; + let products = sqlx::query_as::<_, Product>( + "SELECT p.* FROM products p JOIN shops s ON s.id = p.shop_id + WHERE p.status = 'published' AND s.status = 'active' + AND ($1::uuid IS NULL OR p.category_id = $1) + AND ($2::uuid IS NULL OR p.shop_id = $2) + AND ($3::text IS NULL OR p.name::text ILIKE $3) + ORDER BY p.created_at DESC + LIMIT $4 OFFSET $5", + ) + .bind(q.category_id) + .bind(q.shop_id) + .bind(&pattern) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + let items = attach_skus(&state.db, products, true).await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} + +async fn get_product( + State(state): State, + Path(id_or_slug): Path, +) -> ApiResult> { + let product = if let Ok(id) = Uuid::parse_str(&id_or_slug) { + sqlx::query_as::<_, Product>( + "SELECT p.* FROM products p JOIN shops s ON s.id = p.shop_id + WHERE p.id = $1 AND p.status = 'published' AND s.status = 'active'", + ) + .bind(id) + .fetch_optional(&state.db) + .await? + } else { + sqlx::query_as::<_, Product>( + "SELECT p.* FROM products p JOIN shops s ON s.id = p.shop_id + WHERE p.slug = $1 AND p.status = 'published' AND s.status = 'active'", + ) + .bind(&id_or_slug) + .fetch_optional(&state.db) + .await? + } + .ok_or_else(|| ApiError::NotFound("product".into()))?; + let mut items = attach_skus(&state.db, vec![product], true).await?; + Ok(Json(items.remove(0))) +} + +async fn list_categories(State(state): State) -> ApiResult>> { + let cats = sqlx::query_as::<_, Category>( + "SELECT * FROM categories ORDER BY position, slug", + ) + .fetch_all(&state.db) + .await?; + Ok(Json(cats)) +} diff --git a/apps/api/src/routes/currency.rs b/apps/api/src/routes/currency.rs new file mode 100644 index 0000000..be00714 --- /dev/null +++ b/apps/api/src/routes/currency.rs @@ -0,0 +1,57 @@ +use axum::{extract::{Query, State}, routing::get, Json, Router}; +use serde::Deserialize; +use serde_json::{json, Value}; + +use crate::error::{ApiError, ApiResult}; +use crate::models::Currency; +use crate::money::convert_minor; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/currencies", get(list_currencies)) + .route("/currencies/convert", get(convert)) +} + +pub async fn load_currencies(state: &AppState, enabled_only: bool) -> ApiResult> { + let rows = if enabled_only { + sqlx::query_as::<_, Currency>( + "SELECT * FROM currencies WHERE enabled = TRUE ORDER BY code", + ) + .fetch_all(&state.db) + .await? + } else { + sqlx::query_as::<_, Currency>("SELECT * FROM currencies ORDER BY code") + .fetch_all(&state.db) + .await? + }; + Ok(rows) +} + +async fn list_currencies(State(state): State) -> ApiResult>> { + Ok(Json(load_currencies(&state, true).await?)) +} + +#[derive(Deserialize)] +struct ConvertQuery { + amount_minor: i64, + from: String, + to: String, +} + +async fn convert( + State(state): State, + Query(q): Query, +) -> ApiResult> { + let currencies = load_currencies(&state, true).await?; + let from = currencies + .iter() + .find(|c| c.code == q.from.to_uppercase()) + .ok_or_else(|| ApiError::BadRequest(format!("unknown or disabled currency: {}", q.from)))?; + let to = currencies + .iter() + .find(|c| c.code == q.to.to_uppercase()) + .ok_or_else(|| ApiError::BadRequest(format!("unknown or disabled currency: {}", q.to)))?; + let converted = convert_minor(q.amount_minor, from, to)?; + Ok(Json(json!({ "amount_minor": converted, "currency": to.code }))) +} diff --git a/apps/api/src/routes/health.rs b/apps/api/src/routes/health.rs new file mode 100644 index 0000000..615b239 --- /dev/null +++ b/apps/api/src/routes/health.rs @@ -0,0 +1,28 @@ +use axum::{extract::State, routing::get, Json, Router}; +use redis::AsyncCommands; +use serde_json::{json, Value}; + +use crate::error::ApiResult; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new().route("/ready", get(ready)) +} + +pub async fn health() -> Json { + Json(json!({ "status": "ok" })) +} + +/// Deep health: verifies Postgres and Redis connectivity. +pub async fn ready(State(state): State) -> ApiResult> { + let db_ok = sqlx::query_scalar::<_, i32>("SELECT 1") + .fetch_one(&state.db) + .await + .is_ok(); + let mut redis = state.redis.clone(); + let redis_ok = redis + .set::<_, _, ()>("vmall:ready:ping", "1") + .await + .is_ok(); + Ok(Json(json!({ "db": db_ok, "redis": redis_ok }))) +} diff --git a/apps/api/src/routes/mod.rs b/apps/api/src/routes/mod.rs new file mode 100644 index 0000000..b0653db --- /dev/null +++ b/apps/api/src/routes/mod.rs @@ -0,0 +1,30 @@ +pub mod admin; +pub mod auth; +pub mod cart; +pub mod catalog; +pub mod currency; +pub mod health; +pub mod order_common; +pub mod orders; +pub mod shop; +pub mod shop_catalog; +pub mod shop_orders; + +use axum::Router; + +use crate::state::AppState; + +/// Routers for every domain module are merged here. +pub fn api_router(state: AppState) -> Router { + Router::new() + .merge(health::router(state.clone())) + .merge(auth::router(state.clone())) + .merge(currency::router(state.clone())) + .merge(catalog::router(state.clone())) + .merge(cart::router(state.clone())) + .merge(orders::router(state.clone())) + .merge(shop::router(state.clone())) + .merge(shop_catalog::router(state.clone())) + .merge(shop_orders::router(state.clone())) + .merge(admin::router(state)) +} diff --git a/apps/api/src/routes/order_common.rs b/apps/api/src/routes/order_common.rs new file mode 100644 index 0000000..befcaae --- /dev/null +++ b/apps/api/src/routes/order_common.rs @@ -0,0 +1,175 @@ +//! Shared read models and status-propagation helpers for order, shipment and +//! invoice routes (customer, shop and admin surfaces all use these). + +use serde::Serialize; +use sqlx::PgPool; +use uuid::Uuid; + +use crate::error::ApiResult; +use crate::models::{Invoice, Order, OrderItem, Shipment, ShipmentItem}; + +#[derive(Debug, Serialize)] +pub struct OrderView { + #[serde(flatten)] + pub order: Order, + pub items: Vec, +} + +pub async fn attach_items(db: &PgPool, orders: Vec) -> ApiResult> { + let ids: Vec = orders.iter().map(|o| o.id).collect(); + let items = if ids.is_empty() { + Vec::new() + } else { + sqlx::query_as::<_, OrderItem>( + "SELECT * FROM order_items WHERE order_id = ANY($1) ORDER BY sku_code", + ) + .bind(&ids) + .fetch_all(db) + .await? + }; + Ok(orders + .into_iter() + .map(|o| OrderView { + items: items.iter().filter(|i| i.order_id == o.id).cloned().collect(), + order: o, + }) + .collect()) +} + +#[derive(Debug, Serialize)] +pub struct ShipmentView { + #[serde(flatten)] + pub shipment: Shipment, + pub order_no: String, + pub items: Vec, +} + +pub async fn shipment_views(db: &PgPool, shipments: Vec) -> ApiResult> { + let ids: Vec = shipments.iter().map(|s| s.id).collect(); + let items = if ids.is_empty() { + Vec::new() + } else { + sqlx::query_as::<_, ShipmentItem>( + "SELECT * FROM shipment_items WHERE shipment_id = ANY($1)", + ) + .bind(&ids) + .fetch_all(db) + .await? + }; + let order_ids: Vec = shipments.iter().map(|s| s.order_id).collect(); + let order_nos: Vec<(Uuid, String)> = if order_ids.is_empty() { + Vec::new() + } else { + sqlx::query_as("SELECT id, order_no FROM orders WHERE id = ANY($1)") + .bind(&order_ids) + .fetch_all(db) + .await? + }; + Ok(shipments + .into_iter() + .map(|s| ShipmentView { + order_no: order_nos + .iter() + .find(|(id, _)| *id == s.order_id) + .map(|(_, no)| no.clone()) + .unwrap_or_default(), + items: items.iter().filter(|i| i.shipment_id == s.id).cloned().collect(), + shipment: s, + }) + .collect()) +} + +#[derive(Debug, Serialize)] +pub struct InvoiceView { + #[serde(flatten)] + pub invoice: Invoice, + pub order_no: String, +} + +pub async fn invoice_views(db: &PgPool, invoices: Vec) -> ApiResult> { + let order_ids: Vec = invoices.iter().map(|i| i.order_id).collect(); + let order_nos: Vec<(Uuid, String)> = if order_ids.is_empty() { + Vec::new() + } else { + sqlx::query_as("SELECT id, order_no FROM orders WHERE id = ANY($1)") + .bind(&order_ids) + .fetch_all(db) + .await? + }; + Ok(invoices + .into_iter() + .map(|i| InvoiceView { + order_no: order_nos + .iter() + .find(|(id, _)| *id == i.order_id) + .map(|(_, no)| no.clone()) + .unwrap_or_default(), + invoice: i, + }) + .collect()) +} + +/// After a shipment is marked shipped: order becomes `shipped` once every +/// ordered unit is covered by shipped/delivered shipment lines. +pub async fn maybe_mark_order_shipped(db: &PgPool, order_id: Uuid) -> ApiResult<()> { + let fully_covered: bool = sqlx::query_scalar( + "SELECT NOT EXISTS ( + SELECT 1 FROM order_items oi + WHERE oi.order_id = $1 AND oi.qty > COALESCE(( + SELECT sum(si.qty) FROM shipment_items si + JOIN shipments s ON s.id = si.shipment_id + WHERE si.order_item_id = oi.id AND s.status IN ('shipped', 'delivered') + ), 0) + )", + ) + .bind(order_id) + .fetch_one(db) + .await?; + if fully_covered { + sqlx::query( + "UPDATE orders SET status = 'shipped', updated_at = now() + WHERE id = $1 AND status = 'fulfilling'", + ) + .bind(order_id) + .execute(db) + .await?; + } + Ok(()) +} + +/// After a delivery confirmation: order becomes `completed` when every item is +/// covered and every shipment of the order is delivered. +pub async fn maybe_mark_order_completed(db: &PgPool, order_id: Uuid) -> ApiResult<()> { + let open_shipments: bool = sqlx::query_scalar( + "SELECT EXISTS(SELECT 1 FROM shipments WHERE order_id = $1 AND status <> 'delivered')", + ) + .bind(order_id) + .fetch_one(db) + .await?; + if open_shipments { + return Ok(()); + } + let fully_covered: bool = sqlx::query_scalar( + "SELECT NOT EXISTS ( + SELECT 1 FROM order_items oi + WHERE oi.order_id = $1 AND oi.qty > COALESCE(( + SELECT sum(si.qty) FROM shipment_items si + JOIN shipments s ON s.id = si.shipment_id + WHERE si.order_item_id = oi.id AND s.status = 'delivered' + ), 0) + )", + ) + .bind(order_id) + .fetch_one(db) + .await?; + if fully_covered { + sqlx::query( + "UPDATE orders SET status = 'completed', updated_at = now() + WHERE id = $1 AND status IN ('shipped', 'fulfilling')", + ) + .bind(order_id) + .execute(db) + .await?; + } + Ok(()) +} diff --git a/apps/api/src/routes/orders.rs b/apps/api/src/routes/orders.rs new file mode 100644 index 0000000..ad2d361 --- /dev/null +++ b/apps/api/src/routes/orders.rs @@ -0,0 +1,423 @@ +use axum::{ + extract::{Path, Query, State}, + http::StatusCode, + routing::{get, post}, + Json, Router, +}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::auth::AuthUser; +use crate::cart; +use crate::error::{ApiError, ApiResult}; +use crate::models::{Currency, Invoice, InvoiceKind, Order, OrderStatus, Shipment}; +use crate::money::convert_minor; +use crate::pagination::{clamp_page, clamp_per_page, Paged}; +use crate::routes::order_common::{ + attach_items, invoice_views, maybe_mark_order_completed, shipment_views, InvoiceView, + OrderView, ShipmentView, +}; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/orders", get(list_my_orders)) + .route("/orders/checkout", post(checkout)) + .route("/orders/{id}", get(get_order)) + .route("/orders/{id}/pay", post(pay_order)) + .route("/orders/{id}/cancel", post(cancel_order)) + .route("/orders/{id}/invoice", post(request_invoice)) + .route("/shipments", get(list_my_shipments)) + .route( + "/shipments/{id}/confirm-delivered", + post(confirm_delivered), + ) + .route("/invoices", get(list_my_invoices)) +} + +#[derive(Deserialize)] +struct PageQuery { + page: Option, + per_page: Option, +} + +async fn list_my_orders( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> ApiResult>> { + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let total: i64 = sqlx::query_scalar("SELECT count(*) FROM orders WHERE user_id = $1") + .bind(auth.id) + .fetch_one(&state.db) + .await?; + let orders = sqlx::query_as::<_, Order>( + "SELECT * FROM orders WHERE user_id = $1 + ORDER BY created_at DESC LIMIT $2 OFFSET $3", + ) + .bind(auth.id) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + let items = attach_items(&state.db, orders).await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} + +async fn load_own_order(state: &AppState, user_id: Uuid, id: Uuid) -> ApiResult { + sqlx::query_as::<_, Order>("SELECT * FROM orders WHERE id = $1 AND user_id = $2") + .bind(id) + .bind(user_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("order".into())) +} + +async fn get_order( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let order = load_own_order(&state, auth.id, id).await?; + let mut views = attach_items(&state.db, vec![order]).await?; + Ok(Json(views.remove(0))) +} + +#[derive(Deserialize, serde::Serialize)] +pub struct AddressBody { + recipient: String, + phone: String, + country: String, + region: String, + city: String, + line1: String, + postal_code: String, +} + +impl AddressBody { + fn validate(&self) -> ApiResult<()> { + for (field, value) in [ + ("recipient", &self.recipient), + ("phone", &self.phone), + ("country", &self.country), + ("city", &self.city), + ("line1", &self.line1), + ] { + if value.trim().is_empty() { + return Err(ApiError::BadRequest(format!("shipping_address.{field} is required"))); + } + } + Ok(()) + } +} + +#[derive(Deserialize)] +struct CheckoutBody { + shipping_address: AddressBody, + currency: String, +} + +#[derive(sqlx::FromRow)] +struct CheckoutRow { + sku_id: Uuid, + shop_id: Uuid, + product_name: serde_json::Value, + sku_code: String, + image: Option, + price_minor: i64, + currency: String, + stock: i32, +} + +async fn checkout( + State(state): State, + auth: AuthUser, + Json(body): Json, +) -> ApiResult<(StatusCode, Json>)> { + body.shipping_address.validate()?; + let target_currency = body.currency.to_uppercase(); + let entries = cart::read_cart(&state, auth.id).await?; + if entries.is_empty() { + return Err(ApiError::BadRequest("cart is empty".into())); + } + + let mut tx = state.db.begin().await?; + + let target: Currency = sqlx::query_as::<_, Currency>( + "SELECT * FROM currencies WHERE code = $1 AND enabled = TRUE", + ) + .bind(&target_currency) + .fetch_optional(&mut *tx) + .await? + .ok_or_else(|| ApiError::BadRequest(format!("unknown currency: {target_currency}")))?; + let all_currencies = + sqlx::query_as::<_, Currency>("SELECT * FROM currencies WHERE enabled = TRUE") + .fetch_all(&mut *tx) + .await?; + + let sku_ids: Vec = entries.iter().map(|(id, _)| *id).collect(); + let rows = sqlx::query_as::<_, CheckoutRow>( + "SELECT s.id AS sku_id, p.shop_id, p.name AS product_name, s.sku_code, + (p.images ->> 0) AS image, s.price_minor, s.currency, s.stock + FROM skus s + JOIN products p ON p.id = s.product_id + JOIN shops sh ON sh.id = p.shop_id + WHERE s.id = ANY($1) AND s.active = TRUE + AND p.status = 'published' AND sh.status = 'active' + FOR UPDATE OF s", + ) + .bind(&sku_ids) + .fetch_all(&mut *tx) + .await?; + if rows.len() != entries.len() { + return Err(ApiError::Conflict( + "some cart items are no longer purchasable".into(), + )); + } + for row in &rows { + let qty = entries + .iter() + .find(|(id, _)| *id == row.sku_id) + .map(|(_, q)| *q) + .unwrap_or(0); + if qty > row.stock { + return Err(ApiError::Conflict(format!( + "insufficient stock for SKU {}", + row.sku_code + ))); + } + } + + // group by shop, preserving first-seen order + let mut shop_order: Vec = Vec::new(); + for row in &rows { + if !shop_order.contains(&row.shop_id) { + shop_order.push(row.shop_id); + } + } + + let address = serde_json::to_value(&body.shipping_address).map_err(ApiError::internal)?; + let mut created: Vec = Vec::new(); + for shop_id in shop_order { + let shop_rows: Vec<&CheckoutRow> = rows.iter().filter(|r| r.shop_id == shop_id).collect(); + let mut total: i64 = 0; + let mut line_prices: Vec<(Uuid, i64, i32)> = Vec::new(); + for row in &shop_rows { + let qty = entries + .iter() + .find(|(id, _)| *id == row.sku_id) + .map(|(_, q)| *q) + .unwrap_or(0); + let from = all_currencies + .iter() + .find(|c| c.code == row.currency) + .ok_or_else(|| { + ApiError::BadRequest(format!("currency {} disabled", row.currency)) + })?; + let unit = convert_minor(row.price_minor, from, &target)?; + total += unit * qty as i64; + line_prices.push((row.sku_id, unit, qty)); + } + let order = sqlx::query_as::<_, Order>( + "INSERT INTO orders (order_no, shop_id, user_id, currency, total_minor, shipping_address) + VALUES ('VM' || to_char(now(), 'YYMMDD') || lpad(nextval('order_no_seq')::text, 6, '0'), + $1, $2, $3, $4, $5) + RETURNING *", + ) + .bind(shop_id) + .bind(auth.id) + .bind(&target.code) + .bind(total) + .bind(&address) + .fetch_one(&mut *tx) + .await?; + for row in &shop_rows { + let (_, unit, qty) = line_prices + .iter() + .find(|(sku, _, _)| *sku == row.sku_id) + .unwrap(); + sqlx::query( + "INSERT INTO order_items (order_id, sku_id, product_name, sku_code, image, unit_price_minor, qty) + VALUES ($1, $2, $3, $4, $5, $6, $7)", + ) + .bind(order.id) + .bind(row.sku_id) + .bind(&row.product_name) + .bind(&row.sku_code) + .bind(&row.image) + .bind(unit) + .bind(qty) + .execute(&mut *tx) + .await?; + sqlx::query("UPDATE skus SET stock = stock - $2 WHERE id = $1") + .bind(row.sku_id) + .bind(qty) + .execute(&mut *tx) + .await?; + } + created.push(order); + } + + tx.commit().await?; + cart::clear_cart(&state, auth.id).await?; + let views = attach_items(&state.db, created).await?; + Ok((StatusCode::CREATED, Json(views))) +} + +async fn pay_order( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let order = sqlx::query_as::<_, Order>( + "UPDATE orders SET status = 'paid', updated_at = now() + WHERE id = $1 AND user_id = $2 AND status = 'pending_payment' + RETURNING *", + ) + .bind(id) + .bind(auth.id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::Conflict("order not payable (missing, not yours, or wrong status)".into()))?; + let mut views = attach_items(&state.db, vec![order]).await?; + Ok(Json(views.remove(0))) +} + +async fn cancel_order( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let mut tx = state.db.begin().await?; + let order = sqlx::query_as::<_, Order>( + "UPDATE orders SET status = 'cancelled', updated_at = now() + WHERE id = $1 AND user_id = $2 AND status = 'pending_payment' + RETURNING *", + ) + .bind(id) + .bind(auth.id) + .fetch_optional(&mut *tx) + .await? + .ok_or_else(|| { + ApiError::Conflict("order not cancellable (missing, not yours, or wrong status)".into()) + })?; + // restore stock + sqlx::query( + "UPDATE skus s SET stock = s.stock + oi.qty + FROM order_items oi WHERE oi.order_id = $1 AND oi.sku_id = s.id", + ) + .bind(order.id) + .execute(&mut *tx) + .await?; + tx.commit().await?; + let mut views = attach_items(&state.db, vec![order]).await?; + Ok(Json(views.remove(0))) +} + +async fn list_my_shipments( + State(state): State, + auth: AuthUser, +) -> ApiResult>> { + let shipments = sqlx::query_as::<_, Shipment>( + "SELECT s.* FROM shipments s + JOIN orders o ON o.id = s.order_id + WHERE o.user_id = $1 + ORDER BY s.created_at DESC", + ) + .bind(auth.id) + .fetch_all(&state.db) + .await?; + Ok(Json(shipment_views(&state.db, shipments).await?)) +} + +async fn confirm_delivered( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let shipment = sqlx::query_as::<_, Shipment>( + "UPDATE shipments s SET status = 'delivered', delivered_at = now() + FROM orders o + WHERE s.id = $1 AND o.id = s.order_id AND o.user_id = $2 AND s.status = 'shipped' + RETURNING s.*", + ) + .bind(id) + .bind(auth.id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::Conflict("shipment not confirmable".into()))?; + maybe_mark_order_completed(&state.db, shipment.order_id).await?; + let mut views = shipment_views(&state.db, vec![shipment]).await?; + Ok(Json(views.remove(0))) +} + +#[derive(Deserialize)] +struct InvoiceBody { + title: String, + tax_no: Option, + kind: InvoiceKind, +} + +async fn request_invoice( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult<(StatusCode, Json)> { + let order = load_own_order(&state, auth.id, id).await?; + if matches!(order.status, OrderStatus::PendingPayment | OrderStatus::Cancelled) { + return Err(ApiError::BadRequest( + "invoices can only be requested for paid orders".into(), + )); + } + if body.title.trim().is_empty() { + return Err(ApiError::BadRequest("title is required".into())); + } + if body.kind == InvoiceKind::Company + && body.tax_no.as_ref().map(|t| t.trim().is_empty()).unwrap_or(true) + { + return Err(ApiError::BadRequest( + "tax_no is required for company invoices".into(), + )); + } + let invoice = sqlx::query_as::<_, Invoice>( + "INSERT INTO invoices (order_id, user_id, title, tax_no, kind, amount_minor, currency) + VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *", + ) + .bind(order.id) + .bind(auth.id) + .bind(body.title.trim()) + .bind(body.tax_no.as_deref().map(str::trim)) + .bind(body.kind) + .bind(order.total_minor) + .bind(&order.currency) + .fetch_one(&state.db) + .await + .map_err(|e| match e { + sqlx::Error::Database(d) if d.is_unique_violation() => { + ApiError::Conflict("order already has an open invoice".into()) + } + other => ApiError::from(other), + })?; + let mut views = invoice_views(&state.db, vec![invoice]).await?; + Ok((StatusCode::CREATED, Json(views.remove(0)))) +} + +async fn list_my_invoices( + State(state): State, + auth: AuthUser, +) -> ApiResult>> { + let invoices = sqlx::query_as::<_, Invoice>( + "SELECT * FROM invoices WHERE user_id = $1 ORDER BY created_at DESC", + ) + .bind(auth.id) + .fetch_all(&state.db) + .await?; + Ok(Json(invoice_views(&state.db, invoices).await?)) +} diff --git a/apps/api/src/routes/shop.rs b/apps/api/src/routes/shop.rs new file mode 100644 index 0000000..8270995 --- /dev/null +++ b/apps/api/src/routes/shop.rs @@ -0,0 +1,21 @@ +use axum::{extract::State, routing::get, Json, Router}; + +use crate::auth::AuthUser; +use crate::error::{ApiError, ApiResult}; +use crate::models::{Shop, UserRole}; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new().route("/shop/profile", get(my_shop)) +} + +async fn my_shop(State(state): State, auth: AuthUser) -> ApiResult> { + auth.require(&[UserRole::ShopOwner, UserRole::ShopStaff])?; + let shop_id = auth.own_shop()?; + let shop = sqlx::query_as::<_, Shop>("SELECT * FROM shops WHERE id = $1") + .bind(shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("shop".into()))?; + Ok(Json(shop)) +} diff --git a/apps/api/src/routes/shop_catalog.rs b/apps/api/src/routes/shop_catalog.rs new file mode 100644 index 0000000..d9947cc --- /dev/null +++ b/apps/api/src/routes/shop_catalog.rs @@ -0,0 +1,289 @@ +use axum::{ + extract::{Path, Query, State}, + http::StatusCode, + routing::{get, post}, + Json, Router, +}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::auth::AuthUser; +use crate::error::{ApiError, ApiResult}; +use crate::models::{Product, ProductStatus, Sku, UserRole}; +use crate::pagination::{clamp_page, clamp_per_page, Paged}; +use crate::routes::catalog::{attach_skus, ProductWithSkus}; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/shop/products", get(list_products).post(create_product)) + .route( + "/shop/products/{id}", + get(get_product).put(update_product), + ) + .route("/shop/products/{id}/publish", post(publish)) + .route("/shop/products/{id}/unpublish", post(unpublish)) + .route("/shop/products/{id}/skus", post(upsert_sku)) +} + +fn require_shop(auth: &AuthUser) -> ApiResult { + auth.require(&[UserRole::ShopOwner, UserRole::ShopStaff])?; + auth.own_shop() +} + +async fn load_own_product( + state: &AppState, + shop_id: Uuid, + id: Uuid, +) -> ApiResult { + sqlx::query_as::<_, Product>("SELECT * FROM products WHERE id = $1 AND shop_id = $2") + .bind(id) + .bind(shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("product".into())) +} + +#[derive(Deserialize)] +struct ListQuery { + page: Option, + per_page: Option, + status: Option, +} + +async fn list_products( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> ApiResult>> { + let shop_id = require_shop(&auth)?; + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let total: i64 = sqlx::query_scalar( + "SELECT count(*) FROM products WHERE shop_id = $1 AND ($2::product_status IS NULL OR status = $2)", + ) + .bind(shop_id) + .bind(q.status) + .fetch_one(&state.db) + .await?; + let products = sqlx::query_as::<_, Product>( + "SELECT * FROM products + WHERE shop_id = $1 AND ($2::product_status IS NULL OR status = $2) + ORDER BY created_at DESC LIMIT $3 OFFSET $4", + ) + .bind(shop_id) + .bind(q.status) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + let items = attach_skus(&state.db, products, false).await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} + +async fn get_product( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + let product = load_own_product(&state, shop_id, id).await?; + let mut items = attach_skus(&state.db, vec![product], false).await?; + Ok(Json(items.remove(0))) +} + +#[derive(Deserialize)] +pub struct ProductBody { + category_id: Option, + slug: String, + name: serde_json::Value, + description: Option, + images: Option, +} + +fn validate_product_body(body: &ProductBody) -> ApiResult<()> { + if body.slug.trim().is_empty() + || !body + .slug + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '-') + { + return Err(ApiError::BadRequest( + "slug must be non-empty alphanumeric with dashes".into(), + )); + } + let name_en = body.name.get("en").and_then(|v| v.as_str()).unwrap_or(""); + if name_en.trim().is_empty() { + return Err(ApiError::BadRequest("name.en is required".into())); + } + Ok(()) +} + +async fn create_product( + State(state): State, + auth: AuthUser, + Json(body): Json, +) -> ApiResult<(StatusCode, Json)> { + let shop_id = require_shop(&auth)?; + validate_product_body(&body)?; + let product = sqlx::query_as::<_, Product>( + "INSERT INTO products (shop_id, category_id, slug, name, description, images) + VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", + ) + .bind(shop_id) + .bind(body.category_id) + .bind(body.slug.trim()) + .bind(&body.name) + .bind(body.description.unwrap_or_else(|| serde_json::json!({}))) + .bind(body.images.unwrap_or_else(|| serde_json::json!([]))) + .fetch_one(&state.db) + .await + .map_err(|e| match e { + sqlx::Error::Database(d) if d.is_unique_violation() => { + ApiError::Conflict("slug already exists in this shop".into()) + } + other => ApiError::from(other), + })?; + let mut items = attach_skus(&state.db, vec![product], false).await?; + Ok((StatusCode::CREATED, Json(items.remove(0)))) +} + +async fn update_product( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + load_own_product(&state, shop_id, id).await?; + validate_product_body(&body)?; + let product = sqlx::query_as::<_, Product>( + "UPDATE products + SET category_id = $2, slug = $3, name = $4, description = $5, images = $6, updated_at = now() + WHERE id = $1 RETURNING *", + ) + .bind(id) + .bind(body.category_id) + .bind(body.slug.trim()) + .bind(&body.name) + .bind(body.description.unwrap_or_else(|| serde_json::json!({}))) + .bind(body.images.unwrap_or_else(|| serde_json::json!([]))) + .fetch_one(&state.db) + .await + .map_err(|e| match e { + sqlx::Error::Database(d) if d.is_unique_violation() => { + ApiError::Conflict("slug already exists in this shop".into()) + } + other => ApiError::from(other), + })?; + let mut items = attach_skus(&state.db, vec![product], false).await?; + Ok(Json(items.remove(0))) +} + +async fn transition( + state: &AppState, + auth: &AuthUser, + id: Uuid, + target: ProductStatus, +) -> ApiResult> { + let shop_id = require_shop(auth)?; + let product = load_own_product(state, shop_id, id).await?; + if target == ProductStatus::Published { + let sellable: bool = sqlx::query_scalar( + "SELECT EXISTS(SELECT 1 FROM skus WHERE product_id = $1 AND active = TRUE AND price_minor > 0)", + ) + .bind(product.id) + .fetch_one(&state.db) + .await?; + if !sellable { + return Err(ApiError::BadRequest( + "product needs at least one active SKU with price > 0 to publish".into(), + )); + } + } + let updated = sqlx::query_as::<_, Product>( + "UPDATE products SET status = $2, updated_at = now() WHERE id = $1 RETURNING *", + ) + .bind(product.id) + .bind(target) + .fetch_one(&state.db) + .await?; + let mut items = attach_skus(&state.db, vec![updated], false).await?; + Ok(Json(items.remove(0))) +} + +async fn publish( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + transition(&state, &auth, id, ProductStatus::Published).await +} + +async fn unpublish( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + transition(&state, &auth, id, ProductStatus::Unpublished).await +} + +#[derive(Deserialize)] +pub struct SkuBody { + sku_code: String, + attributes: Option, + price_minor: i64, + currency: String, + stock: i32, + active: Option, +} + +async fn upsert_sku( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + load_own_product(&state, shop_id, id).await?; + if body.sku_code.trim().is_empty() { + return Err(ApiError::BadRequest("sku_code is required".into())); + } + if body.price_minor < 0 { + return Err(ApiError::BadRequest("price_minor must be >= 0".into())); + } + if body.stock < 0 { + return Err(ApiError::BadRequest("stock must be >= 0".into())); + } + let currency = body.currency.to_uppercase(); + let currency_ok: bool = + sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM currencies WHERE code = $1 AND enabled)") + .bind(¤cy) + .fetch_one(&state.db) + .await?; + if !currency_ok { + return Err(ApiError::BadRequest(format!("unknown currency: {currency}"))); + } + let sku = sqlx::query_as::<_, Sku>( + "INSERT INTO skus (product_id, sku_code, attributes, price_minor, currency, stock, active) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (product_id, sku_code) + DO UPDATE SET attributes = $3, price_minor = $4, currency = $5, stock = $6, active = $7 + RETURNING *", + ) + .bind(id) + .bind(body.sku_code.trim()) + .bind(body.attributes.unwrap_or_else(|| serde_json::json!({}))) + .bind(body.price_minor) + .bind(¤cy) + .bind(body.stock) + .bind(body.active.unwrap_or(true)) + .fetch_one(&state.db) + .await?; + Ok(Json(sku)) +} diff --git a/apps/api/src/routes/shop_orders.rs b/apps/api/src/routes/shop_orders.rs new file mode 100644 index 0000000..21cef92 --- /dev/null +++ b/apps/api/src/routes/shop_orders.rs @@ -0,0 +1,275 @@ +use axum::{ + extract::{Path, Query, State}, + http::StatusCode, + routing::{get, post}, + Json, Router, +}; +use serde::Deserialize; +use uuid::Uuid; + +use crate::auth::AuthUser; +use crate::error::{ApiError, ApiResult}; +use crate::models::{Invoice, Order, OrderStatus, Shipment, UserRole}; +use crate::pagination::{clamp_page, clamp_per_page, Paged}; +use crate::routes::order_common::{ + attach_items, invoice_views, maybe_mark_order_shipped, shipment_views, InvoiceView, OrderView, + ShipmentView, +}; +use crate::state::AppState; + +pub fn router(_state: AppState) -> Router { + Router::new() + .route("/shop/orders", get(list_orders)) + .route("/shop/orders/{id}", get(get_order)) + .route("/shop/orders/{id}/shipments", post(create_shipment)) + .route("/shop/shipments", get(list_shipments)) + .route("/shop/shipments/{id}/ship", post(mark_shipped)) + .route("/shop/invoices", get(list_invoices)) + .route("/shop/invoices/{id}/issue", post(issue_invoice)) +} + +fn require_shop(auth: &AuthUser) -> ApiResult { + auth.require(&[UserRole::ShopOwner, UserRole::ShopStaff])?; + auth.own_shop() +} + +async fn load_shop_order(state: &AppState, shop_id: Uuid, id: Uuid) -> ApiResult { + sqlx::query_as::<_, Order>("SELECT * FROM orders WHERE id = $1 AND shop_id = $2") + .bind(id) + .bind(shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::NotFound("order".into())) +} + +#[derive(Deserialize)] +struct OrderQuery { + page: Option, + per_page: Option, + status: Option, +} + +async fn list_orders( + State(state): State, + auth: AuthUser, + Query(q): Query, +) -> ApiResult>> { + let shop_id = require_shop(&auth)?; + let page = clamp_page(q.page); + let per_page = clamp_per_page(q.per_page); + let total: i64 = sqlx::query_scalar( + "SELECT count(*) FROM orders WHERE shop_id = $1 AND ($2::order_status IS NULL OR status = $2)", + ) + .bind(shop_id) + .bind(q.status) + .fetch_one(&state.db) + .await?; + let orders = sqlx::query_as::<_, Order>( + "SELECT * FROM orders + WHERE shop_id = $1 AND ($2::order_status IS NULL OR status = $2) + ORDER BY created_at DESC LIMIT $3 OFFSET $4", + ) + .bind(shop_id) + .bind(q.status) + .bind(per_page) + .bind((page - 1) * per_page) + .fetch_all(&state.db) + .await?; + let items = attach_items(&state.db, orders).await?; + Ok(Json(Paged { + items, + total, + page, + per_page, + })) +} + +async fn get_order( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + let order = load_shop_order(&state, shop_id, id).await?; + let mut views = attach_items(&state.db, vec![order]).await?; + Ok(Json(views.remove(0))) +} + +#[derive(Deserialize)] +struct ShipmentItemBody { + order_item_id: Uuid, + qty: i32, +} + +#[derive(Deserialize)] +struct ShipmentBody { + carrier: String, + tracking_no: String, + items: Vec, +} + +async fn create_shipment( + State(state): State, + auth: AuthUser, + Path(id): Path, + Json(body): Json, +) -> ApiResult<(StatusCode, Json)> { + let shop_id = require_shop(&auth)?; + if body.carrier.trim().is_empty() || body.tracking_no.trim().is_empty() { + return Err(ApiError::BadRequest("carrier and tracking_no are required".into())); + } + if body.items.is_empty() || body.items.iter().any(|i| i.qty <= 0) { + return Err(ApiError::BadRequest("items must be non-empty with qty > 0".into())); + } + let mut tx = state.db.begin().await?; + let order = sqlx::query_as::<_, Order>( + "SELECT * FROM orders WHERE id = $1 AND shop_id = $2 FOR UPDATE", + ) + .bind(id) + .bind(shop_id) + .fetch_optional(&mut *tx) + .await? + .ok_or_else(|| ApiError::NotFound("order".into()))?; + if !matches!(order.status, OrderStatus::Paid | OrderStatus::Fulfilling) { + return Err(ApiError::Conflict(format!( + "order status {} does not accept shipments", + serde_json::to_value(order.status) + .ok() + .and_then(|v| v.as_str().map(String::from)) + .unwrap_or_default() + ))); + } + // validate quantities against unshipped remainder + for item in &body.items { + let remainder: Option = sqlx::query_scalar( + "SELECT oi.qty - COALESCE(( + SELECT sum(si.qty) FROM shipment_items si + JOIN shipments s ON s.id = si.shipment_id + WHERE si.order_item_id = oi.id), 0) + FROM order_items oi + WHERE oi.id = $1 AND oi.order_id = $2", + ) + .bind(item.order_item_id) + .bind(order.id) + .fetch_optional(&mut *tx) + .await?; + let remainder = remainder + .ok_or_else(|| ApiError::BadRequest("order_item_id not in this order".into()))?; + if item.qty as i64 > remainder { + return Err(ApiError::BadRequest(format!( + "qty {} exceeds unshipped remainder {}", + item.qty, remainder + ))); + } + } + let shipment = sqlx::query_as::<_, Shipment>( + "INSERT INTO shipments (shipment_no, order_id, carrier, tracking_no) + VALUES ('SH' || to_char(now(), 'YYMMDD') || lpad(nextval('shipment_no_seq')::text, 6, '0'), + $1, $2, $3) + RETURNING *", + ) + .bind(order.id) + .bind(body.carrier.trim()) + .bind(body.tracking_no.trim()) + .fetch_one(&mut *tx) + .await?; + for item in &body.items { + sqlx::query( + "INSERT INTO shipment_items (shipment_id, order_item_id, qty) VALUES ($1, $2, $3)", + ) + .bind(shipment.id) + .bind(item.order_item_id) + .bind(item.qty) + .execute(&mut *tx) + .await?; + } + sqlx::query( + "UPDATE orders SET status = 'fulfilling', updated_at = now() + WHERE id = $1 AND status = 'paid'", + ) + .bind(order.id) + .execute(&mut *tx) + .await?; + tx.commit().await?; + let mut views = shipment_views(&state.db, vec![shipment]).await?; + Ok((StatusCode::CREATED, Json(views.remove(0)))) +} + +async fn list_shipments( + State(state): State, + auth: AuthUser, +) -> ApiResult>> { + let shop_id = require_shop(&auth)?; + let shipments = sqlx::query_as::<_, Shipment>( + "SELECT s.* FROM shipments s + JOIN orders o ON o.id = s.order_id + WHERE o.shop_id = $1 + ORDER BY s.created_at DESC", + ) + .bind(shop_id) + .fetch_all(&state.db) + .await?; + Ok(Json(shipment_views(&state.db, shipments).await?)) +} + +async fn mark_shipped( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + let shipment = sqlx::query_as::<_, Shipment>( + "UPDATE shipments s SET status = 'shipped', shipped_at = now() + FROM orders o + WHERE s.id = $1 AND o.id = s.order_id AND o.shop_id = $2 AND s.status = 'pending' + RETURNING s.*", + ) + .bind(id) + .bind(shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::Conflict("shipment not found or not pending".into()))?; + maybe_mark_order_shipped(&state.db, shipment.order_id).await?; + let mut views = shipment_views(&state.db, vec![shipment]).await?; + Ok(Json(views.remove(0))) +} + +async fn list_invoices( + State(state): State, + auth: AuthUser, +) -> ApiResult>> { + let shop_id = require_shop(&auth)?; + let invoices = sqlx::query_as::<_, Invoice>( + "SELECT i.* FROM invoices i + JOIN orders o ON o.id = i.order_id + WHERE o.shop_id = $1 + ORDER BY i.created_at DESC", + ) + .bind(shop_id) + .fetch_all(&state.db) + .await?; + Ok(Json(invoice_views(&state.db, invoices).await?)) +} + +async fn issue_invoice( + State(state): State, + auth: AuthUser, + Path(id): Path, +) -> ApiResult> { + let shop_id = require_shop(&auth)?; + let invoice = sqlx::query_as::<_, Invoice>( + "UPDATE invoices i + SET status = 'issued', issued_at = now(), + invoice_no = 'INV' || to_char(now(), 'YYMMDD') || lpad(nextval('invoice_no_seq')::text, 6, '0') + FROM orders o + WHERE i.id = $1 AND o.id = i.order_id AND o.shop_id = $2 AND i.status = 'requested' + RETURNING i.*", + ) + .bind(id) + .bind(shop_id) + .fetch_optional(&state.db) + .await? + .ok_or_else(|| ApiError::Conflict("invoice not found or not in requested status".into()))?; + let mut views = invoice_views(&state.db, vec![invoice]).await?; + Ok(Json(views.remove(0))) +} diff --git a/apps/api/src/seed.rs b/apps/api/src/seed.rs new file mode 100644 index 0000000..35ab6af --- /dev/null +++ b/apps/api/src/seed.rs @@ -0,0 +1,26 @@ +use crate::auth::hash_password; +use crate::state::AppState; + +/// Idempotent dev seed: platform admin account. +pub async fn ensure_platform_admin(state: &AppState) -> anyhow::Result<()> { + let email = "admin@vmall.local"; + let exists: bool = + sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM users WHERE email = $1)") + .bind(email) + .fetch_one(&state.db) + .await?; + if exists { + return Ok(()); + } + let hash = hash_password("admin1234")?; + sqlx::query( + "INSERT INTO users (email, password_hash, display_name, role) + VALUES ($1, $2, 'Platform Admin', 'platform_admin')", + ) + .bind(email) + .bind(hash) + .execute(&state.db) + .await?; + tracing::info!("seeded platform admin admin@vmall.local"); + Ok(()) +} diff --git a/apps/api/src/state.rs b/apps/api/src/state.rs new file mode 100644 index 0000000..755b9ae --- /dev/null +++ b/apps/api/src/state.rs @@ -0,0 +1,19 @@ +use sqlx::PgPool; + +#[derive(Clone)] +pub struct AppState { + pub db: PgPool, + pub redis: redis::aio::ConnectionManager, + pub config: crate::config::Config, +} + +pub async fn build_state(config: &crate::config::Config) -> anyhow::Result { + let db = PgPool::connect(&config.database_url).await?; + let client = redis::Client::open(config.redis_url.clone())?; + let redis = redis::aio::ConnectionManager::new(client).await?; + Ok(AppState { + db, + redis, + config: config.clone(), + }) +} diff --git a/apps/api/tests/auth.rs b/apps/api/tests/auth.rs new file mode 100644 index 0000000..9873be1 --- /dev/null +++ b/apps/api/tests/auth.rs @@ -0,0 +1,91 @@ +mod common; + +use common::{client, login_admin, register_customer, spawn_app}; +use serial_test::serial; + +#[tokio::test] +#[serial] +async fn register_login_me_happy_path() { + let app = spawn_app().await; + let (token, user_id) = register_customer(&app, "alice").await; + + let res = client() + .get(app.url("/api/auth/me")) + .bearer_auth(&token) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let me: serde_json::Value = res.json().await.unwrap(); + assert_eq!(me["id"], user_id); + assert_eq!(me["role"], "customer"); + assert!(me.get("password_hash").is_none(), "hash must not leak"); +} + +#[tokio::test] +#[serial] +async fn duplicate_email_conflict() { + let app = spawn_app().await; + let email = format!("dup-{}@test.local", uuid::Uuid::new_v4()); + for expected in [201, 409] { + let res = client() + .post(app.url("/api/auth/register")) + .json(&serde_json::json!({ + "email": email, + "password": "password123", + "display_name": "dup", + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), expected); + } +} + +#[tokio::test] +#[serial] +async fn wrong_password_unauthorized() { + let app = spawn_app().await; + let email = format!("wp-{}@test.local", uuid::Uuid::new_v4()); + client() + .post(app.url("/api/auth/register")) + .json(&serde_json::json!({ + "email": email, + "password": "password123", + "display_name": "wp", + })) + .send() + .await + .unwrap(); + + let res = client() + .post(app.url("/api/auth/login")) + .json(&serde_json::json!({ "email": email, "password": "wrong-password" })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 401); +} + +#[tokio::test] +#[serial] +async fn me_requires_token() { + let app = spawn_app().await; + let res = client().get(app.url("/api/auth/me")).send().await.unwrap(); + assert_eq!(res.status(), 401); +} + +#[tokio::test] +#[serial] +async fn seeded_admin_can_login() { + let app = spawn_app().await; + let token = login_admin(&app).await; + let res = client() + .get(app.url("/api/auth/me")) + .bearer_auth(token) + .send() + .await + .unwrap(); + let me: serde_json::Value = res.json().await.unwrap(); + assert_eq!(me["role"], "platform_admin"); +} diff --git a/apps/api/tests/catalog.rs b/apps/api/tests/catalog.rs new file mode 100644 index 0000000..18a9250 --- /dev/null +++ b/apps/api/tests/catalog.rs @@ -0,0 +1,204 @@ +mod common; + +use common::{ + client, create_product_with_sku, create_shop, login_admin, make_shop_owner, register_customer, + spawn_app, +}; +use serial_test::serial; + +#[tokio::test] +#[serial] +async fn customer_forbidden_on_admin_routes() { + let app = spawn_app().await; + let (customer_token, _) = register_customer(&app, "cust").await; + let res = client() + .get(app.url("/api/admin/users")) + .bearer_auth(&customer_token) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 403); +} + +#[tokio::test] +#[serial] +async fn publish_lifecycle_and_public_visibility() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let shop_id = create_shop(&app, &admin, "shop-life").await; + let owner = make_shop_owner(&app, &admin, &shop_id).await; + + // draft with no SKU cannot be published + let res = client() + .post(app.url("/api/shop/products")) + .bearer_auth(&owner) + .json(&serde_json::json!({ + "slug": "nosku", + "name": {"en": "NoSku", "zh": "无SKU"}, + })) + .send() + .await + .unwrap(); + let no_sku_id = res.json::().await.unwrap()["id"] + .as_str() + .unwrap() + .to_string(); + let res = client() + .post(app.url(&format!("/api/shop/products/{no_sku_id}/publish"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 400); + + // product with SKU: publish → listed publicly → unpublish → gone + let (product_id, mug_slug) = create_product_with_sku(&app, &owner, "mug", 1299, 10).await; + let res = client() + .post(app.url(&format!("/api/shop/products/{product_id}/publish"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + assert_eq!(res.json::().await.unwrap()["status"], "published"); + + let res = client().get(app.url("/api/products")).send().await.unwrap(); + let list: serde_json::Value = res.json().await.unwrap(); + assert!(list["items"] + .as_array() + .unwrap() + .iter() + .any(|p| p["id"] == product_id)); + + // detail by slug works and carries i18n fields + let res = client() + .get(app.url(&format!("/api/products/{mug_slug}"))) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let detail: serde_json::Value = res.json().await.unwrap(); + assert_eq!(detail["name"]["en"], format!("Product {mug_slug}")); + assert_eq!(detail["name"]["zh"], format!("商品 {mug_slug}")); + assert_eq!(detail["skus"][0]["price_minor"], 1299); + + let res = client() + .post(app.url(&format!("/api/shop/products/{product_id}/unpublish"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let res = client() + .get(app.url(&format!("/api/products/{product_id}"))) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 404); +} + +#[tokio::test] +#[serial] +async fn shop_isolation_enforced() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let shop_a = create_shop(&app, &admin, "shop-iso-a").await; + let shop_b = create_shop(&app, &admin, "shop-iso-b").await; + let owner_a = make_shop_owner(&app, &admin, &shop_a).await; + let owner_b = make_shop_owner(&app, &admin, &shop_b).await; + + let (product_b, _) = create_product_with_sku(&app, &owner_b, "b-item", 500, 3).await; + let res = client() + .get(app.url(&format!("/api/shop/products/{product_b}"))) + .bearer_auth(&owner_a) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 404); + + // owner A's product list contains none of shop B's products + let res = client() + .get(app.url("/api/shop/products")) + .bearer_auth(&owner_a) + .send() + .await + .unwrap(); + let list: serde_json::Value = res.json().await.unwrap(); + assert!(!list["items"] + .as_array() + .unwrap() + .iter() + .any(|p| p["id"] == product_b)); +} + +#[tokio::test] +#[serial] +async fn currency_conversion_math() { + let app = spawn_app().await; + // 1000 minor USD ($10.00) -> JPY at rate 150 => 1500 minor (¥1500) + let res = client() + .get(app.url("/api/currencies/convert?amount_minor=1000&from=USD&to=JPY")) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let body: serde_json::Value = res.json().await.unwrap(); + assert_eq!(body["amount_minor"], 1500); + assert_eq!(body["currency"], "JPY"); + + // disabled currency rejected + let admin = login_admin(&app).await; + let res = client() + .post(app.url("/api/admin/currencies")) + .bearer_auth(&admin) + .json(&serde_json::json!({ + "code": "XXX", + "name": {"en": "Test", "zh": "测试"}, + "symbol": "X", + "exponent": 2, + "rate_to_base": "2.0", + "enabled": false, + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let res = client() + .get(app.url("/api/currencies/convert?amount_minor=100&from=USD&to=XXX")) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 400); +} + +#[tokio::test] +#[serial] +async fn suspended_shop_hidden_from_public_catalog() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let shop_id = create_shop(&app, &admin, "shop-susp").await; + let owner = make_shop_owner(&app, &admin, &shop_id).await; + let (product_id, _) = create_product_with_sku(&app, &owner, "susp-item", 100, 1).await; + client() + .post(app.url(&format!("/api/shop/products/{product_id}/publish"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + + client() + .put(app.url(&format!("/api/admin/shops/{shop_id}/status"))) + .bearer_auth(&admin) + .json(&serde_json::json!({ "status": "suspended" })) + .send() + .await + .unwrap(); + + let res = client().get(app.url("/api/products")).send().await.unwrap(); + let list: serde_json::Value = res.json().await.unwrap(); + assert!(!list["items"] + .as_array() + .unwrap() + .iter() + .any(|p| p["id"] == product_id)); +} diff --git a/apps/api/tests/common/mod.rs b/apps/api/tests/common/mod.rs new file mode 100644 index 0000000..ffc6182 --- /dev/null +++ b/apps/api/tests/common/mod.rs @@ -0,0 +1,256 @@ +use vmall_api::{build_router, config::Config, seed::ensure_platform_admin, state::build_state}; + +pub const TEST_DB_URL: &str = "postgres://postgres:postgres@127.0.0.1:5432/vmall_test"; +pub const TEST_REDIS_URL: &str = "redis://127.0.0.1:6379/"; + +pub struct TestApp { + pub base: String, + pub db: sqlx::PgPool, +} + +impl TestApp { + pub fn url(&self, path: &str) -> String { + format!("{}{}", self.base, path) + } +} + +/// Spin up the full app against the test database on an ephemeral port. +/// Migrations run once per process; domain tables are truncated per app. +pub async fn spawn_app() -> TestApp { + let config = Config { + database_url: TEST_DB_URL.into(), + redis_url: TEST_REDIS_URL.into(), + jwt_secret: "test-secret".into(), + port: 0, + jwt_ttl_secs: 3600, + }; + sqlx::migrate!("./migrations") + .run(&sqlx::PgPool::connect(TEST_DB_URL).await.unwrap()) + .await + .unwrap(); + let state = build_state(&config).await.unwrap(); + ensure_platform_admin(&state).await.unwrap(); + let app = build_router(state.clone()); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let port = listener.local_addr().unwrap().port(); + tokio::spawn(async move { + axum::serve(listener, app).await.unwrap(); + }); + TestApp { + base: format!("http://127.0.0.1:{port}"), + db: state.db, + } +} + +pub fn client() -> reqwest::Client { + reqwest::Client::new() +} + +/// Register a fresh customer; returns (token, user_id). +pub async fn register_customer(app: &TestApp, label: &str) -> (String, String) { + let email = format!("{label}-{}@test.local", uuid::Uuid::new_v4()); + let res = client() + .post(app.url("/api/auth/register")) + .json(&serde_json::json!({ + "email": email, + "password": "password123", + "display_name": label, + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201, "register failed: {:?}", res.text().await); + let body: serde_json::Value = res.json().await.unwrap(); + ( + body["token"].as_str().unwrap().to_string(), + body["user"]["id"].as_str().unwrap().to_string(), + ) +} + +pub async fn login_admin(app: &TestApp) -> String { + let res = client() + .post(app.url("/api/auth/login")) + .json(&serde_json::json!({ + "email": "admin@vmall.local", + "password": "admin1234", + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + res.json::().await.unwrap()["token"] + .as_str() + .unwrap() + .to_string() +} + +/// Create a shop via admin API; returns shop id. +pub async fn create_shop(app: &TestApp, admin_token: &str, slug: &str) -> String { + let slug = format!("{slug}-{}", &uuid::Uuid::new_v4().simple().to_string()[..8]); + let res = client() + .post(app.url("/api/admin/shops")) + .bearer_auth(admin_token) + .json(&serde_json::json!({ + "name": {"en": format!("Shop {slug}"), "zh": format!("店铺 {slug}")}, + "slug": slug, + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201, "create shop: {:?}", res.text().await); + res.json::().await.unwrap()["id"] + .as_str() + .unwrap() + .to_string() +} + +/// Register a user and promote them to shop_owner of `shop_id`; returns a +/// fresh token carrying the shop role (issued after role change). +pub async fn make_shop_owner(app: &TestApp, admin_token: &str, shop_id: &str) -> String { + let email = format!("owner-{}@test.local", uuid::Uuid::new_v4()); + let res = client() + .post(app.url("/api/auth/register")) + .json(&serde_json::json!({ + "email": email, + "password": "password123", + "display_name": "owner", + })) + .send() + .await + .unwrap(); + let user_id = res.json::().await.unwrap()["user"]["id"] + .as_str() + .unwrap() + .to_string(); + let res = client() + .put(app.url(&format!("/api/admin/users/{user_id}/role"))) + .bearer_auth(admin_token) + .json(&serde_json::json!({ "role": "shop_owner", "shop_id": shop_id })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200, "set role: {:?}", res.text().await); + let res = client() + .post(app.url("/api/auth/login")) + .json(&serde_json::json!({ "email": email, "password": "password123" })) + .send() + .await + .unwrap(); + res.json::().await.unwrap()["token"] + .as_str() + .unwrap() + .to_string() +} + +/// Create a draft product with one priced SKU; returns product id. +pub async fn create_product_with_sku( + app: &TestApp, + owner_token: &str, + slug: &str, + price_minor: i64, + stock: i32, +) -> (String, String) { + let slug = format!("{slug}-{}", &uuid::Uuid::new_v4().simple().to_string()[..8]); + let res = client() + .post(app.url("/api/shop/products")) + .bearer_auth(owner_token) + .json(&serde_json::json!({ + "slug": slug, + "name": {"en": format!("Product {slug}"), "zh": format!("商品 {slug}")}, + "description": {"en": "desc en", "zh": "描述"}, + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201, "create product: {:?}", res.text().await); + let product_id = res.json::().await.unwrap()["id"] + .as_str() + .unwrap() + .to_string(); + let res = client() + .post(app.url(&format!("/api/shop/products/{product_id}/skus"))) + .bearer_auth(owner_token) + .json(&serde_json::json!({ + "sku_code": format!("{slug}-default"), + "price_minor": price_minor, + "currency": "USD", + "stock": stock, + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200, "upsert sku: {:?}", res.text().await); + (product_id, slug) +} + +/// Full sellable fixture: shop + owner + published product with one SKU. +/// Returns (owner_token, shop_id, product_id, sku_id). +pub async fn setup_sellable( + app: &TestApp, + admin: &str, + slug: &str, + price_minor: i64, + stock: i32, +) -> (String, String, String, String) { + let shop_id = create_shop(app, admin, slug).await; + let owner = make_shop_owner(app, admin, &shop_id).await; + let (product_id, _) = create_product_with_sku(app, &owner, slug, price_minor, stock).await; + let res = client() + .post(app.url(&format!("/api/shop/products/{product_id}/publish"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200, "publish: {:?}", res.text().await); + let sku_id: String = + sqlx::query_scalar("SELECT id::text FROM skus WHERE product_id = $1::uuid") + .bind(&product_id) + .fetch_one(&app.db) + .await + .unwrap(); + (owner, shop_id, product_id, sku_id) +} + +pub async fn add_to_cart(app: &TestApp, token: &str, sku_id: &str, qty: i32) { + let res = client() + .post(app.url("/api/cart/items")) + .bearer_auth(token) + .json(&serde_json::json!({ "sku_id": sku_id, "qty": qty })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200, "add to cart: {:?}", res.text().await); +} + +pub async fn checkout(app: &TestApp, token: &str) -> Vec { + let res = client() + .post(app.url("/api/orders/checkout")) + .bearer_auth(token) + .json(&serde_json::json!({ + "shipping_address": { + "recipient": "Test Recipient", + "phone": "123456", + "country": "US", + "region": "CA", + "city": "San Jose", + "line1": "1 Test Way", + "postal_code": "95131" + }, + "currency": "USD" + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201, "checkout: {:?}", res.text().await); + res.json::>().await.unwrap() +} + +pub async fn pay(app: &TestApp, token: &str, order_id: &str) { + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/pay"))) + .bearer_auth(token) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200, "pay: {:?}", res.text().await); +} diff --git a/apps/api/tests/orders.rs b/apps/api/tests/orders.rs new file mode 100644 index 0000000..4414bea --- /dev/null +++ b/apps/api/tests/orders.rs @@ -0,0 +1,318 @@ +mod common; + +use common::{ + add_to_cart, checkout, client, login_admin, pay, register_customer, setup_sellable, spawn_app, +}; +use serial_test::serial; + +async fn stock_of(app: &common::TestApp, sku_id: &str) -> i32 { + sqlx::query_scalar("SELECT stock FROM skus WHERE id = $1::uuid") + .bind(sku_id) + .fetch_one(&app.db) + .await + .unwrap() +} + +#[tokio::test] +#[serial] +async fn checkout_splits_orders_per_shop_and_clears_cart() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (_, _, _, sku_a) = setup_sellable(&app, &admin, "split-a", 1000, 5).await; + let (_, _, _, sku_b) = setup_sellable(&app, &admin, "split-b", 2000, 5).await; + let (buyer, _) = register_customer(&app, "buyer").await; + + add_to_cart(&app, &buyer, &sku_a, 2).await; + add_to_cart(&app, &buyer, &sku_b, 1).await; + + let orders = checkout(&app, &buyer).await; + assert_eq!(orders.len(), 2, "one order per shop"); + let totals: Vec = orders + .iter() + .map(|o| o["total_minor"].as_i64().unwrap()) + .collect(); + assert!(totals.contains(&2000) && totals.contains(&2000)); // 2×1000 and 1×2000 + assert!(orders.iter().all(|o| o["status"] == "pending_payment")); + + // stock decremented + assert_eq!(stock_of(&app, &sku_a).await, 3); + assert_eq!(stock_of(&app, &sku_b).await, 4); + + // cart cleared + let res = client() + .get(app.url("/api/cart")) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.json::().await.unwrap()["items"] + .as_array() + .unwrap() + .len(), 0); +} + +#[tokio::test] +#[serial] +async fn checkout_insufficient_stock_rolls_back() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (_, _, _, sku) = setup_sellable(&app, &admin, "lowstock", 500, 1).await; + let (buyer, _) = register_customer(&app, "buyer2").await; + add_to_cart(&app, &buyer, &sku, 2).await; + + let res = client() + .post(app.url("/api/orders/checkout")) + .bearer_auth(&buyer) + .json(&serde_json::json!({ + "shipping_address": { + "recipient": "R", "phone": "1", "country": "US", "region": "CA", + "city": "SJ", "line1": "1 Way", "postal_code": "95131" + }, + "currency": "USD" + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 409); + assert_eq!(stock_of(&app, &sku).await, 1, "stock unchanged"); +} + +#[tokio::test] +#[serial] +async fn cancel_rules_and_stock_restore() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (_, _, _, sku) = setup_sellable(&app, &admin, "cancelme", 800, 4).await; + let (buyer, _) = register_customer(&app, "buyer3").await; + add_to_cart(&app, &buyer, &sku, 2).await; + let orders = checkout(&app, &buyer).await; + let order_id = orders[0]["id"].as_str().unwrap(); + assert_eq!(stock_of(&app, &sku).await, 2); + + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/cancel"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + assert_eq!(stock_of(&app, &sku).await, 4, "stock restored"); + + // paid orders cannot be cancelled + add_to_cart(&app, &buyer, &sku, 1).await; + let orders = checkout(&app, &buyer).await; + let order_id = orders[0]["id"].as_str().unwrap(); + pay(&app, &buyer, order_id).await; + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/cancel"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 409); +} + +#[tokio::test] +#[serial] +async fn fulfillment_flow_partial_then_complete() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (owner, _, _, sku) = setup_sellable(&app, &admin, "fulfil", 1500, 10).await; + let (buyer, _) = register_customer(&app, "buyer4").await; + add_to_cart(&app, &buyer, &sku, 3).await; + let orders = checkout(&app, &buyer).await; + let order = &orders[0]; + let order_id = order["id"].as_str().unwrap(); + let item_id = order["items"][0]["id"].as_str().unwrap(); + pay(&app, &buyer, order_id).await; + + // over-shipping the remainder is rejected + let res = client() + .post(app.url(&format!("/api/shop/orders/{order_id}/shipments"))) + .bearer_auth(&owner) + .json(&serde_json::json!({ + "carrier": "UPS", "tracking_no": "T1", + "items": [{ "order_item_id": item_id, "qty": 4 }] + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 400); + + // partial shipment of 2 → order fulfilling + let res = client() + .post(app.url(&format!("/api/shop/orders/{order_id}/shipments"))) + .bearer_auth(&owner) + .json(&serde_json::json!({ + "carrier": "UPS", "tracking_no": "T1", + "items": [{ "order_item_id": item_id, "qty": 2 }] + })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201); + let shipment1: serde_json::Value = res.json().await.unwrap(); + let shipment1_id = shipment1["id"].as_str().unwrap().to_string(); + + let res = client() + .post(app.url(&format!("/api/shop/shipments/{shipment1_id}/ship"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let res = client() + .get(app.url(&format!("/api/orders/{order_id}"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.json::().await.unwrap()["status"], "fulfilling"); + + // second shipment covers remainder → shipped after mark + let res = client() + .post(app.url(&format!("/api/shop/orders/{order_id}/shipments"))) + .bearer_auth(&owner) + .json(&serde_json::json!({ + "carrier": "UPS", "tracking_no": "T2", + "items": [{ "order_item_id": item_id, "qty": 1 }] + })) + .send() + .await + .unwrap(); + let shipment2_id = res.json::().await.unwrap()["id"] + .as_str() + .unwrap() + .to_string(); + client() + .post(app.url(&format!("/api/shop/shipments/{shipment2_id}/ship"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + let res = client() + .get(app.url(&format!("/api/orders/{order_id}"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.json::().await.unwrap()["status"], "shipped"); + + // confirm both deliveries → completed + for sid in [&shipment1_id, &shipment2_id] { + let res = client() + .post(app.url(&format!("/api/shipments/{sid}/confirm-delivered"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + } + let res = client() + .get(app.url(&format!("/api/orders/{order_id}"))) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + assert_eq!(res.json::().await.unwrap()["status"], "completed"); +} + +#[tokio::test] +#[serial] +async fn invoice_lifecycle() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (owner, _, _, sku) = setup_sellable(&app, &admin, "invc", 3000, 2).await; + let (buyer, _) = register_customer(&app, "buyer5").await; + add_to_cart(&app, &buyer, &sku, 1).await; + let orders = checkout(&app, &buyer).await; + let order_id = orders[0]["id"].as_str().unwrap(); + + // pending_payment orders cannot be invoiced + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/invoice"))) + .bearer_auth(&buyer) + .json(&serde_json::json!({ "title": "Me", "kind": "personal" })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 400); + + pay(&app, &buyer, order_id).await; + + // company invoice requires tax_no + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/invoice"))) + .bearer_auth(&buyer) + .json(&serde_json::json!({ "title": "ACME", "kind": "company" })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 400); + + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/invoice"))) + .bearer_auth(&buyer) + .json(&serde_json::json!({ "title": "ACME", "tax_no": "US-123", "kind": "company" })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 201); + let invoice: serde_json::Value = res.json().await.unwrap(); + assert_eq!(invoice["status"], "requested"); + assert_eq!(invoice["amount_minor"], 3000); + + // duplicate rejected + let res = client() + .post(app.url(&format!("/api/orders/{order_id}/invoice"))) + .bearer_auth(&buyer) + .json(&serde_json::json!({ "title": "Again", "kind": "personal" })) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 409); + + // shop issues it + let invoice_id = invoice["id"].as_str().unwrap(); + let res = client() + .post(app.url(&format!("/api/shop/invoices/{invoice_id}/issue"))) + .bearer_auth(&owner) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 200); + let issued: serde_json::Value = res.json().await.unwrap(); + assert_eq!(issued["status"], "issued"); + assert!(issued["invoice_no"].as_str().unwrap().starts_with("INV")); + + // customer sees issued invoice + let res = client() + .get(app.url("/api/invoices")) + .bearer_auth(&buyer) + .send() + .await + .unwrap(); + let invoices: serde_json::Value = res.json().await.unwrap(); + assert_eq!(invoices[0]["status"], "issued"); +} + +#[tokio::test] +#[serial] +async fn order_ownership_enforced() { + let app = spawn_app().await; + let admin = login_admin(&app).await; + let (_, _, _, sku) = setup_sellable(&app, &admin, "ownerchk", 100, 1).await; + let (buyer, _) = register_customer(&app, "buyer6").await; + let (other, _) = register_customer(&app, "buyer7").await; + add_to_cart(&app, &buyer, &sku, 1).await; + let orders = checkout(&app, &buyer).await; + let order_id = orders[0]["id"].as_str().unwrap(); + + let res = client() + .get(app.url(&format!("/api/orders/{order_id}"))) + .bearer_auth(&other) + .send() + .await + .unwrap(); + assert_eq!(res.status(), 404); +} diff --git a/apps/mall/app.d.ts b/apps/mall/app.d.ts new file mode 100644 index 0000000..4e21577 --- /dev/null +++ b/apps/mall/app.d.ts @@ -0,0 +1,9 @@ +import type { ApiClient } from "@vmall/shared"; + +declare module "#app" { + interface NuxtApp { + $api: ApiClient; + } +} + +export {}; diff --git a/apps/mall/app.vue b/apps/mall/app.vue new file mode 100644 index 0000000..7bac7dd --- /dev/null +++ b/apps/mall/app.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/mall/composables/usePrefs.ts b/apps/mall/composables/usePrefs.ts new file mode 100644 index 0000000..03412fa --- /dev/null +++ b/apps/mall/composables/usePrefs.ts @@ -0,0 +1,5 @@ +/** Shopper preferences: display currency, persisted in a cookie (SSR-safe). */ +export function usePrefs() { + const currency = useCookie("vmall.currency", { default: () => "USD" }); + return { currency }; +} diff --git a/apps/mall/i18n.config.ts b/apps/mall/i18n.config.ts new file mode 100644 index 0000000..bcfb01f --- /dev/null +++ b/apps/mall/i18n.config.ts @@ -0,0 +1,8 @@ +import { en, zh } from "@vmall/shared/locales"; + +export default defineI18nConfig(() => ({ + legacy: false, + locale: "en", + fallbackLocale: "en", + messages: { en, zh }, +})); diff --git a/apps/mall/nuxt.config.ts b/apps/mall/nuxt.config.ts new file mode 100644 index 0000000..98190ff --- /dev/null +++ b/apps/mall/nuxt.config.ts @@ -0,0 +1,22 @@ +export default defineNuxtConfig({ + modules: ["@pinia/nuxt", "@nuxtjs/i18n"], + css: ["@vmall/shared/ui.css"], + devtools: { enabled: false }, + devServer: { port: 3000 }, + runtimeConfig: { + public: { + apiBase: "http://localhost:8080/api", + appName: "mall", + }, + }, + i18n: { + strategy: "no_prefix", + defaultLocale: "en", + locales: [ + { code: "en", name: "English" }, + { code: "zh", name: "中文" }, + ], + vueI18n: "./i18n.config.ts", + }, + compatibilityDate: "2025-01-01", +}); diff --git a/apps/mall/package.json b/apps/mall/package.json new file mode 100644 index 0000000..ae6be9d --- /dev/null +++ b/apps/mall/package.json @@ -0,0 +1,19 @@ +{ + "name": "@vmall/mall", + "private": true, + "type": "module", + "scripts": { + "dev": "nuxt dev", + "build": "nuxt build", + "preview": "nuxt preview" + }, + "dependencies": { + "@nuxtjs/i18n": "^9.5.3", + "@pinia/nuxt": "^0.10.1", + "@vmall/shared": "workspace:*", + "nuxt": "^3.15.4", + "pinia": "^2.3.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + } +} diff --git a/apps/mall/pages/index.vue b/apps/mall/pages/index.vue new file mode 100644 index 0000000..d286cfd --- /dev/null +++ b/apps/mall/pages/index.vue @@ -0,0 +1,6 @@ + diff --git a/apps/mall/plugins/api.ts b/apps/mall/plugins/api.ts new file mode 100644 index 0000000..1678a49 --- /dev/null +++ b/apps/mall/plugins/api.ts @@ -0,0 +1,10 @@ +import { createApi } from "@vmall/shared"; + +export default defineNuxtPlugin(() => { + const config = useRuntimeConfig(); + const api = createApi({ + baseUrl: config.public.apiBase as string, + getToken: () => (import.meta.client ? localStorage.getItem("vmall.token") : null), + }); + return { provide: { api } }; +}); diff --git a/apps/mall/stores/session.ts b/apps/mall/stores/session.ts new file mode 100644 index 0000000..286bda2 --- /dev/null +++ b/apps/mall/stores/session.ts @@ -0,0 +1,64 @@ +import { defineStore } from "pinia"; +import type { AuthTokens, User } from "@vmall/shared"; + +const USER_KEY = "vmall.user"; +const TOKEN_KEY = "vmall.token"; + +function isUser(v: unknown): v is User { + if (!v || typeof v !== "object") return false; + const o = v as Record; + return ( + typeof o.id === "string" && + typeof o.email === "string" && + typeof o.display_name === "string" && + typeof o.role === "string" + ); +} + +export function readStoredUser(): User | null { + if (!import.meta.client) return null; + try { + const raw = localStorage.getItem(USER_KEY); + if (!raw) return null; + const parsed: unknown = JSON.parse(raw); + return isUser(parsed) ? parsed : null; + } catch { + return null; + } +} + +interface SessionState { + user: User | null; + token: string | null; +} + +export const useSessionStore = defineStore("session", { + state: (): SessionState => ({ user: null, token: null }), + getters: { + isLoggedIn: (s): boolean => s.token !== null, + }, + actions: { + hydrate(): void { + if (!import.meta.client) return; + this.token = localStorage.getItem(TOKEN_KEY); + this.user = readStoredUser(); + }, + setAuth(auth: AuthTokens): void { + this.token = auth.token; + this.user = auth.user; + if (import.meta.client) { + localStorage.setItem(TOKEN_KEY, auth.token); + localStorage.setItem(USER_KEY, JSON.stringify(auth.user)); + } + }, + logout(): void { + this.token = null; + this.user = null; + if (import.meta.client) { + localStorage.removeItem(TOKEN_KEY); + localStorage.removeItem(USER_KEY); + } + navigateTo("/login"); + }, + }, +}); diff --git a/apps/shop-admin/app.d.ts b/apps/shop-admin/app.d.ts new file mode 100644 index 0000000..4e21577 --- /dev/null +++ b/apps/shop-admin/app.d.ts @@ -0,0 +1,9 @@ +import type { ApiClient } from "@vmall/shared"; + +declare module "#app" { + interface NuxtApp { + $api: ApiClient; + } +} + +export {}; diff --git a/apps/shop-admin/app.vue b/apps/shop-admin/app.vue new file mode 100644 index 0000000..b61555a --- /dev/null +++ b/apps/shop-admin/app.vue @@ -0,0 +1,47 @@ + + + diff --git a/apps/shop-admin/composables/usePrefs.ts b/apps/shop-admin/composables/usePrefs.ts new file mode 100644 index 0000000..03412fa --- /dev/null +++ b/apps/shop-admin/composables/usePrefs.ts @@ -0,0 +1,5 @@ +/** Shopper preferences: display currency, persisted in a cookie (SSR-safe). */ +export function usePrefs() { + const currency = useCookie("vmall.currency", { default: () => "USD" }); + return { currency }; +} diff --git a/apps/shop-admin/i18n.config.ts b/apps/shop-admin/i18n.config.ts new file mode 100644 index 0000000..bcfb01f --- /dev/null +++ b/apps/shop-admin/i18n.config.ts @@ -0,0 +1,8 @@ +import { en, zh } from "@vmall/shared/locales"; + +export default defineI18nConfig(() => ({ + legacy: false, + locale: "en", + fallbackLocale: "en", + messages: { en, zh }, +})); diff --git a/apps/shop-admin/nuxt.config.ts b/apps/shop-admin/nuxt.config.ts new file mode 100644 index 0000000..e06f0ab --- /dev/null +++ b/apps/shop-admin/nuxt.config.ts @@ -0,0 +1,22 @@ +export default defineNuxtConfig({ + modules: ["@pinia/nuxt", "@nuxtjs/i18n"], + css: ["@vmall/shared/ui.css"], + devtools: { enabled: false }, + devServer: { port: 3001 }, + runtimeConfig: { + public: { + apiBase: "http://localhost:8080/api", + appName: "shop-admin", + }, + }, + i18n: { + strategy: "no_prefix", + defaultLocale: "en", + locales: [ + { code: "en", name: "English" }, + { code: "zh", name: "中文" }, + ], + vueI18n: "./i18n.config.ts", + }, + compatibilityDate: "2025-01-01", +}); diff --git a/apps/shop-admin/package.json b/apps/shop-admin/package.json new file mode 100644 index 0000000..99ca057 --- /dev/null +++ b/apps/shop-admin/package.json @@ -0,0 +1,19 @@ +{ + "name": "@vmall/shop-admin", + "private": true, + "type": "module", + "scripts": { + "dev": "nuxt dev", + "build": "nuxt build", + "preview": "nuxt preview" + }, + "dependencies": { + "@nuxtjs/i18n": "^9.5.3", + "@pinia/nuxt": "^0.10.1", + "@vmall/shared": "workspace:*", + "nuxt": "^3.15.4", + "pinia": "^2.3.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + } +} diff --git a/apps/shop-admin/pages/index.vue b/apps/shop-admin/pages/index.vue new file mode 100644 index 0000000..d286cfd --- /dev/null +++ b/apps/shop-admin/pages/index.vue @@ -0,0 +1,6 @@ + diff --git a/apps/shop-admin/plugins/api.ts b/apps/shop-admin/plugins/api.ts new file mode 100644 index 0000000..1678a49 --- /dev/null +++ b/apps/shop-admin/plugins/api.ts @@ -0,0 +1,10 @@ +import { createApi } from "@vmall/shared"; + +export default defineNuxtPlugin(() => { + const config = useRuntimeConfig(); + const api = createApi({ + baseUrl: config.public.apiBase as string, + getToken: () => (import.meta.client ? localStorage.getItem("vmall.token") : null), + }); + return { provide: { api } }; +}); diff --git a/apps/shop-admin/stores/session.ts b/apps/shop-admin/stores/session.ts new file mode 100644 index 0000000..286bda2 --- /dev/null +++ b/apps/shop-admin/stores/session.ts @@ -0,0 +1,64 @@ +import { defineStore } from "pinia"; +import type { AuthTokens, User } from "@vmall/shared"; + +const USER_KEY = "vmall.user"; +const TOKEN_KEY = "vmall.token"; + +function isUser(v: unknown): v is User { + if (!v || typeof v !== "object") return false; + const o = v as Record; + return ( + typeof o.id === "string" && + typeof o.email === "string" && + typeof o.display_name === "string" && + typeof o.role === "string" + ); +} + +export function readStoredUser(): User | null { + if (!import.meta.client) return null; + try { + const raw = localStorage.getItem(USER_KEY); + if (!raw) return null; + const parsed: unknown = JSON.parse(raw); + return isUser(parsed) ? parsed : null; + } catch { + return null; + } +} + +interface SessionState { + user: User | null; + token: string | null; +} + +export const useSessionStore = defineStore("session", { + state: (): SessionState => ({ user: null, token: null }), + getters: { + isLoggedIn: (s): boolean => s.token !== null, + }, + actions: { + hydrate(): void { + if (!import.meta.client) return; + this.token = localStorage.getItem(TOKEN_KEY); + this.user = readStoredUser(); + }, + setAuth(auth: AuthTokens): void { + this.token = auth.token; + this.user = auth.user; + if (import.meta.client) { + localStorage.setItem(TOKEN_KEY, auth.token); + localStorage.setItem(USER_KEY, JSON.stringify(auth.user)); + } + }, + logout(): void { + this.token = null; + this.user = null; + if (import.meta.client) { + localStorage.removeItem(TOKEN_KEY); + localStorage.removeItem(USER_KEY); + } + navigateTo("/login"); + }, + }, +}); diff --git a/openspec/changes/cart-checkout-orders/proposal.md b/openspec/changes/cart-checkout-orders/proposal.md new file mode 100644 index 0000000..0148be8 --- /dev/null +++ b/openspec/changes/cart-checkout-orders/proposal.md @@ -0,0 +1,17 @@ +# Proposal: cart-checkout-orders + +## Why +Shoppers must be able to collect items and place orders. Checkout splits the cart into one order per shop (B2B2C requirement), snapshots prices, and decrements stock atomically. + +## What changes +- Redis-backed cart per authenticated user (add/update/remove/list), merged SKU + product snapshot at read time. +- Checkout: validate stock + published status, create orders (one per shop) with items, decrement stock in a transaction, clear cart. +- Order lifecycle: pending_payment → paid (mock pay endpoint) → fulfilling → shipped → completed; customer cancel while pending_payment. +- Customer APIs: my orders list/detail, cancel, mock-pay. + +## Non-goals +- Real payment gateways, partial refunds, guest checkout. + +## Capabilities +- `cart`: server-side cart. +- `order`: checkout, order lifecycle, customer order APIs. diff --git a/openspec/changes/cart-checkout-orders/specs/cart/spec.md b/openspec/changes/cart-checkout-orders/specs/cart/spec.md new file mode 100644 index 0000000..8a30edf --- /dev/null +++ b/openspec/changes/cart-checkout-orders/specs/cart/spec.md @@ -0,0 +1,14 @@ +# Spec delta: cart + +## ADDED Requirements + +### Requirement: Server-side cart +Authenticated shoppers SHALL have a Redis-backed cart keyed by user id, containing sku_id + qty entries. + +#### Scenario: add and update +- **WHEN** a shopper POSTs sku + qty, then PUTs a new qty +- **THEN** GET /api/cart reflects the latest qty with current price/name snapshot + +#### Scenario: unpurchasable SKU rejected +- **WHEN** adding a SKU that is inactive or whose product is not published +- **THEN** the API returns 400 diff --git a/openspec/changes/cart-checkout-orders/specs/order/spec.md b/openspec/changes/cart-checkout-orders/specs/order/spec.md new file mode 100644 index 0000000..bac498c --- /dev/null +++ b/openspec/changes/cart-checkout-orders/specs/order/spec.md @@ -0,0 +1,32 @@ +# Spec delta: order + +## ADDED Requirements + +### Requirement: Checkout splits by shop +`POST /api/orders/checkout` SHALL create one order per distinct shop in the cart, in a single database transaction: stock decrement, order + item insert with price snapshots, cart clear. All amounts use the cart's SKU currencies converted into the buyer-chosen display currency at checkout time. + +#### Scenario: two shops → two orders +- **WHEN** the cart contains SKUs from shops A and B +- **THEN** two orders are created, each with only its shop's items, and the cart is empty + +#### Scenario: insufficient stock +- **WHEN** any line's qty exceeds SKU stock +- **THEN** the whole checkout returns 409 and no order is created and stock is unchanged + +### Requirement: Order lifecycle +Status transitions SHALL be: pending_payment → paid → fulfilling → shipped → completed; cancellable only from pending_payment, which MUST restore stock. + +#### Scenario: cancel restores stock +- **WHEN** a customer cancels a pending_payment order +- **THEN** stock of each SKU increases by the ordered qty and status is cancelled + +#### Scenario: illegal transition rejected +- **WHEN** cancelling a paid order via the customer endpoint +- **THEN** the API returns 409 + +### Requirement: Order ownership +Customers SHALL see only their own orders; shop roles only their shop's orders; platform_admin sees all. + +#### Scenario: cross-customer read denied +- **WHEN** customer X requests customer Y's order id +- **THEN** the API returns 404 diff --git a/openspec/changes/cart-checkout-orders/tasks.md b/openspec/changes/cart-checkout-orders/tasks.md new file mode 100644 index 0000000..dfe434a --- /dev/null +++ b/openspec/changes/cart-checkout-orders/tasks.md @@ -0,0 +1,17 @@ +# Tasks: cart-checkout-orders + +## 1. Schema +- [ ] Migration: orders, order_items; order status enum; order_no sequence + +## 2. Cart (Redis) +- [ ] GET /api/cart, POST /api/cart/items, PUT/DELETE /api/cart/items/{sku_id} +- [ ] Cart read joins SKU/product snapshots; rejects inactive/unpublished SKUs + +## 3. Checkout & orders +- [ ] POST /api/orders/checkout (one order per shop, tx: stock decrement + order insert, cart clear) +- [ ] GET /api/orders (mine, paged), GET /api/orders/{id} +- [ ] POST /api/orders/{id}/pay (mock) and /cancel with state rules +- [ ] GET /api/shop/orders for merchants; platform admin list + +## 4. Tests +- [ ] cargo test: multi-shop checkout splits orders, insufficient stock → 409, cancel rules, stock restored on cancel diff --git a/openspec/changes/catalog-i18n-currency/proposal.md b/openspec/changes/catalog-i18n-currency/proposal.md new file mode 100644 index 0000000..71bb38d --- /dev/null +++ b/openspec/changes/catalog-i18n-currency/proposal.md @@ -0,0 +1,18 @@ +# Proposal: catalog-i18n-currency + +## Why +Merchants must manage products (create, edit, publish/unpublish) and shoppers must browse a localized, multi-currency storefront. This phase delivers the catalog core plus the currency infrastructure every price display depends on. + +## What changes +- Schema: categories, products (JSONB i18n name/description), skus (price minor units + currency + stock), currencies (rate_to_base). +- Public APIs: product list (paged, filter by category/q/shop), product detail by id/slug, category list, currency list + conversion endpoint. +- Shop-admin APIs: product CRUD, SKU upsert, publish/unpublish transitions. +- Seed: base currency USD, plus CNY/EUR/JPY; demo categories. + +## Non-goals +- Inventory reservations/warehouses, product variants matrix UI, image upload (URLs only). +- Full-text search engines; ILIKE search is sufficient for MVP. + +## Capabilities +- `catalog`: categories, products, SKUs, publish lifecycle. +- `currency`: currency registry and conversion. diff --git a/openspec/changes/catalog-i18n-currency/specs/catalog/spec.md b/openspec/changes/catalog-i18n-currency/specs/catalog/spec.md new file mode 100644 index 0000000..62940aa --- /dev/null +++ b/openspec/changes/catalog-i18n-currency/specs/catalog/spec.md @@ -0,0 +1,37 @@ +# Spec delta: catalog + +## ADDED Requirements + +### Requirement: Localized product content +Product and category names/descriptions SHALL be stored as JSONB maps keyed by locale (`en`, `zh`). The API MUST return the full map; clients pick the display locale. + +#### Scenario: bilingual round-trip +- **WHEN** a shop owner creates a product with name `{"en": "Mug", "zh": "马克杯"}` +- **THEN** both public detail and shop-admin GET return the identical map + +### Requirement: Publish lifecycle +Products SHALL have status `draft | published | unpublished`. Only `published` products appear in public list/detail. + +#### Scenario: publish then unpublish +- **WHEN** a product is published +- **THEN** it appears in `GET /api/products` +- **WHEN** it is unpublished +- **THEN** public detail returns 404 and it disappears from listings + +#### Scenario: publish requires sellable SKU +- **WHEN** publishing a product with no active SKU having price > 0 +- **THEN** the API returns 400 + +### Requirement: Shop isolation +Shop-role users SHALL only see and mutate their own shop's products under `/api/shop/products`. + +#### Scenario: cross-shop access denied +- **WHEN** shop owner A requests `/api/shop/products/{id}` of shop B +- **THEN** the API returns 404 + +### Requirement: SKU pricing +Each SKU SHALL carry `price_minor` (integer minor units) and an ISO `currency` code; stock is a non-negative integer. + +#### Scenario: negative stock rejected +- **WHEN** upserting a SKU with stock < 0 +- **THEN** the API returns 400 diff --git a/openspec/changes/catalog-i18n-currency/specs/currency/spec.md b/openspec/changes/catalog-i18n-currency/specs/currency/spec.md new file mode 100644 index 0000000..6bc0242 --- /dev/null +++ b/openspec/changes/catalog-i18n-currency/specs/currency/spec.md @@ -0,0 +1,21 @@ +# Spec delta: currency + +## ADDED Requirements + +### Requirement: Currency registry +The system SHALL maintain a currencies table: ISO code, localized name, symbol, exponent (minor units), enabled flag, and `rate_to_base` (NUMERIC). Exactly one currency is the base. + +#### Scenario: seeded currencies +- **WHEN** migrations finish +- **THEN** USD exists as base with rate 1, and CNY/EUR/JPY exist with positive rates + +### Requirement: Amount conversion +`GET /api/currencies/convert` SHALL convert integer minor units between enabled currencies via base rates, rounding half-up to the target exponent. + +#### Scenario: USD to JPY +- **WHEN** converting 1000 minor USD (=$10.00) to JPY with rate 150 +- **THEN** the result is 1500 minor JPY (¥1500), an integer + +#### Scenario: disabled currency rejected +- **WHEN** converting to a disabled or unknown currency +- **THEN** the API returns 400 diff --git a/openspec/changes/catalog-i18n-currency/tasks.md b/openspec/changes/catalog-i18n-currency/tasks.md new file mode 100644 index 0000000..dd0ddf1 --- /dev/null +++ b/openspec/changes/catalog-i18n-currency/tasks.md @@ -0,0 +1,22 @@ +# Tasks: catalog-i18n-currency + +## 1. Schema +- [ ] Migration: currencies, categories, products, skus; product status enum +- [ ] Seed currencies (USD base, CNY, EUR, JPY) + demo categories (bilingual) + +## 2. Currency APIs +- [ ] GET /api/currencies (public, enabled only) +- [ ] GET /api/currencies/convert?amount_minor&from&to + +## 3. Public catalog APIs +- [ ] GET /api/products (paged; filters: category_id, q, shop_id; only published) +- [ ] GET /api/products/{id_or_slug} (published only, with SKUs) +- [ ] GET /api/categories + +## 4. Shop-admin catalog APIs +- [ ] GET/POST /api/shop/products, PUT /api/shop/products/{id} +- [ ] POST /api/shop/products/{id}/publish | /unpublish +- [ ] POST /api/shop/products/{id}/skus (upsert by sku_code) + +## 5. Tests +- [ ] cargo test: publish lifecycle visibility, i18n fields round-trip, currency conversion math, shop isolation diff --git a/openspec/changes/foundation-auth/proposal.md b/openspec/changes/foundation-auth/proposal.md new file mode 100644 index 0000000..8a265f0 --- /dev/null +++ b/openspec/changes/foundation-auth/proposal.md @@ -0,0 +1,19 @@ +# Proposal: foundation-auth + +## Why +VMall needs a working backend skeleton and an identity layer before any commerce feature: users, roles (platform_admin / shop_owner / shop_staff / customer), and JWT-based auth that gates every protected endpoint. + +## What changes +- Rust axum API skeleton: config, structured errors, health/readiness endpoints, sqlx migrations on boot, Redis connection manager. +- Users table with argon2 password hashes; shops table (needed for role scoping). +- Auth endpoints: register (customer), login, me. +- JWT issuance/validation middleware; role-guard helpers (`require_role`, shop-scoping for shop roles). +- Seed: one platform admin account. + +## Non-goals +- OAuth / social login, refresh tokens, password reset flows. +- Fine-grained permission tables beyond the four roles. + +## Capabilities +- `auth`: registration, login, token issuance, current-user lookup. +- `rbac`: role model and enforcement on protected routes. diff --git a/openspec/changes/foundation-auth/specs/auth/spec.md b/openspec/changes/foundation-auth/specs/auth/spec.md new file mode 100644 index 0000000..e46ceea --- /dev/null +++ b/openspec/changes/foundation-auth/specs/auth/spec.md @@ -0,0 +1,32 @@ +# Spec delta: auth + +## ADDED Requirements + +### Requirement: Customer registration +The API SHALL provide `POST /api/auth/register` accepting email, password, display_name. New users are created with role `customer`. Duplicate emails MUST be rejected with 409. + +#### Scenario: successful registration +- **WHEN** a client posts a unique email with password ≥ 8 chars +- **THEN** the API returns 201 with `{ token, user }` and the user can call `/api/auth/me` with the token + +#### Scenario: duplicate email +- **WHEN** the email already exists +- **THEN** the API returns 409 with code `CONFLICT` + +### Requirement: Login +The API SHALL provide `POST /api/auth/login` issuing a signed JWT (24h TTL) containing user id and role. + +#### Scenario: valid credentials +- **WHEN** email + correct password are posted +- **THEN** the API returns `{ token, user }` + +#### Scenario: invalid credentials +- **WHEN** the password is wrong or email unknown +- **THEN** the API returns 401 with code `UNAUTHORIZED` and no token + +### Requirement: Current user +`GET /api/auth/me` SHALL return the authenticated user profile. + +#### Scenario: missing token +- **WHEN** no Bearer token is supplied +- **THEN** the API returns 401 diff --git a/openspec/changes/foundation-auth/specs/rbac/spec.md b/openspec/changes/foundation-auth/specs/rbac/spec.md new file mode 100644 index 0000000..9a11106 --- /dev/null +++ b/openspec/changes/foundation-auth/specs/rbac/spec.md @@ -0,0 +1,21 @@ +# Spec delta: rbac + +## ADDED Requirements + +### Requirement: Role model +The system SHALL support roles `platform_admin`, `shop_owner`, `shop_staff`, `customer`. Shop roles MUST carry a `shop_id` scope. + +#### Scenario: seeded platform admin +- **WHEN** migrations run on a fresh database +- **THEN** a `platform_admin` account exists and can log in + +### Requirement: Role enforcement +Protected routes SHALL declare required roles; the API MUST reject requests with insufficient role using 403. + +#### Scenario: customer hits admin route +- **WHEN** a `customer` token calls an `/api/admin/*` route +- **THEN** the API returns 403 with code `FORBIDDEN` + +#### Scenario: shop scope isolation +- **WHEN** a `shop_owner` of shop A accesses `/api/shop/*` resources of shop B +- **THEN** the API returns 403 or 404, never the data diff --git a/openspec/changes/foundation-auth/tasks.md b/openspec/changes/foundation-auth/tasks.md new file mode 100644 index 0000000..9af7fef --- /dev/null +++ b/openspec/changes/foundation-auth/tasks.md @@ -0,0 +1,20 @@ +# Tasks: foundation-auth + +## 1. Backend skeleton +- [x] Cargo workspace, vmall-api crate (axum, sqlx, redis, tower-http) +- [x] Config from env (DATABASE_URL, REDIS_URL, JWT_SECRET, PORT) +- [x] Health + readiness endpoints (db/redis checked) +- [x] sqlx migrate on boot; 0001_init migration + +## 2. Identity schema +- [ ] Migration: users, shops tables; role enum +- [ ] Seed platform admin (admin@vmall.local / admin1234) + +## 3. Auth API +- [ ] POST /api/auth/register (customer role) +- [ ] POST /api/auth/login → JWT + user +- [ ] GET /api/auth/me (Bearer) +- [ ] Auth extractor + require_role guard + +## 4. Tests +- [ ] cargo test: register/login/me happy path, wrong password, role guard denies customer on admin route diff --git a/openspec/changes/frontend-apps/proposal.md b/openspec/changes/frontend-apps/proposal.md new file mode 100644 index 0000000..6c377c6 --- /dev/null +++ b/openspec/changes/frontend-apps/proposal.md @@ -0,0 +1,18 @@ +# Proposal: frontend-apps + +## Why +The API needs its three user-facing surfaces: customer storefront (mall), merchant console (shop-admin), and platform console (admin) — all Nuxt 3, all bilingual (en/zh), with the mall offering multi-currency display. + +## What changes +- Shared package @vmall/shared: API contract types, typed API client, en/zh locales, base stylesheet. +- mall (port 3000): product browsing w/ search+category, product detail, cart, checkout, orders, shipments, invoices, login/register, currency switcher (display conversion). +- shop-admin (3001): dashboard, product CRUD + publish/unpublish + SKU editing, order list, shipment creation/ship, invoice issue. +- admin (3002): user role assignment, shop creation/suspension, order oversight, currency management (rates). + +## Non-goals +- SSR SEO tuning, design-system polish beyond the shared stylesheet, e2e test suites (smoke-verified in browser). + +## Capabilities +- `frontend-mall`: shopper experience. +- `frontend-shop-admin`: merchant experience. +- `frontend-admin`: platform operator experience. diff --git a/openspec/changes/frontend-apps/specs/frontend-admin/spec.md b/openspec/changes/frontend-apps/specs/frontend-admin/spec.md new file mode 100644 index 0000000..c2cca3e --- /dev/null +++ b/openspec/changes/frontend-apps/specs/frontend-admin/spec.md @@ -0,0 +1,17 @@ +# Spec delta: frontend-admin + +## ADDED Requirements + +### Requirement: Platform user and shop management +Platform admins SHALL assign user roles (with shop scope), create shops, and suspend/activate shops. Suspended shops' products MUST NOT be purchasable (enforced by API, reflected in UI). + +#### Scenario: assign shop owner +- **WHEN** an admin assigns role shop_owner with a shop to a user +- **THEN** that user can log into shop-admin and manage that shop + +### Requirement: Currency management +Platform admins SHALL view currencies and update exchange rates; new rates affect subsequent conversions. + +#### Scenario: rate update +- **WHEN** an admin updates CNY rate_to_base +- **THEN** the mall conversion endpoint returns amounts computed with the new rate diff --git a/openspec/changes/frontend-apps/specs/frontend-mall/spec.md b/openspec/changes/frontend-apps/specs/frontend-mall/spec.md new file mode 100644 index 0000000..2496e86 --- /dev/null +++ b/openspec/changes/frontend-apps/specs/frontend-mall/spec.md @@ -0,0 +1,24 @@ +# Spec delta: frontend-mall + +## ADDED Requirements + +### Requirement: Localized storefront +The mall SHALL render UI strings and catalog content in en or zh from one switcher, defaulting to en. + +#### Scenario: switch to Chinese +- **WHEN** a shopper switches locale to zh +- **THEN** navigation, buttons and product names render in Chinese without reload errors + +### Requirement: Multi-currency display +The mall SHALL offer a currency switcher (enabled currencies from the API) converting SKU prices for display; checkout uses the selected currency. + +#### Scenario: switch currency +- **WHEN** a shopper switches from USD to JPY on a product priced $10.00 +- **THEN** the displayed price reflects the API conversion rate (integer minor units) + +### Requirement: Shopping flow +A shopper SHALL be able to browse, view detail, add to cart, checkout with a shipping address, pay (mock), track shipments, confirm delivery, and request an invoice — all against the live API. + +#### Scenario: end-to-end purchase +- **WHEN** a registered shopper completes checkout on a non-empty cart +- **THEN** orders appear under Orders and the cart is empty diff --git a/openspec/changes/frontend-apps/specs/frontend-shop-admin/spec.md b/openspec/changes/frontend-apps/specs/frontend-shop-admin/spec.md new file mode 100644 index 0000000..74b64c8 --- /dev/null +++ b/openspec/changes/frontend-apps/specs/frontend-shop-admin/spec.md @@ -0,0 +1,17 @@ +# Spec delta: frontend-shop-admin + +## ADDED Requirements + +### Requirement: Merchant product management +Shop users SHALL manage only their own shop's products: create/edit bilingual content, manage SKUs, publish/unpublish with immediate effect on the storefront. + +#### Scenario: publish visible in mall +- **WHEN** a merchant publishes a product in shop-admin +- **THEN** it appears in the mall product list for the matching locale + +### Requirement: Merchant fulfillment +Shop users SHALL see incoming orders, create shipments, mark them shipped, and issue requested invoices. + +#### Scenario: ship an order +- **WHEN** a merchant creates a shipment for a paid order and marks it shipped +- **THEN** the shopper sees the shipment with tracking info diff --git a/openspec/changes/frontend-apps/tasks.md b/openspec/changes/frontend-apps/tasks.md new file mode 100644 index 0000000..1ed2d55 --- /dev/null +++ b/openspec/changes/frontend-apps/tasks.md @@ -0,0 +1,22 @@ +# Tasks: frontend-apps + +## 1. Shared package +- [x] @vmall/shared: types, API client, locales (en/zh), ui.css + +## 2. Scaffolds +- [x] Three Nuxt apps: config, i18n, pinia session store, api plugin, layouts + +## 3. mall +- [ ] Home: product grid + search + category filter + paging +- [ ] Product detail with SKU picker, localized content, converted price +- [ ] Cart page, checkout page (address form), orders list/detail, shipments, invoices, login/register + +## 4. shop-admin +- [ ] Login guard, dashboard, products list/new/edit (i18n fields, SKUs), publish/unpublish +- [ ] Orders, shipment creation + mark shipped, invoices list + issue + +## 5. admin +- [ ] Login guard, users (role assignment), shops (create/suspend), orders, currencies (rate edit) + +## 6. Verification +- [ ] All three apps build; browser smoke: register→shop create→product publish→purchase→ship→invoice in en + zh diff --git a/openspec/changes/fulfillment-invoices/proposal.md b/openspec/changes/fulfillment-invoices/proposal.md new file mode 100644 index 0000000..290cc16 --- /dev/null +++ b/openspec/changes/fulfillment-invoices/proposal.md @@ -0,0 +1,17 @@ +# Proposal: fulfillment-invoices + +## Why +After payment, merchants ship goods (发货单) and customers request invoices (发票). This phase closes the post-order loop of the MVP. + +## What changes +- Schema: shipments (carrier, tracking, status, per-item qty), invoices (title, tax_no, kind, amount, status). +- Shipment lifecycle: created(pending) → shipped → delivered; order becomes fulfilling on first shipment, shipped when all items shipped, completed when all delivered (customer confirm allowed). +- Merchant APIs: create shipment for paid/fulfilling orders, mark shipped, list shipments/invoices, issue invoice. +- Customer APIs: my shipments, confirm delivery, request invoice per order, my invoices. + +## Non-goals +- Carrier API integrations, e-invoice/PDF generation, partial invoice amounts. + +## Capabilities +- `shipment`: 发货单 lifecycle. +- `invoice`: 发票 request/issue lifecycle. diff --git a/openspec/changes/fulfillment-invoices/specs/invoice/spec.md b/openspec/changes/fulfillment-invoices/specs/invoice/spec.md new file mode 100644 index 0000000..59373bb --- /dev/null +++ b/openspec/changes/fulfillment-invoices/specs/invoice/spec.md @@ -0,0 +1,21 @@ +# Spec delta: invoice + +## ADDED Requirements + +### Requirement: Invoice request +Customers SHALL request at most one open invoice (发票) per order, with title, kind (`personal | company`), and tax_no required for company invoices. Amount equals the order total in the order currency. + +#### Scenario: company invoice requires tax number +- **WHEN** requesting a company invoice without tax_no +- **THEN** the API returns 400 + +#### Scenario: duplicate rejected +- **WHEN** an order already has a requested or issued invoice +- **THEN** a second request returns 409 + +### Requirement: Invoice issuance +Merchants SHALL issue requested invoices of their own shop's orders; issuing sets invoice_no, issued_at and status `issued`. + +#### Scenario: issue flow +- **WHEN** the shop issues a requested invoice +- **THEN** the customer sees status `issued` with an invoice number diff --git a/openspec/changes/fulfillment-invoices/specs/shipment/spec.md b/openspec/changes/fulfillment-invoices/specs/shipment/spec.md new file mode 100644 index 0000000..2ddfb71 --- /dev/null +++ b/openspec/changes/fulfillment-invoices/specs/shipment/spec.md @@ -0,0 +1,23 @@ +# Spec delta: shipment + +## ADDED Requirements + +### Requirement: Shipment creation +Merchants SHALL create shipments (发货单) for their own orders in `paid` or `fulfilling` status, specifying carrier, tracking_no and per-item quantities. + +#### Scenario: partial shipment +- **WHEN** an order has 3 units of item X and a shipment covers 2 +- **THEN** a later shipment may cover the remaining 1; requesting more than the remainder returns 400 + +#### Scenario: status propagation +- **WHEN** the first shipment is created for a paid order +- **THEN** the order becomes `fulfilling` +- **WHEN** all ordered quantities are covered by shipped shipments +- **THEN** the order becomes `shipped` + +### Requirement: Delivery confirmation +Customers SHALL confirm delivery of their own shipments; when every shipment of an order is delivered the order becomes `completed`. + +#### Scenario: confirm delivered +- **WHEN** the customer confirms the only shipment of a shipped order +- **THEN** shipment becomes `delivered` and the order `completed` diff --git a/openspec/changes/fulfillment-invoices/tasks.md b/openspec/changes/fulfillment-invoices/tasks.md new file mode 100644 index 0000000..076015c --- /dev/null +++ b/openspec/changes/fulfillment-invoices/tasks.md @@ -0,0 +1,17 @@ +# Tasks: fulfillment-invoices + +## 1. Schema +- [ ] Migration: shipments, shipment_items, invoices; status enums; shipment_no/invoice_no sequences + +## 2. Shipments +- [ ] POST /api/shop/orders/{id}/shipments (qty validation vs unshipped remainder) +- [ ] POST /api/shop/shipments/{id}/ship; order status propagation (fulfilling/shipped) +- [ ] GET /api/shipments (customer), POST /api/shipments/{id}/confirm-delivered → order completed when done +- [ ] GET /api/shop/shipments + +## 3. Invoices +- [ ] POST /api/orders/{id}/invoice (one open invoice per order; amount = order total) +- [ ] GET /api/invoices (customer), GET /api/shop/invoices, POST /api/shop/invoices/{id}/issue + +## 4. Tests +- [ ] cargo test: partial shipment qty math, order status propagation, duplicate invoice rejected, issue flow diff --git a/openspec/config.yaml b/openspec/config.yaml new file mode 100644 index 0000000..2352cdd --- /dev/null +++ b/openspec/config.yaml @@ -0,0 +1,22 @@ +schema: spec-driven + +context: | + VMall: B2B2C e-commerce MVP, spec-driven in phases. + + Tech stack: + - Backend: Rust (axum 0.8, sqlx 0.8 + Postgres 18, redis 8, JWT, argon2) at apps/api, crate vmall-api. Money is stored as integer minor units + ISO currency code; never floats. + - Frontends: three Nuxt 3 apps in pnpm workspace: apps/mall (customer storefront, port 3000), apps/shop-admin (merchant console, 3001), apps/admin (platform console, 3002). + - Shared contract: packages/shared (@vmall/shared) — TS types, API client, en/zh locales, ui.css. Frontends must use it; no per-app API reimplementation. + - Dev infra: Postgres + Redis run in local docker (containers pg18, rdb8); databases vmall / vmall_test; API runs migrations on boot (sqlx migrate). + + Conventions: + - i18n: product/shop/category content stored as JSONB {"en": "...", "zh": "..."}; UI strings in @vmall/shared locales. + - Multi-currency: currencies table with rate_to_base; prices stored in the SKU's own currency; display conversion via /api/currencies/convert. + - RBAC roles: platform_admin, shop_owner, shop_staff, customer. + - API errors: {"error": {"code", "message"}} with proper HTTP status. + +rules: + proposal: + - Keep proposals under 300 words with a Non-goals section + tasks: + - Group tasks by milestone with verifiable checkboxes diff --git a/package.json b/package.json new file mode 100644 index 0000000..8fe34dc --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "vmall", + "private": true, + "type": "module", + "scripts": { + "dev:mall": "pnpm --filter @vmall/mall dev", + "dev:shop-admin": "pnpm --filter @vmall/shop-admin dev", + "dev:admin": "pnpm --filter @vmall/admin dev", + "dev:api": "cargo run -p vmall-api", + "build": "pnpm -r build" + }, + "devDependencies": {} +} diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..0ae5698 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,12 @@ +{ + "name": "@vmall/shared", + "version": "0.1.0", + "private": true, + "type": "module", + "exports": { + ".": "./src/index.ts", + "./locales": "./src/locales/index.ts", + "./types": "./src/types.ts", + "./ui.css": "./src/ui.css" + } +} diff --git a/packages/shared/src/api.ts b/packages/shared/src/api.ts new file mode 100644 index 0000000..d16fda3 --- /dev/null +++ b/packages/shared/src/api.ts @@ -0,0 +1,253 @@ +import type { + Address, + AuthTokens, + Cart, + Category, + Currency, + Invoice, + InvoiceKind, + LocalizedText, + Order, + OrderStatus, + Paged, + Product, + ProductStatus, + Shipment, + Shop, + Sku, + User, +} from "./types"; + +export interface ApiClientOptions { + baseUrl: string; + getToken?: () => string | null; +} + +export class ApiError extends Error { + code: string; + status: number; + constructor(status: number, code: string, message: string) { + super(message); + this.status = status; + this.code = code; + } +} + +// ---- request bodies ---- + +export interface ProductListQuery { + page?: number; + per_page?: number; + category_id?: string; + q?: string; + shop_id?: string; +} + +export interface ProductUpsertBody { + category_id?: string | null; + slug: string; + name: LocalizedText; + description?: LocalizedText; + images?: string[]; +} + +export interface SkuUpsertBody { + sku_code: string; + attributes?: Record; + price_minor: number; + currency: string; + stock: number; + active?: boolean; +} + +export interface ShipmentItemBody { + order_item_id: string; + qty: number; +} + +export interface CurrencyUpsertBody { + code: string; + name: LocalizedText; + symbol: string; + exponent: number; + rate_to_base: string; + enabled: boolean; +} + +export interface ShopProductQuery { + page?: number; + status?: ProductStatus; +} + +export interface ShopOrderQuery { + page?: number; + status?: OrderStatus; +} + +export interface ConvertResult { + amount_minor: number; + currency: string; +} + +type Query = Record; + +async function request( + opts: ApiClientOptions, + method: string, + path: string, + body?: unknown, + query?: Query, +): Promise { + const url = new URL(opts.baseUrl + path); + if (query) { + for (const [k, v] of Object.entries(query)) { + if (v !== undefined && v !== null && v !== "") url.searchParams.set(k, String(v)); + } + } + const headers: Record = { "content-type": "application/json" }; + const token = opts.getToken?.(); + if (token) headers.authorization = `Bearer ${token}`; + const res = await fetch(url.toString(), { + method, + headers, + body: body === undefined ? undefined : JSON.stringify(body), + }); + if (!res.ok) { + let code = "UNKNOWN"; + let message = res.statusText; + try { + const data = (await res.json()) as { error?: { code?: string; message?: string } }; + code = data?.error?.code ?? code; + message = data?.error?.message ?? message; + } catch { + /* non-JSON error body */ + } + throw new ApiError(res.status, code, message); + } + if (res.status === 204) return undefined as T; + return (await res.json()) as T; +} + +export interface ApiClient { + register(email: string, password: string, displayName: string): Promise; + login(email: string, password: string): Promise; + me(): Promise; + listProducts(q?: ProductListQuery): Promise>; + getProduct(idOrSlug: string): Promise; + listCategories(): Promise; + listCurrencies(): Promise; + convert(amountMinor: number, from: string, to: string): Promise; + getCart(): Promise; + addCartItem(skuId: string, qty: number): Promise; + updateCartItem(skuId: string, qty: number): Promise; + removeCartItem(skuId: string): Promise; + checkout(shippingAddress: Address, currency: string): Promise; + listMyOrders(page?: number): Promise>; + getOrder(id: string): Promise; + cancelOrder(id: string): Promise; + confirmDelivered(shipmentId: string): Promise; + listMyShipments(): Promise; + requestInvoice( + orderId: string, + title: string, + taxNo: string | null, + kind: InvoiceKind, + ): Promise; + listMyInvoices(): Promise; + shop: { + getMyShop(): Promise; + listMyProducts(q?: ShopProductQuery): Promise>; + createProduct(body: ProductUpsertBody): Promise; + updateProduct(id: string, body: ProductUpsertBody): Promise; + publish(id: string): Promise; + unpublish(id: string): Promise; + upsertSku(productId: string, body: SkuUpsertBody): Promise; + listOrders(q?: ShopOrderQuery): Promise>; + createShipment( + orderId: string, + carrier: string, + trackingNo: string, + items: ShipmentItemBody[], + ): Promise; + listShipments(): Promise; + markShipped(id: string): Promise; + listInvoices(): Promise; + issueInvoice(id: string): Promise; + }; + admin: { + listUsers(page?: number): Promise>; + setUserRole(id: string, role: string, shopId: string | null): Promise; + listShops(): Promise; + createShop(name: LocalizedText, slug: string): Promise; + setShopStatus(id: string, status: "active" | "suspended"): Promise; + listOrders(page?: number): Promise>; + listCurrencies(): Promise; + upsertCurrency(body: CurrencyUpsertBody): Promise; + setRate(code: string, rateToBase: string): Promise; + }; +} + +export function createApi(opts: ApiClientOptions): ApiClient { + const r = (m: string, p: string, b?: unknown, q?: Query): Promise => + request(opts, m, p, b, q); + return { + register: (email, password, displayName) => + r("POST", "/auth/register", { email, password, display_name: displayName }), + login: (email, password) => r("POST", "/auth/login", { email, password }), + me: () => r("GET", "/auth/me"), + listProducts: (q = {}) => r("GET", "/products", undefined, { ...q }), + getProduct: (idOrSlug) => r("GET", `/products/${idOrSlug}`), + listCategories: () => r("GET", "/categories"), + listCurrencies: () => r("GET", "/currencies"), + convert: (amountMinor, from, to) => + r("GET", "/currencies/convert", undefined, { amount_minor: amountMinor, from, to }), + getCart: () => r("GET", "/cart"), + addCartItem: (skuId, qty) => r("POST", "/cart/items", { sku_id: skuId, qty }), + updateCartItem: (skuId, qty) => r("PUT", `/cart/items/${skuId}`, { qty }), + removeCartItem: (skuId) => r("DELETE", `/cart/items/${skuId}`), + checkout: (shippingAddress, currency) => + r("POST", "/orders/checkout", { shipping_address: shippingAddress, currency }), + listMyOrders: (page = 1) => r("GET", "/orders", undefined, { page }), + getOrder: (id) => r("GET", `/orders/${id}`), + cancelOrder: (id) => r("POST", `/orders/${id}/cancel`), + confirmDelivered: (shipmentId) => r("POST", `/shipments/${shipmentId}/confirm-delivered`), + listMyShipments: () => r("GET", "/shipments"), + requestInvoice: (orderId, title, taxNo, kind) => + r("POST", `/orders/${orderId}/invoice`, { title, tax_no: taxNo, kind }), + listMyInvoices: () => r("GET", "/invoices"), + shop: { + getMyShop: () => r("GET", "/shop/profile"), + listMyProducts: (q = {}) => r("GET", "/shop/products", undefined, { ...q }), + createProduct: (body) => r("POST", "/shop/products", body), + updateProduct: (id, body) => r("PUT", `/shop/products/${id}`, body), + publish: (id) => r("POST", `/shop/products/${id}/publish`), + unpublish: (id) => r("POST", `/shop/products/${id}/unpublish`), + upsertSku: (productId, body) => r("POST", `/shop/products/${productId}/skus`, body), + listOrders: (q = {}) => r("GET", "/shop/orders", undefined, { ...q }), + createShipment: (orderId, carrier, trackingNo, items) => + r("POST", `/shop/orders/${orderId}/shipments`, { + carrier, + tracking_no: trackingNo, + items, + }), + listShipments: () => r("GET", "/shop/shipments"), + markShipped: (id) => r("POST", `/shop/shipments/${id}/ship`), + listInvoices: () => r("GET", "/shop/invoices"), + issueInvoice: (id) => r("POST", `/shop/invoices/${id}/issue`), + }, + admin: { + listUsers: (page = 1) => r("GET", "/admin/users", undefined, { page }), + setUserRole: (id, role, shopId) => + r("PUT", `/admin/users/${id}/role`, { role, shop_id: shopId }), + listShops: () => r("GET", "/admin/shops"), + createShop: (name, slug) => r("POST", "/admin/shops", { name, slug }), + setShopStatus: (id, status) => r("PUT", `/admin/shops/${id}/status`, { status }), + listOrders: (page = 1) => r("GET", "/admin/orders", undefined, { page }), + listCurrencies: () => r("GET", "/admin/currencies"), + upsertCurrency: (body) => r("POST", "/admin/currencies", body), + setRate: (code, rateToBase) => r("PUT", `/admin/currencies/${code}/rate`, { + rate_to_base: rateToBase, + }), + }, + }; +} diff --git a/packages/shared/src/format.ts b/packages/shared/src/format.ts new file mode 100644 index 0000000..01a9f9d --- /dev/null +++ b/packages/shared/src/format.ts @@ -0,0 +1,21 @@ +import type { Currency, LocalizedText } from "./types"; + +/** Pick the best translation for a locale, falling back to en then any value. */ +export function t(text: LocalizedText | null | undefined, locale: string): string { + if (!text) return ""; + return text[locale] ?? text.en ?? Object.values(text)[0] ?? ""; +} + +/** Format minor-unit amount using the currency's exponent. */ +export function formatMoney( + amountMinor: number, + currency: string, + exponent = 2, + locale = "en", +): string { + const value = amountMinor / 10 ** exponent; + return new Intl.NumberFormat(locale === "zh" ? "zh-CN" : "en-US", { + style: "currency", + currency, + }).format(value); +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 0000000..7b83148 --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,3 @@ +export * from "./types"; +export * from "./api"; +export * from "./format"; diff --git a/packages/shared/src/locales/en.ts b/packages/shared/src/locales/en.ts new file mode 100644 index 0000000..fb492e7 --- /dev/null +++ b/packages/shared/src/locales/en.ts @@ -0,0 +1,168 @@ +export default { + common: { + appName: "VMall", + login: "Sign in", + logout: "Sign out", + register: "Create account", + email: "Email", + password: "Password", + displayName: "Display name", + submit: "Submit", + cancel: "Cancel", + save: "Save", + delete: "Delete", + edit: "Edit", + create: "Create", + search: "Search", + loading: "Loading…", + empty: "Nothing here yet", + back: "Back", + actions: "Actions", + status: "Status", + total: "Total", + qty: "Qty", + price: "Price", + yes: "Yes", + no: "No", + all: "All", + language: "Language", + currency: "Currency", + page: "Page", + prev: "Prev", + next: "Next", + error: "Something went wrong", + required: "Required", + }, + nav: { + home: "Home", + products: "Products", + categories: "Categories", + cart: "Cart", + orders: "Orders", + invoices: "Invoices", + shipments: "Shipments", + account: "Account", + dashboard: "Dashboard", + users: "Users", + shops: "Shops", + currencies: "Currencies", + settings: "Settings", + }, + auth: { + welcome: "Welcome back", + createAccount: "Create your account", + haveAccount: "Already have an account?", + noAccount: "No account yet?", + badCredentials: "Invalid email or password", + }, + product: { + addToCart: "Add to cart", + buyNow: "Buy now", + stock: "Stock", + publish: "Publish", + unpublish: "Unpublish", + draft: "Draft", + published: "Published", + unpublished: "Unpublished", + newProduct: "New product", + editProduct: "Edit product", + nameEn: "Name (English)", + nameZh: "Name (中文)", + descEn: "Description (English)", + descZh: "Description (中文)", + slug: "Slug", + category: "Category", + images: "Image URLs (one per line)", + skus: "SKUs", + addSku: "Add SKU", + skuCode: "SKU code", + detail: "Product detail", + shop: "Shop", + }, + cart: { + title: "Shopping cart", + checkout: "Checkout", + emptyCart: "Your cart is empty", + remove: "Remove", + subtotal: "Subtotal", + }, + order: { + title: "Orders", + orderNo: "Order no.", + placeOrder: "Place order", + shippingAddress: "Shipping address", + recipient: "Recipient", + phone: "Phone", + country: "Country", + region: "State / Province", + city: "City", + line1: "Street address", + postalCode: "Postal code", + pay: "Pay", + cancelOrder: "Cancel order", + confirmDelivery: "Confirm delivery", + requestInvoice: "Request invoice", + status: { + pending_payment: "Pending payment", + paid: "Paid", + fulfilling: "Fulfilling", + shipped: "Shipped", + completed: "Completed", + cancelled: "Cancelled", + }, + }, + shipment: { + title: "Shipments", + shipmentNo: "Shipment no.", + carrier: "Carrier", + trackingNo: "Tracking no.", + create: "Create shipment", + markShipped: "Mark shipped", + status: { + pending: "Pending", + shipped: "Shipped", + delivered: "Delivered", + }, + }, + invoice: { + title: "Invoices", + invoiceNo: "Invoice no.", + invoiceTitle: "Invoice title", + taxNo: "Tax number", + kind: "Type", + personal: "Personal", + company: "Company", + issue: "Issue invoice", + amount: "Amount", + status: { + requested: "Requested", + issued: "Issued", + cancelled: "Cancelled", + }, + }, + admin: { + role: "Role", + roles: { + platform_admin: "Platform admin", + shop_owner: "Shop owner", + shop_staff: "Shop staff", + customer: "Customer", + }, + assignShop: "Assigned shop", + createShop: "Create shop", + shopSlug: "Shop slug", + shopNameEn: "Shop name (English)", + shopNameZh: "Shop name (中文)", + suspend: "Suspend", + activate: "Activate", + active: "Active", + suspended: "Suspended", + rate: "Rate to base", + symbol: "Symbol", + exponent: "Minor units", + baseCurrency: "Base", + enabled: "Enabled", + saveCurrency: "Save currency", + updateRate: "Update rate", + }, +} as const; diff --git a/packages/shared/src/locales/index.ts b/packages/shared/src/locales/index.ts new file mode 100644 index 0000000..6b3eb46 --- /dev/null +++ b/packages/shared/src/locales/index.ts @@ -0,0 +1,2 @@ +export { default as en } from "./en"; +export { default as zh } from "./zh"; diff --git a/packages/shared/src/locales/zh.ts b/packages/shared/src/locales/zh.ts new file mode 100644 index 0000000..d1bce02 --- /dev/null +++ b/packages/shared/src/locales/zh.ts @@ -0,0 +1,168 @@ +export default { + common: { + appName: "VMall 云商城", + login: "登录", + logout: "退出登录", + register: "注册", + email: "邮箱", + password: "密码", + displayName: "昵称", + submit: "提交", + cancel: "取消", + save: "保存", + delete: "删除", + edit: "编辑", + create: "新建", + search: "搜索", + loading: "加载中…", + empty: "暂无数据", + back: "返回", + actions: "操作", + status: "状态", + total: "合计", + qty: "数量", + price: "价格", + yes: "是", + no: "否", + all: "全部", + language: "语言", + currency: "币种", + page: "页", + prev: "上一页", + next: "下一页", + error: "出错了", + required: "必填", + }, + nav: { + home: "首页", + products: "商品", + categories: "分类", + cart: "购物车", + orders: "订单", + invoices: "发票", + shipments: "发货单", + account: "我的", + dashboard: "仪表盘", + users: "用户", + shops: "店铺", + currencies: "币种", + settings: "设置", + }, + auth: { + welcome: "欢迎回来", + createAccount: "创建账号", + haveAccount: "已有账号?", + noAccount: "还没有账号?", + badCredentials: "邮箱或密码错误", + }, + product: { + addToCart: "加入购物车", + buyNow: "立即购买", + stock: "库存", + publish: "上架", + unpublish: "下架", + draft: "草稿", + published: "已上架", + unpublished: "已下架", + newProduct: "新建商品", + editProduct: "编辑商品", + nameEn: "名称(英文)", + nameZh: "名称(中文)", + descEn: "描述(英文)", + descZh: "描述(中文)", + slug: "别名", + category: "分类", + images: "图片链接(每行一个)", + skus: "SKU", + addSku: "添加 SKU", + skuCode: "SKU 编码", + detail: "商品详情", + shop: "店铺", + }, + cart: { + title: "购物车", + checkout: "去结算", + emptyCart: "购物车是空的", + remove: "移除", + subtotal: "小计", + }, + order: { + title: "订单", + orderNo: "订单号", + placeOrder: "提交订单", + shippingAddress: "收货地址", + recipient: "收货人", + phone: "电话", + country: "国家", + region: "省/州", + city: "城市", + line1: "详细地址", + postalCode: "邮编", + pay: "支付", + cancelOrder: "取消订单", + confirmDelivery: "确认收货", + requestInvoice: "申请发票", + status: { + pending_payment: "待支付", + paid: "已支付", + fulfilling: "履约中", + shipped: "已发货", + completed: "已完成", + cancelled: "已取消", + }, + }, + shipment: { + title: "发货单", + shipmentNo: "发货单号", + carrier: "承运商", + trackingNo: "物流单号", + create: "创建发货单", + markShipped: "标记发货", + status: { + pending: "待发货", + shipped: "已发货", + delivered: "已送达", + }, + }, + invoice: { + title: "发票", + invoiceNo: "发票号", + invoiceTitle: "抬头", + taxNo: "税号", + kind: "类型", + personal: "个人", + company: "企业", + issue: "开具发票", + amount: "金额", + status: { + requested: "已申请", + issued: "已开具", + cancelled: "已作废", + }, + }, + admin: { + role: "角色", + roles: { + platform_admin: "平台管理员", + shop_owner: "店主", + shop_staff: "店员", + customer: "顾客", + }, + assignShop: "所属店铺", + createShop: "创建店铺", + shopSlug: "店铺别名", + shopNameEn: "店铺名(英文)", + shopNameZh: "店铺名(中文)", + suspend: "停用", + activate: "启用", + active: "启用中", + suspended: "已停用", + rate: "对基准汇率", + symbol: "符号", + exponent: "小数位", + baseCurrency: "基准", + enabled: "启用", + saveCurrency: "保存币种", + updateRate: "更新汇率", + }, +} as const; diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts new file mode 100644 index 0000000..fa7e182 --- /dev/null +++ b/packages/shared/src/types.ts @@ -0,0 +1,198 @@ +// API contract types shared by all three frontends. + +export type LocaleCode = "en" | "zh"; + +export interface Money { + amount_minor: number; + currency: string; +} + +export interface LocalizedText { + [locale: string]: string; +} + +export type UserRole = "platform_admin" | "shop_owner" | "shop_staff" | "customer"; + +export interface User { + id: string; + email: string; + display_name: string; + role: UserRole; + shop_id: string | null; + locale: string; + created_at: string; +} + +export interface AuthTokens { + token: string; + user: User; +} + +export interface Shop { + id: string; + name: LocalizedText; + slug: string; + status: "active" | "suspended"; + created_at: string; +} + +export interface Category { + id: string; + parent_id: string | null; + name: LocalizedText; + slug: string; + position: number; +} + +export type ProductStatus = "draft" | "published" | "unpublished"; + +export interface Product { + id: string; + shop_id: string; + category_id: string | null; + slug: string; + name: LocalizedText; + description: LocalizedText; + images: string[]; + status: ProductStatus; + created_at: string; + skus?: Sku[]; +} + +export interface Sku { + id: string; + product_id: string; + sku_code: string; + attributes: Record; + price_minor: number; + currency: string; + stock: number; + active: boolean; +} + +export interface Currency { + code: string; + name: LocalizedText; + symbol: string; + exponent: number; + is_base: boolean; + rate_to_base: string; + enabled: boolean; +} + +export interface CartItem { + sku_id: string; + product_id: string; + product_name: LocalizedText; + sku_code: string; + image: string | null; + unit_price_minor: number; + currency: string; + qty: number; +} + +export interface Cart { + items: CartItem[]; +} + +export type OrderStatus = + | "pending_payment" + | "paid" + | "fulfilling" + | "shipped" + | "completed" + | "cancelled"; + +export interface OrderItem { + id: string; + sku_id: string; + product_name: LocalizedText; + sku_code: string; + unit_price_minor: number; + qty: number; + image: string | null; +} + +export interface Order { + id: string; + order_no: string; + shop_id: string; + user_id: string; + status: OrderStatus; + currency: string; + total_minor: number; + items: OrderItem[]; + shipping_address: Address; + created_at: string; +} + +export type InvoiceKind = "personal" | "company"; + +export interface Invoice { + id: string; + invoice_no: string; + order_id: string; + order_no?: string; + title: string; + tax_no: string | null; + kind: InvoiceKind; + amount_minor: number; + currency: string; + status: InvoiceStatus; + issued_at: string | null; + created_at: string; +} + +export interface Address { + recipient: string; + phone: string; + country: string; + region: string; + city: string; + line1: string; + postal_code: string; +} + +export type ShipmentStatus = "pending" | "shipped" | "delivered"; + +export interface Shipment { + id: string; + shipment_no: string; + order_id: string; + order_no?: string; + carrier: string; + tracking_no: string; + status: ShipmentStatus; + items: { order_item_id: string; qty: number }[]; + shipped_at: string | null; + delivered_at: string | null; + created_at: string; +} + +export type InvoiceStatus = "requested" | "issued" | "cancelled"; + +export interface Invoice { + id: string; + invoice_no: string; + order_id: string; + order_no?: string; + title: string; + tax_no: string | null; + kind: "personal" | "company"; + amount_minor: number; + currency: string; + status: InvoiceStatus; + issued_at: string | null; + created_at: string; +} + +export interface Paged { + items: T[]; + total: number; + page: number; + per_page: number; +} + +export interface ApiErrorBody { + error: { code: string; message: string }; +} diff --git a/packages/shared/src/ui.css b/packages/shared/src/ui.css new file mode 100644 index 0000000..8852080 --- /dev/null +++ b/packages/shared/src/ui.css @@ -0,0 +1,159 @@ +:root { + --bg: #f6f7f9; + --surface: #ffffff; + --border: #e2e5ea; + --text: #1c2330; + --muted: #66707f; + --primary: #2f6fed; + --primary-dark: #2058c8; + --danger: #d64545; + --success: #1f9d63; + --warning: #c77d0a; + --radius: 8px; + --shadow: 0 1px 3px rgba(16, 24, 40, 0.08); +} + +* { box-sizing: border-box; } + +body { + margin: 0; + font-family: "Inter", -apple-system, "PingFang SC", "Microsoft YaHei", "Segoe UI", sans-serif; + background: var(--bg); + color: var(--text); + font-size: 14px; + line-height: 1.55; +} + +a { color: var(--primary); text-decoration: none; } +a:hover { text-decoration: underline; } + +.container { max-width: 1120px; margin: 0 auto; padding: 0 16px; } + +.topnav { + background: var(--surface); + border-bottom: 1px solid var(--border); + position: sticky; + top: 0; + z-index: 10; +} +.topnav-inner { + display: flex; + align-items: center; + gap: 20px; + height: 56px; +} +.topnav .brand { font-weight: 700; font-size: 17px; color: var(--text); } +.topnav nav { display: flex; gap: 14px; flex: 1; } +.topnav nav a { color: var(--muted); font-weight: 500; } +.topnav nav a.router-link-active { color: var(--primary); } +.topnav .spacer { flex: 1; } + +select, input, textarea { + font: inherit; + padding: 8px 10px; + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--surface); + color: var(--text); + width: 100%; +} +select { width: auto; } +input:focus, textarea:focus, select:focus { outline: 2px solid rgba(47, 111, 237, 0.3); border-color: var(--primary); } +label { display: block; font-weight: 500; margin-bottom: 4px; color: var(--text); } +.field { margin-bottom: 14px; } +.field-row { display: flex; gap: 12px; } +.field-row .field { flex: 1; } + +.btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 14px; + border-radius: var(--radius); + border: 1px solid var(--border); + background: var(--surface); + color: var(--text); + font-weight: 500; + cursor: pointer; + font-size: 14px; +} +.btn:hover { background: #f0f2f5; } +.btn.primary { background: var(--primary); border-color: var(--primary); color: #fff; } +.btn.primary:hover { background: var(--primary-dark); } +.btn.danger { color: var(--danger); border-color: var(--danger); } +.btn.danger:hover { background: #fdf0f0; } +.btn.sm { padding: 4px 10px; font-size: 13px; } +.btn:disabled { opacity: 0.5; cursor: not-allowed; } + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow); + padding: 20px; +} +.card + .card { margin-top: 16px; } + +.page { padding: 24px 0 48px; } +.page-title { font-size: 20px; font-weight: 700; margin: 0 0 16px; } +.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; } +.page-head .page-title { margin: 0; } + +table.table { width: 100%; border-collapse: collapse; background: var(--surface); } +.table th, .table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); } +.table th { color: var(--muted); font-weight: 600; font-size: 13px; } +.table tr:last-child td { border-bottom: none; } + +.badge { + display: inline-block; + padding: 2px 8px; + border-radius: 999px; + font-size: 12px; + font-weight: 600; + background: #eef1f5; + color: var(--muted); +} +.badge.green { background: #e4f6ec; color: var(--success); } +.badge.blue { background: #e7effd; color: var(--primary); } +.badge.orange { background: #fdf1e0; color: var(--warning); } +.badge.red { background: #fbe6e6; color: var(--danger); } + +.grid { display: grid; gap: 16px; } +.grid.products { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); } +.product-card { overflow: hidden; padding: 0; display: flex; flex-direction: column; } +.product-card img { width: 100%; aspect-ratio: 1; object-fit: cover; background: #eef1f5; } +.product-card .body { padding: 12px; } +.product-card .name { font-weight: 600; margin-bottom: 4px; } +.product-card .price { color: var(--primary); font-weight: 700; } + +.muted { color: var(--muted); } +.row { display: flex; align-items: center; gap: 12px; } +.between { justify-content: space-between; } +.mt { margin-top: 16px; } +.mb { margin-bottom: 16px; } +.error-text { color: var(--danger); margin: 8px 0; } + +.form-narrow { max-width: 420px; margin: 40px auto; } + +.auth-layout { display: flex; min-height: 100vh; } +.auth-layout aside { + width: 220px; + background: var(--surface); + border-right: 1px solid var(--border); + padding: 16px 12px; + display: flex; + flex-direction: column; + gap: 4px; +} +.auth-layout aside .brand { font-weight: 700; font-size: 16px; padding: 8px 10px 16px; } +.auth-layout aside a { + display: block; + padding: 8px 10px; + border-radius: var(--radius); + color: var(--muted); + font-weight: 500; +} +.auth-layout aside a:hover { background: #f0f2f5; text-decoration: none; } +.auth-layout aside a.router-link-active { background: #e7effd; color: var(--primary); } +.auth-layout main { flex: 1; padding: 24px; overflow: auto; } +.auth-layout .main-head { display: flex; justify-content: flex-end; gap: 10px; margin-bottom: 12px; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..267acf0 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,8556 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + apps/admin: + dependencies: + '@nuxtjs/i18n': + specifier: ^9.5.3 + version: 9.5.6(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(rollup@4.63.3)(vue@3.5.42(typescript@5.9.3)) + '@pinia/nuxt': + specifier: ^0.10.1 + version: 0.10.1(magicast@0.5.5)(pinia@2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))) + '@vmall/shared': + specifier: workspace:* + version: link:../../packages/shared + nuxt: + specifier: ^3.15.4 + version: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1) + pinia: + specifier: ^2.3.1 + version: 2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)) + vue: + specifier: ^3.5.13 + version: 3.5.42(typescript@5.9.3) + vue-router: + specifier: ^4.5.0 + version: 4.6.4(vue@3.5.42(typescript@5.9.3)) + + apps/mall: + dependencies: + '@nuxtjs/i18n': + specifier: ^9.5.3 + version: 9.5.6(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(rollup@4.63.3)(vue@3.5.42(typescript@5.9.3)) + '@pinia/nuxt': + specifier: ^0.10.1 + version: 0.10.1(magicast@0.5.5)(pinia@2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))) + '@vmall/shared': + specifier: workspace:* + version: link:../../packages/shared + nuxt: + specifier: ^3.15.4 + version: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1) + pinia: + specifier: ^2.3.1 + version: 2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)) + vue: + specifier: ^3.5.13 + version: 3.5.42(typescript@5.9.3) + vue-router: + specifier: ^4.5.0 + version: 4.6.4(vue@3.5.42(typescript@5.9.3)) + + apps/shop-admin: + dependencies: + '@nuxtjs/i18n': + specifier: ^9.5.3 + version: 9.5.6(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(rollup@4.63.3)(vue@3.5.42(typescript@5.9.3)) + '@pinia/nuxt': + specifier: ^0.10.1 + version: 0.10.1(magicast@0.5.5)(pinia@2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))) + '@vmall/shared': + specifier: workspace:* + version: link:../../packages/shared + nuxt: + specifier: ^3.15.4 + version: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1) + pinia: + specifier: ^2.3.1 + version: 2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)) + vue: + specifier: ^3.5.13 + version: 3.5.42(typescript@5.9.3) + vue-router: + specifier: ^4.5.0 + version: 4.6.4(vue@3.5.42(typescript@5.9.3)) + + packages/shared: {} + +packages: + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + 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-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} + 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-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} + 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.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + 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.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.29.7': + resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bomb.sh/tab@0.0.19': + resolution: {integrity: sha512-dTRfo9Q9B+lbLG3JCu8a/AGQSfD2XXcFcnakQzVjSOX+VvR/s9zpsH8TlqV3iHqazniRn1Ypwd1hcRlXcu/4BA==} + hasBin: true + peerDependencies: + cac: ^6.7.14 + citty: ^0.1.6 || ^0.2.0 + commander: ^13.1.0 || ^14.0.0 || ^15.0.0 + peerDependenciesMeta: + cac: + optional: true + citty: + optional: true + commander: + optional: true + + '@cacheable/memory@2.2.0': + resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==} + + '@cacheable/utils@2.5.0': + resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} + engines: {node: '>= 20.12.0'} + + '@cloudflare/kv-asset-handler@0.4.2': + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + + '@colordx/core@5.8.0': + resolution: {integrity: sha512-cG0QJAO6VkaRUlIb0zOzX9gfJgs1pjoOL9gZ/PK1kfvBs0GCkADu5oQh6gPxXgQnZ3gV575h+lQRC0NlMDTclA==} + + '@dxup/nuxt@0.5.10': + resolution: {integrity: sha512-54Vehb7LmR7qYpC6KFwjDTSm6CB1CayBu+JXdHrPLrIjjr5xAgb43jvgOU+mnB+tsRh414fSsEy0QjBMKILQ8g==} + + '@dxup/unimport@0.1.2': + resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + + '@emnapi/core@1.11.3': + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/wasi-threads@1.2.3': + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.7.3': + resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@intlify/bundle-utils@10.0.1': + resolution: {integrity: sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ==} + engines: {node: '>= 18'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + + '@intlify/core-base@10.0.8': + resolution: {integrity: sha512-FoHslNWSoHjdUBLy35bpm9PV/0LVI/DSv9L6Km6J2ad8r/mm0VaGg06C40FqlE8u2ADcGUM60lyoU7Myo4WNZQ==} + engines: {node: '>= 16'} + + '@intlify/core@10.0.8': + resolution: {integrity: sha512-2BbgN0aeuYHOHe7kVlTr2XxyrnLQZ/4/Y0Pw8luU67723+AqVYqxB7ZG1FzLCVNwAmzdVZMjKzFpgOzdUSdBfw==} + engines: {node: '>= 16'} + + '@intlify/h3@0.6.1': + resolution: {integrity: sha512-hFMcqWXCoFNZkraa+JF7wzByGdE0vGi8rUs7CTFrE4hE3X2u9QcelH8VRO8mPgJDH+TgatzvrVp6iZsWVluk2A==} + engines: {node: '>= 18'} + + '@intlify/message-compiler@10.0.8': + resolution: {integrity: sha512-DV+sYXIkHVd5yVb2mL7br/NEUwzUoLBsMkV3H0InefWgmYa34NLZUvMCGi5oWX+Hqr2Y2qUxnVrnOWF4aBlgWg==} + engines: {node: '>= 16'} + + '@intlify/message-compiler@11.4.12': + resolution: {integrity: sha512-kBczk9r44fdBYnkC5tXRWa/UaA+e9NglXE3cX7jPnDd2nHzoFHYrKGfIbn8JFZpMA9omexZZo2WxOpTvlHdjsw==} + engines: {node: '>= 22'} + + '@intlify/shared@10.0.8': + resolution: {integrity: sha512-BcmHpb5bQyeVNrptC3UhzpBZB/YHHDoEREOUERrmF2BRxsyOEuRrq+Z96C/D4+2KJb8kuHiouzAei7BXlG0YYw==} + engines: {node: '>= 16'} + + '@intlify/shared@11.4.12': + resolution: {integrity: sha512-ojfehaXMFrGFcSnK3cJPaMxlrSXT8FwZUG9H4i+WKX4OFD4Yl1WKdTmfwoC0REnwIfTrnt1QhRtd8kwi/te6bQ==} + engines: {node: '>= 22'} + + '@intlify/unplugin-vue-i18n@6.0.8': + resolution: {integrity: sha512-Vvm3KhjE6TIBVUQAk37rBiaYy2M5OcWH0ZcI1XKEsOTeN1o0bErk+zeuXmcrcMc/73YggfI8RoxOUz9EB/69JQ==} + engines: {node: '>= 18'} + peerDependencies: + petite-vue-i18n: '*' + vue: ^3.2.25 + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + + '@intlify/utils@0.13.0': + resolution: {integrity: sha512-8i3uRdAxCGzuHwfmHcVjeLQBtysQB2aXl/ojoagDut5/gY5lvWCQ2+cnl2TiqE/fXj/D8EhWG/SLKA7qz4a3QA==} + engines: {node: '>= 18'} + + '@intlify/vue-i18n-extensions@8.0.0': + resolution: {integrity: sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ==} + engines: {node: '>= 18'} + peerDependencies: + '@intlify/shared': ^9.0.0 || ^10.0.0 || ^11.0.0 + '@vue/compiler-dom': ^3.0.0 + vue: ^3.0.0 + vue-i18n: ^9.0.0 || ^10.0.0 || ^11.0.0 + peerDependenciesMeta: + '@intlify/shared': + optional: true + '@vue/compiler-dom': + optional: true + vue: + optional: true + vue-i18n: + optional: true + + '@ioredis/commands@1.10.0': + resolution: {integrity: sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + + '@kwsites/file-exists@1.1.1': + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + + '@kwsites/promise-deferred@1.1.1': + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + + '@miyaneee/rollup-plugin-json5@1.2.0': + resolution: {integrity: sha512-JjTIaXZp9WzhUHpElrqPnl1AzBi/rvRs065F71+aTmlqvTMVkdbjZ8vfFl4nRlgJy+TPBw69ZK4pwFdmOAt4aA==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.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@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nuxt/cli@3.37.0': + resolution: {integrity: sha512-Zj9NwHjEBzVrgezsgMFjpMhNqwNgROk9DzNi/dyfk1mCbXIRigV11br2xOl0Satek30bmv7oZAfMtCnDe6Ip0Q==} + engines: {node: ^16.14.0 || >=18.0.0} + hasBin: true + peerDependencies: + '@nuxt/schema': ^4.4.6 + peerDependenciesMeta: + '@nuxt/schema': + optional: true + + '@nuxt/devalue@2.0.2': + resolution: {integrity: sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==} + + '@nuxt/devtools-kit@3.4.2': + resolution: {integrity: sha512-TPPbmH9xrExagYxfCe6JgtbHmgchfgDdA656Yws18rn8I/oCvB+gcw3kTWBBp2sC9ipZPXsgbsW/yZnVnGNBiA==} + peerDependencies: + vite: '>=6.0' + + '@nuxt/devtools-wizard@3.4.2': + resolution: {integrity: sha512-U2G8fw7KW1rdECyJDho5N14z8hSllpTk430KG1QPLjrv5w3pDksZ+YcpITd0u762Vw3gq3Arpg65Bk6U4ua6aQ==} + hasBin: true + + '@nuxt/devtools@3.4.2': + resolution: {integrity: sha512-Nidg0/zB710cyK89ltTkv66hMfPlIPlKA+Yb67bIrAkNm5PoTwQ1goHdFWHIAGZ9nTadcVTzATwMwa56nvl/Wg==} + hasBin: true + peerDependencies: + '@vitejs/devtools': '*' + vite: '>=6.0' + peerDependenciesMeta: + '@vitejs/devtools': + optional: true + + '@nuxt/kit@3.21.11': + resolution: {integrity: sha512-0Xi3tgwN77w43Q8GCPIrvWmF1J7Peehkts44E0uKNIml9lB8WoUn8YxyUjxBv47XtVR86NWoWALAT+/IEMHJEA==} + engines: {node: '>=18.12.0'} + + '@nuxt/kit@4.5.2': + resolution: {integrity: sha512-l66LU9DcJYjmNwqwAj2I5UGRrUbnG2DOKGChnN70zIGtn0eq/z87gi/FRgha6eMb9/FmB1PFHgtx6PWVml1C2Q==} + engines: {node: '>=18.12.0'} + + '@nuxt/nitro-server@3.21.11': + resolution: {integrity: sha512-QIIFH+0xtDBjOdXeTcC23dr+CS98vQv3/wcPtM72BHUUFYH+GWf7TiFCp6xG0wUN6MhGg3KTDjE6yV9U9g6H6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: ^3.21.11 + + '@nuxt/schema@3.21.11': + resolution: {integrity: sha512-5Couz53Pl/SgTwtMQ9jlxVIC6wZk9aAbWyeOD7D6D1UIP5DzV/yV5lPDY/kM0nmiqPSzJf9WLTdJgB2gNm0dOA==} + engines: {node: ^14.18.0 || >=16.10.0} + + '@nuxt/telemetry@2.9.1': + resolution: {integrity: sha512-WYQs6GvebU278YXhbGlLA8pUO3ox+juHAiKCB3SEH0lq2PDRwX465tHRtpVIqsHv+lGK/n99FC7qqyBt9+p3oQ==} + engines: {node: '>=18.12.0'} + hasBin: true + peerDependencies: + '@nuxt/kit': '>=3.0.0' + + '@nuxt/vite-builder@3.21.11': + resolution: {integrity: sha512-4w3g5IFzXhVdX0ZIgmd/zKE2xPZ/e2ms4On1z0OWTDIzvIbrWeednYAJA0bgmgwCBsInYppdih8ZN0w+yWIQmw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + nuxt: 3.21.11 + rolldown: ^1.0.0-beta.38 + rollup-plugin-visualizer: ^6.0.0 || ^7.0.1 + vue: ^3.3.4 + peerDependenciesMeta: + rolldown: + optional: true + rollup-plugin-visualizer: + optional: true + + '@nuxtjs/i18n@9.5.6': + resolution: {integrity: sha512-PhrQtJT6Di9uoslL5BTrBFqntFlfCaUKlO3T9ORJwmWFdowPqQeFjQ9OjVbKA6TNWr3kQhDqLbIcGlhbuG1USQ==} + engines: {node: '>=18.12.0'} + + '@oxc-minify/binding-android-arm-eabi@0.143.0': + resolution: {integrity: sha512-/UEp7vlZSeB5kkcspO93fec1NnPfdkF0JmKUSKm6ZLBhkh+Ua6hHmGU5tBJYF3LeuDDVpe+RIjBlmSu4d0kmKg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-minify/binding-android-arm64@0.143.0': + resolution: {integrity: sha512-ZdqRE7yvqP1snCTlCuJ2u9KUSTIj4k1NobK44VRSboAQb6+9j3rxkJ5wPFuIYRYa12lBijFSijSYAFbYapkibw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-minify/binding-darwin-arm64@0.143.0': + resolution: {integrity: sha512-KGt9pdVmgmSoec2ViIIPaBS4E0LLXP9fuk+ALDgeVvbOo3IffJPBgL8PWGC5jDXvBOAET1p6Ps9B4VcOQnu1sg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-minify/binding-darwin-x64@0.143.0': + resolution: {integrity: sha512-gb7Nc1la98YxpY3uEiCeXsI/D9YzOAkh3nIpyfPRpZGERLUQ/OpLFqXBTQ+/VD/gSHS+BVQPPLukQcZDnRxX8A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-minify/binding-freebsd-x64@0.143.0': + resolution: {integrity: sha512-XBcPdh9Z7eusL49InRDjZQb5M/c9Uc95LVjbj4X9Vn/8K+HP3bI/RhAl+870kxRqRFcSZru/a4VRxWM/q+eYjw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-minify/binding-linux-arm-gnueabihf@0.143.0': + resolution: {integrity: sha512-w9qTGLd+tGkf8sM9QWbzut+BxS5WLEph/annIxbZwoiDzob/6UCHY3j1AOMx9cp34iHv4jdoE5ZpcjkJM7vm6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-minify/binding-linux-arm-musleabihf@0.143.0': + resolution: {integrity: sha512-oqzjfB+JWnP8+A97R9MXZSRokQNrkMadxRdZ6NFIFPshjbqyrCZy0VQAHkdVPUulMYGziKXI3D18fxYTomPNjw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-minify/binding-linux-arm64-gnu@0.143.0': + resolution: {integrity: sha512-kzUFsaL8ZMmwgMSY5PYvwOTBsQuSOp/FrWjmV3cecu54+f0RbF2mrDXVxOirRpF+mc4HzU8ndkatmgFlpIEo6A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-minify/binding-linux-arm64-musl@0.143.0': + resolution: {integrity: sha512-Si6teAvC97dUa2Dat0Aj15bqEKb8+bomAqLrmMZgJ5z6zZTFdDspmCM0dy7XlPVIV/gmM8b9R7353om6M868ag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-minify/binding-linux-ppc64-gnu@0.143.0': + resolution: {integrity: sha512-1YHgZgUHn6kL5q72ohDD7/BwmNTqy71ckz4X++yQ0gLA5iyFCZux+WYO5KOcR/gsh1nRgH7k/XhRlNpvvT43cA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-minify/binding-linux-riscv64-gnu@0.143.0': + resolution: {integrity: sha512-XDVP9LLHxfMB2HiXFKF9gT3Zq648dugq98IUgmBCmRKvryxgXMVlzt+nxHL0v/3r4xtPYcbSTCOhMvVtApUtqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-minify/binding-linux-riscv64-musl@0.143.0': + resolution: {integrity: sha512-m6s3L8zbQWpOHtJ9n+8FQ1dBQ+eQz6l3hK2hDKvPRaYM1+nFjHWrVj6EIwXidBtk4OT1gGvw+ojPWi6X2xZ9SQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-minify/binding-linux-s390x-gnu@0.143.0': + resolution: {integrity: sha512-5ILtPXU0zhjRoaQ86JbtkJwrIsJ70EEV4rYbYmtB6BJDxKDAb8P/tjwYcnBgVTrxrqn/3Mms2wGa2T9yXY6FRg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-minify/binding-linux-x64-gnu@0.143.0': + resolution: {integrity: sha512-JzSNJd8/sO0m+VEhgNfA1ZPxogwhDGrQ5ajNqP1Rdo1N7o4CLBH8wLMpBiHk7a/7Y3V0QHQZScCx6SnwoZ3Qsg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-minify/binding-linux-x64-musl@0.143.0': + resolution: {integrity: sha512-yvA7b2vJP29Kf/lbA+wgJjwgiRxHxK+vR/NVmqK39H40K1dWeugiIRLl3u7P5Q5xVsBaEfg36uokrZiyNY4IAw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-minify/binding-openharmony-arm64@0.143.0': + resolution: {integrity: sha512-0bIPZFCoc5IJvenc3cTP6GRqn6PoIZeQwYlVvdbpun0IlE/Rwx9WTo622T2jcc4+j+u9Vk/oz6wHgisVzDtB5Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-minify/binding-win32-arm64-msvc@0.143.0': + resolution: {integrity: sha512-sO3l3B5iWt1QS3owmR+HfJr6PZ3djl7Qu8EsdLao7Ampz1j2RqGpaLSdcLm5OUtFxXEpjQURG6K4yjg6idOXeA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-minify/binding-win32-ia32-msvc@0.143.0': + resolution: {integrity: sha512-ZyqIYHCB2R0gSr8FqQVUeJNY5yyGoVWyewi9Mx7A222L4392KCzAYLZj9Hh6eAMO2fu9gX52vguA/gCWo2et4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-minify/binding-win32-x64-msvc@0.143.0': + resolution: {integrity: sha512-akQwyMeeaOPBZRklc+KsGfvuAcfjUKctnivNLxW4ubG1SgwRoljR5QliS313lVhixdXiBsIF9eIGCU68RIBfOQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-parser/binding-android-arm-eabi@0.143.0': + resolution: {integrity: sha512-n9uozULWflPqBtdmI8lAabLqGKNgLVNN0ZH8HfgCwpKGNtzRzauB76jTiW/3YLkcA7N1zskpi9GdVnZuu1SAvg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.143.0': + resolution: {integrity: sha512-9BbdjHETk6O3zH/DDid9IgBtF0GlpLabNKN231uraXpRDSfY+iiZxTP5bk1Z63GBownVdhdINFIeddmMz4MzpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.143.0': + resolution: {integrity: sha512-gh+6ecoHUy4/sUcolBl/1qPXKBbYNxFY0Pk0ujgQvINTMSftJY7o4yb8gOkDJPeZeB8+a+u7xTe6umoP8N5HFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-arm64@0.70.0': + resolution: {integrity: sha512-pIi7L9PnsBctS/ruW6JQVSYRJkh76PblBN46uQxpBfVsM57c1s4HGZlmGysQWbdmQTFDZW+SmH3u0JpmDLF0+A==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.143.0': + resolution: {integrity: sha512-qd1hl2d+lXgHv/VQ/M9qm8TrMC5T4RqDBwtOnl+1D0QMjwcz+8AaB4JSg8STgeag0GP6a6L74XEGAsrTSJWNzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.70.0': + resolution: {integrity: sha512-EbKqtOHzZR56ZFC5HHg6XrYneFAJmpLC1Z6FSgbI061Ley1atAViQg7S6Agm9wAcPpns+BeFJqXEBx/y3MKa2w==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.143.0': + resolution: {integrity: sha512-M5XXcNa7aOqLPKTR41msfghKu2yQ4xWvCm11/gwU0JzOzHNk5sgW//rVEjJ+LO48+VDAMzXTSzurUVxIDKwozw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-freebsd-x64@0.70.0': + resolution: {integrity: sha512-MVUaOMEUVE8q3nsWtEo589h++V5wAdqTbCRa9WY4Yuyxska4xcuJQk/kDNCx+n92saS7Luk+b20O9+VCI03c+A==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.143.0': + resolution: {integrity: sha512-T/GXusuOkPNQhCQCSBbcU/N8j0rAypuDBl1IyFK+lyYT594XsVz80clPC/OtbSSpBGyJxj8uYEfctxVuxVYoww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.70.0': + resolution: {integrity: sha512-8N4JTYTgKiRHlMUDAdzKs6iEC57a8ex408VgKoLD/Fl+Un79qOti3S9sotdnWSdH/BsDQeO5NW+PKaqFBTw+hA==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.143.0': + resolution: {integrity: sha512-oKu4RcBlXSqo3OC62dp6YTnQaZIurNDpCX3BnAM3+bJxt7s8J2TJKMnC0UYer1qhlRaDCg6wkTaTw+2IlsZ12w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.70.0': + resolution: {integrity: sha512-Bsu+YvtgWuSfSDJTHMF5APZBOtvddR0GiHyrL0yaXDwaYvAL/E7XcoSK2GdmKTpw+J8nk5IlejEXlQliPo52pQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.143.0': + resolution: {integrity: sha512-WJBbD186AZmMGaSIhlktC+rPl8L3peCTXAh88Ih9uEvK0en2mPojGyCGYiL6mHtV1RPV3JyfJW5t6n5hh0lXhA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.70.0': + resolution: {integrity: sha512-tDzHWKexJPHR+qSiuAFoZ1v8EgCd4ggBNbjJHkcIHsoYKnsKaT1+uE9xfW9UhI1mhv2lo1JJ9n9og2yDTGxSeA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-musl@0.143.0': + resolution: {integrity: sha512-t1AcYOwEzgceadT4v5e+vaCCb0AncCA3v5AyzfBAz/tMq11qzVccXKzNHtkWdjBsgvTKwRkaUF3QvT4kot8vcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-musl@0.70.0': + resolution: {integrity: sha512-BJ+N25UWmHU624558ojSTnht3uFL00jV1c8qk1hnKf4cl6+ovFcoktRWAWSBlgLEP8tLlu8qgIhz875tMj2PkQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-ppc64-gnu@0.143.0': + resolution: {integrity: sha512-RsnO/NoD8376LMJq8JS8TwI0ieNaFRTuNe2GVJntQg6gwZNMENZsEbknHdVwjpOmxdGLGodcwaGSbAeRr5Bgjw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-gnu@0.143.0': + resolution: {integrity: sha512-48fSVfR9TZi5CASZFyv0VC6z6BCoeihFsX031mAD/oSH7d9PYsPgIqza7d9mjP7Z2KTEpTFyH6SIu0Ui6R1vdg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-gnu@0.70.0': + resolution: {integrity: sha512-nxu22nVuPA2xy1cxvBC0D5mVl0myqStOw3XBkVkDViNL01iPyuEFJd5VsM0GqsgrXvF95H/jrbMd+XWnto924g==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-musl@0.143.0': + resolution: {integrity: sha512-T8CpdD+SfE01DnIOD4HpVxu0ZJOfMJ/VhCvikKfaXAxkZ+9veyLM/D2hpi7Y2hFUyPmVQO3FNZHmYzV/WlVR4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-s390x-gnu@0.143.0': + resolution: {integrity: sha512-QLdeMsCcacenPEFsfxnBUDF1y6opyz5+fmOz9bfD5Y7fiGCMupUCuB3KTPQhNwshIG1P9fPqar9MHxuBDd4bwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-parser/binding-linux-s390x-gnu@0.70.0': + resolution: {integrity: sha512-AQ6Xj97lYRxHZl94cZIHJxT5M1qkeEi+vQe+e7M2lAtjcURl8cwhZmWKSv4rt4BQRVfO3ys0bY8AgIh4eFJiqw==} + engines: {node: '>=14.0.0'} + cpu: [s390x] + os: [linux] + + '@oxc-parser/binding-linux-x64-gnu@0.143.0': + resolution: {integrity: sha512-659ujfqLy6k7cuH3sbzhd8b+ztSq+i6E2E9pG78Q0BmHjAExfGIdgc8cGgMdwAozDXeZFHkJ+LXYJdWsaGdgyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-gnu@0.70.0': + resolution: {integrity: sha512-RIxaVsIxtG90CoX6/Okij8itaMrJp4SEJm1pSL0pz3hGo0yur3Il9M1mmGvOpW+avY8uHdwXIvf2qMnnTKZuoQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-musl@0.143.0': + resolution: {integrity: sha512-/Mw/9j4TfZcnKphPrzOE6t4MMknXadcAAuVUlDRTF/ETWB5xOgQvOJV2Mh9We/bWxZdoxaGAdc+hy4GuYwQ2yQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-musl@0.70.0': + resolution: {integrity: sha512-B3S0G4TlZ+WLdQq4mSQtt2ZW0MAkKWc8dla17tZY86kcXvvCWwACvj7I27Z/nSlb7uJOdRZS9/r6Gw0uAARNVQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-openharmony-arm64@0.143.0': + resolution: {integrity: sha512-8rIKWR2BFuifbIK/1XB9wTaSdtuJ25dlE7ZQYDnEwj/2xH2vHsxnvIjHT3ZjSVuLLwGGlSslIG/fbOJ8TV8rTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.70.0': + resolution: {integrity: sha512-QN8yxH7eHXTqed8Oo7ZUzOWn6hixXa8EVINLy21eLU9isoifSPKMswSmCXHxsM2L5rIIvzoaKfghGOru1mMQbw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.143.0': + resolution: {integrity: sha512-5U9kQYMfRRI6Zq7KDxgbIP0RMnKrfn3gLepRMgJuRkPSUALTiRCk9d/uyhb4lGDjUdzwK7mBkKqhLgzBPCmLpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-arm64-msvc@0.70.0': + resolution: {integrity: sha512-6k8/s78g0GQKqrxk4F0wYj32NBF9oSP6089e6BeuIRQ9l+Zh0cuI6unJeLzXNszxmlqq84xmf/tmP3MSDG43Uw==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.143.0': + resolution: {integrity: sha512-25P7AaHk4R88Yv2XH4gToDVmh0cOu+bEURQU10CRrmvgabfRArSGAP5osmwUKeSUHj0VS50upbpbRWWW/m7mHA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.143.0': + resolution: {integrity: sha512-ORMh3JE1s6V7ySicdRK7vgaDQnn5o+UHg9ct989PlWHbel8O9ARrmWXM6kZjrBMtNucxNayQ8g69G0VfWzhANw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.70.0': + resolution: {integrity: sha512-nd9o1QtEvupaJZ3Wn7PfsuC00n31NNRQZ5+Mui6Q0ZyDzp+obqPUSbSt7xh9Dy0c5zgtYMk8WY4n/VBJY2VvTQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + '@oxc-parser/wasm@0.60.0': + resolution: {integrity: sha512-Dkf9/D87WGBCW3L0+1DtpAfL4SrNsgeRvxwjpKCtbH7Kf6K+pxrT0IridaJfmWKu1Ml+fDvj+7HEyBcfUC/TXQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + '@oxc-project/types@0.143.0': + resolution: {integrity: sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==} + + '@oxc-project/types@0.60.0': + resolution: {integrity: sha512-prhfNnb3ATFHOCv7mzKFfwLij5RzoUz6Y1n525ZhCEqfq5wreCXL+DyVoq3ShukPo7q45ZjYIdjFUgjj+WKzng==} + + '@oxc-project/types@0.70.0': + resolution: {integrity: sha512-ngyLUpUjO3dpqygSRQDx7nMx8+BmXbWOU4oIwTJFV2MVIDG7knIZwgdwXlQWLg3C3oxg1lS7ppMtPKqKFb7wzw==} + + '@oxc-transform/binding-android-arm-eabi@0.143.0': + resolution: {integrity: sha512-Rufrk7btlzkIAofJyrm3COzSrn4iNYOnHNYOahBDQly/PgleJv6QIVCHsPTqC6qfX/EJNoAeNshALvVfKSTY5A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-transform/binding-android-arm64@0.143.0': + resolution: {integrity: sha512-EwdR7ynio7zcg3CCaArr/FllpJX8fxmCCQlDdo6o4rZuCSXuIE04hRgcOgRRd5r5AKu81s/XP0TBulXWXaWpmQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-transform/binding-darwin-arm64@0.143.0': + resolution: {integrity: sha512-+o1gLw5mefaKDFfhpIyxKEyeE9kAopy8uA/JCUG0D3stDeY35b3vjeWHgTTBwkOgLXWblq8OvZee1yEJ9Xd40Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-transform/binding-darwin-x64@0.143.0': + resolution: {integrity: sha512-lKEnKHSspm8c+aR+lspmP6m8g09f5VivzMCRpLTrMJLgaWmipUCflBsS8qTKcmRp/hYZl3ARfJ3K00SHSIFb2g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-transform/binding-freebsd-x64@0.143.0': + resolution: {integrity: sha512-8Rir0D6CpKuh0tWuCjnZgk+r8XmKsGXncGBp6lmcYXwC5baLI3DK3T9I/CM1+khoF7JbFE3PqAmoF4HxGysxUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-transform/binding-linux-arm-gnueabihf@0.143.0': + resolution: {integrity: sha512-4F+ErMGgG6f7ydN42VwD+4F1UHhYBb4vELUT/0+gOhuGBN1wwhOPNLhHeJJnZQHZM2JYERdS6wn9uBoBiXw3gw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm-musleabihf@0.143.0': + resolution: {integrity: sha512-XqEYetdBUbFJE8IQUOtDUlyAmoec7I5xkLBFW5wdMI6oRaRJeFFTAK4jg/5sSRzNLU/OFTBTWCn5soQ/iLbwHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm64-gnu@0.143.0': + resolution: {integrity: sha512-LXswrXbEouF3X/q5s+X3Im4VCCNu8aZDj6gRI/s32WDlBqwGosW/A8Ci5MgvCEnU3efVacXhAPPF9zbFE42OAg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-transform/binding-linux-arm64-musl@0.143.0': + resolution: {integrity: sha512-/TKz33dR/kqEdmLwGYsAKuVbjDEPhFKq0PAyIMVCLbqglBy7BRQCw7w7g78X5PLFXso0LgfCFCz/C5dDtBDj/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-transform/binding-linux-ppc64-gnu@0.143.0': + resolution: {integrity: sha512-2mVVq6P4cCXElahTV/GKufxdqRUWZtPHD3EQP2GFigjXRSAXl3HGelIgpYT8I8eoU7QNq6qk+avYsXImt9Hb+Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-transform/binding-linux-riscv64-gnu@0.143.0': + resolution: {integrity: sha512-kkZtkNIqljF8KP9jrZYkhtY1Vbg35jaRj7mZCOinWUPwZIR8PYJwe2KkUVNII+148mYyxlCuf8DZXHiJJ9SNgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-transform/binding-linux-riscv64-musl@0.143.0': + resolution: {integrity: sha512-GRJr0FmQ6C8pbAl0ZyPh/VQwb1/hiXtwrb3IoK93LNsqMWNjbqKFP39lZlLQOdeU8QQADlZM8Qx75YQAOFkbSw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-transform/binding-linux-s390x-gnu@0.143.0': + resolution: {integrity: sha512-k4fpvbh7zGvSLXgOJznv7zPGLgFSYvaMWgVhebxmXZqJgax1kWVOhiJ92L+K/Aqq3tgLEQwkQ8wWGcArSM/O4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-transform/binding-linux-x64-gnu@0.143.0': + resolution: {integrity: sha512-utU2SgpVcipJsQ2lHmZm1twk5ke75/Xt1PivxGV8Va55vrXdIXK+At6ERv+6BikB28qauCe7vv2yovtkEuvmQQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-transform/binding-linux-x64-musl@0.143.0': + resolution: {integrity: sha512-T+cQ/IcWiQ5XVC1cG+DczewthN7c2Vujw0JyO2ugcr6B7TCQiucDd/erVxJSaY59X8d6970+lPtng8Z8XiyGYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-transform/binding-openharmony-arm64@0.143.0': + resolution: {integrity: sha512-3uyqUj+d9hccXdL5WiJW+SVojwckAqSGz+eEBjwIs0/2SXavVpasH8n4E2N5CbCOa4NJdaRKmquHa52s/DN1yQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-transform/binding-win32-arm64-msvc@0.143.0': + resolution: {integrity: sha512-5x4/nWog5kjADuMVoZx9KOpbrzJNRuz59oA5jFW95NvV69lZikgubJDIM7WwBReS0mIoIF+QC2r3pAiJtKrYJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-transform/binding-win32-ia32-msvc@0.143.0': + resolution: {integrity: sha512-z/hozOHz6t/iB68GQPskKJMGxBMpBYqKhOmik3wOprnvnpwOeEyOQ89xuWgvQvX4B69LnxGyAWpJWjSK5zUVzA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-transform/binding-win32-x64-msvc@0.143.0': + resolution: {integrity: sha512-8AaiwIM4M/gEcvXWD71SZDCpY70z7J99G110+fSBws/MHa9PaaWu0IVp5clEG/0alWPQiPZcZRFE3ZIhSd5fng==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@parcel/watcher-wasm@2.6.0': + resolution: {integrity: sha512-dtjbDxKSDPQ8AmA+pS4OFaHE1FKrjtGpLGBxw85uKFkRorjNbvDM/aFPgqosu40wprbp1xw2ZSxIKqghCUHe2w==} + engines: {node: '>= 10.0.0'} + bundledDependencies: + - napi-wasm + + '@pinia/nuxt@0.10.1': + resolution: {integrity: sha512-xrpkKZHSmshPK6kQzboJ+TZiZ5zj73gBCI5SfiUaJkKKS9gx4B1hLEzJIjxZl0/HS5jRWrIvQ+u9ulvIRlNiow==} + peerDependencies: + pinia: ^3.0.1 + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.7.0': + resolution: {integrity: sha512-0UTYalzk2t6S4rA2uHOz5bSSW2CHdv4vggJI6Alg90yvl0UgXs6XSXpH96OH+bRkX4J/06djv29pqXJ0lq5Kag==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/plugin-alias@6.0.0': + resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==} + engines: {node: '>=20.19.0'} + peerDependencies: + rollup: '>=4.0.0' + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-commonjs@29.0.3': + resolution: {integrity: sha512-ZaOxZceP7SOUW7Lqw5IRVweSQYWaeIPnXIGLiB690EBA3FGJTO40EEr2L5yZplJWsgTCogILRSpcAe7+U0Otdg==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-inject@5.0.5': + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-yaml@4.1.2': + resolution: {integrity: sha512-RpupciIeZMUqhgFE97ba0s98mOFS7CWzN3EJNhJkqSv9XLlWYtwVdtE6cDw6ASOF/sZVFS7kRJXftaqM2Vakdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.63.3': + resolution: {integrity: sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.63.3': + resolution: {integrity: sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.63.3': + resolution: {integrity: sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.63.3': + resolution: {integrity: sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.63.3': + resolution: {integrity: sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.63.3': + resolution: {integrity: sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.63.3': + resolution: {integrity: sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.63.3': + resolution: {integrity: sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.63.3': + resolution: {integrity: sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.63.3': + resolution: {integrity: sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.63.3': + resolution: {integrity: sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.63.3': + resolution: {integrity: sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.63.3': + resolution: {integrity: sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.63.3': + resolution: {integrity: sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.63.3': + resolution: {integrity: sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.63.3': + resolution: {integrity: sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.63.3': + resolution: {integrity: sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.63.3': + resolution: {integrity: sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.63.3': + resolution: {integrity: sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.63.3': + resolution: {integrity: sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.63.3': + resolution: {integrity: sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.63.3': + resolution: {integrity: sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.63.3': + resolution: {integrity: sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.63.3': + resolution: {integrity: sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.63.3': + resolution: {integrity: sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==} + cpu: [x64] + os: [win32] + + '@simple-git/args-pathspec@1.0.3': + resolution: {integrity: sha512-ngJMaHlsWDTfjyq9F3VIQ8b7NXbBLq5j9i5bJ6XLYtD6qlDXT7fdKY2KscWWUF8t18xx052Y/PUO1K1TRc9yKA==} + + '@simple-git/argv-parser@1.1.1': + resolution: {integrity: sha512-Q9lBcfQ+VQCpQqGJFHe5yooOS5hGdLFFbJ5R+R5aDsnkPCahtn1hSkMcORX65J2Z5lxSkD0lQorMsncuBQxYUw==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.24': + resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} + + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@typescript-eslint/project-service@8.70.0': + resolution: {integrity: sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.70.0': + resolution: {integrity: sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.70.0': + resolution: {integrity: sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.70.0': + resolution: {integrity: sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.70.0': + resolution: {integrity: sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.70.0': + resolution: {integrity: sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unhead/vue@2.1.17': + resolution: {integrity: sha512-pnC8x9HLV3qQXdvWfylUEU25uhfCAy3ly9nmpQz84j9py818DRfU8jOsQ5wjdWtxyU1vX/fW2udfm4jtxUK8Bg==} + peerDependencies: + vue: '>=3.5.18' + + '@vercel/nft@1.11.0': + resolution: {integrity: sha512-m1QFg+U+3yPOnP1xSYJ73UIRxLOXdts1JOhiOiyPYqEsALgrXFFINvgUaD6R6iNvaBFAjHllBCbkfx4FuOdpaA==} + engines: {node: '>=20'} + hasBin: true + + '@vitejs/plugin-vue-jsx@5.1.6': + resolution: {integrity: sha512-YXvi4as2clxt6DFw5+a0tTA97ntiQXm/raR8ofNj3aNwwdlVGTiG2gp7EvfZW17P50acL/9bP0ccF4XnqNmlgA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.0.0 + + '@vitejs/plugin-vue@6.0.9': + resolution: {integrity: sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@vue-macros/common@1.16.1': + resolution: {integrity: sha512-Pn/AWMTjoMYuquepLZP813BIcq8DTZiNCoaceuNlvaYuOTd8DqBZWc5u0uOMQZMInwME1mdSmmBAcTluiV9Jtg==} + engines: {node: '>=16.14.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + + '@vue-macros/common@3.1.4': + resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==} + engines: {node: '>=20.19.0'} + peerDependencies: + vue: ^2.7.0 || ^3.2.25 + peerDependenciesMeta: + vue: + optional: true + + '@vue/babel-helper-vue-transform-on@2.0.1': + resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} + + '@vue/babel-plugin-jsx@2.0.1': + resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@2.0.1': + resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.42': + resolution: {integrity: sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==} + + '@vue/compiler-dom@3.5.42': + resolution: {integrity: sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==} + + '@vue/compiler-sfc@3.5.42': + resolution: {integrity: sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==} + + '@vue/compiler-ssr@3.5.42': + resolution: {integrity: sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-core@8.2.1': + resolution: {integrity: sha512-s/VfAY9oDTb/kFEWmy461jaFde2MIV1RO/gi1vwM+PAZBZ/Pc2Ndu3BNBdZUze8QDUuyYvElbEEGA83syjJfzA==} + peerDependencies: + vue: ^3.0.0 + + '@vue/devtools-kit@8.2.1': + resolution: {integrity: sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==} + + '@vue/devtools-shared@8.2.1': + resolution: {integrity: sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==} + + '@vue/language-core@3.3.11': + resolution: {integrity: sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==} + + '@vue/reactivity@3.5.42': + resolution: {integrity: sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==} + + '@vue/runtime-core@3.5.42': + resolution: {integrity: sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==} + + '@vue/runtime-dom@3.5.42': + resolution: {integrity: sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==} + + '@vue/server-renderer@3.5.42': + resolution: {integrity: sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==} + + '@vue/shared@3.5.42': + resolution: {integrity: sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==} + + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + alien-signals@3.2.1: + resolution: {integrity: sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.4.0: + resolution: {integrity: sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==} + engines: {node: '>=14'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + ast-kit@1.4.3: + resolution: {integrity: sha512-MdJqjpodkS5J149zN0Po+HPshkTdUyrvF7CKTafUgv69vBSPtncrj+3IiUgqdd7ElIEkbeXCsEouBUwLrw9Ilg==} + engines: {node: '>=16.14.0'} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + ast-walker-scope@0.6.2: + resolution: {integrity: sha512-1UWOyC50xI3QZkRuDj6PqDtpm1oHWtYs+NQGwqL/2R11eN3Q81PHAHPM0SWW3BNQm53UDwS//Jv8L4CCVLM1bQ==} + engines: {node: '>=16.14.0'} + + ast-walker-scope@0.8.3: + resolution: {integrity: sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==} + engines: {node: '>=20.19.0'} + + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + autoprefixer@10.6.1: + resolution: {integrity: sha512-cL1Qz6ADZhcEbny/8HPfe99J6HhNoYtpX2LFLIbhgGE7Q1hlQVkYFdetDN7Id3KiQxhDrHwzlHr/YQCnZ8+xSA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + b4a@1.9.0: + resolution: {integrity: sha512-dpfcF9fDNR6++cthXR67iyhgqWy9CBouAvIWhIntzBG6cvK/cnIPiZQjBwi/ZqjjBEDGfoNDtmB0kTjroOJ3pQ==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + 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} + + bare-events@2.9.2: + resolution: {integrity: sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.8.1: + resolution: {integrity: sha512-N1nnXdHZAOSstz0XiHikGS4HGMH4CnSwhqWdGQQMqqdvp4Jybm9sE3R1WVnpWVd4SFkc8ryPDBLViNLwiEqECg==} + engines: {bare: '>=1.28.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-path@3.1.2: + resolution: {integrity: sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw==} + + bare-stream@2.13.4: + resolution: {integrity: sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA==} + peerDependencies: + bare-abort-controller: '*' + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.5.4: + resolution: {integrity: sha512-Gxa7UVWBr0/edU1b+TJhn/AZvMQUj9OGspvYsaTYQrAbZA4BOTZGL3LiZxvD+CeMlDH4juwD84+eTAp/bLYW5g==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.11.24: + resolution: {integrity: sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg==} + engines: {node: '>=6.0.0'} + hasBin: true + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + birpc@4.2.0: + resolution: {integrity: sha512-KxgKcZPfrtzJDDALHPguGpGJUrzdgpymyiQQgzFjWreHMOpWrnFNVREr5J48x2DBh8ZVioscrV1SBkDipGiX+Q==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@2.1.7: + resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==} + + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.29.0: + resolution: {integrity: sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} + + cacheable@2.5.0: + resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} + + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + + cluster-key-slot@1.1.1: + resolution: {integrity: sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compatx@0.2.0: + resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + confbox@0.3.1: + resolution: {integrity: sha512-cKUSoKa8YxFZZSmraVi7onONx3amu77ngK3kGpsYHDH7drPwCRkQE1RYMPlLRrMtnciRj274XNRxcHxnKmDSnA==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cookie-es@2.0.1: + resolution: {integrity: sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==} + + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + croner@10.0.1: + resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} + engines: {node: '>=18.0'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + crossws@0.4.12: + resolution: {integrity: sha512-aypfsr6t0uNvkqaZc6zvBfXzC6pLI0/sIulpkV6RwCVtZqG5ebBzv4weImKK0VNCj91Wl9F5j7p5WU4MNrybng==} + peerDependencies: + srvx: '>=0.11.5' + peerDependenciesMeta: + srvx: + optional: true + + css-declaration-sorter@7.4.0: + resolution: {integrity: sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.0.9 + + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@7.0.17: + resolution: {integrity: sha512-11qO63A+czwguQFJCaTdICvbaxn0pJzz/XghLlv+OT7WyToDxAMR0Xb3/26/l0y0hQJywwNbj/SLSQlGBHE1OA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + cssnano-utils@5.0.3: + resolution: {integrity: sha512-ynIREMICLxkxm7e9bCR9sh75s4Q5drICi0ua1yxo5jH2XPBqSKkl4dOh4EbFqtUmnTMhRffHgYL0EKKkMjtJTg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + cssnano@7.1.9: + resolution: {integrity: sha512-uPR75+5Dk/WJ/YSPR1/YDHdwMM9c5FsaARljfKWgeCKLKOtJ0we21xy/RcCjn53fZnD/f6yYEIZ8pu18+GnbNQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + db0@0.3.4: + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + better-sqlite3: '*' + drizzle-orm: '*' + mysql2: '*' + sqlite3: '*' + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + better-sqlite3: + optional: true + drizzle-orm: + optional: true + mysql2: + optional: true + sqlite3: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.1: + resolution: {integrity: sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==} + engines: {node: '>=18'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.9.2: + resolution: {integrity: sha512-po4PAY5c53tw5XMocSnf8A/5OHhbbUftpr93aEN6BBoAdntUmK7vu7wOATqvt7cXO7m1Cl4gMVn6p7n6n4mj0w==} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-prop@10.2.0: + resolution: {integrity: sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw==} + engines: {node: '>=20'} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.430: + resolution: {integrity: sha512-e1QEj72Y4zd8RlNZVmoTg+iCOSVwpk05IOiiQwdrkwCSVlZfPthevErhE+nckGd2YbsXfp1SkisznhGVIXP2NQ==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.25.1: + resolution: {integrity: sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + error-stack-parser-es@2.0.1: + resolution: {integrity: sha512-J36ntO+rMQVRuR/umlmxmfLi4TpWwtmTnHoJoXTiC2xDNazs0VDPKcX6pbhZMDd2HFtH9isMBJXMdbki+A++Pg==} + + errx@0.1.2: + resolution: {integrity: sha512-chfpPHmCerdo/rXr/nNvPZRkV4WwDRwzwnsJ0Uzz3tVi8Z41tDctRjduYy1138ii77AFlts1qvWtX3g/Acg91Q==} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.10.0: + resolution: {integrity: sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + exsolve@1.1.1: + resolution: {integrity: sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==} + + externality@1.0.2: + resolution: {integrity: sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-npm-meta@2.2.0: + resolution: {integrity: sha512-99jPl8JkCSCa4VlboNU1XuL98ijm74Pm9CGo6H4BoMVoVh1uhguQcvwLgXDT8Vkl2qj/UEQ0J9gD8beHjTFk1w==} + hasBin: true + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + + fastq@1.20.3: + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@11.1.5: + resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@6.1.23: + resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} + + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + fuse.js@7.5.0: + resolution: {integrity: sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==} + engines: {node: '>=10'} + + fzf@0.5.2: + resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} + + generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + giget@3.3.1: + resolution: {integrity: sha512-r+mvuDjrjMpsdw46Kmeydb8bdHm7wOKw8wNBtTndkjbPjgAp5oUJUxRE76wZFknxIPokfWvep2qSXK37aXE6zg==} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + 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} + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + globby@16.2.4: + resolution: {integrity: sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==} + engines: {node: '>=20'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gzip-size@7.0.0: + resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hookable@6.1.1: + resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + httpxy@0.5.5: + resolution: {integrity: sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.9: + resolution: {integrity: sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==} + engines: {node: '>= 4'} + + image-meta@0.2.2: + resolution: {integrity: sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA==} + + impound@1.2.0: + resolution: {integrity: sha512-hbFh2WURN+XQ364SbblzubhEEj/B3qZCe80l/EHXPWM6/kZP2mvOllxwRBBWNxe4gLbqXZL0fxOZwoDCSlJZQw==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ioredis@5.11.1: + resolution: {integrity: sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==} + engines: {node: '>=12.22.0'} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-installed-globally@1.0.0: + resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} + engines: {node: '>=18'} + + 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-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-eslint-parser@2.4.2: + resolution: {integrity: sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} + + launch-editor@2.14.1: + resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + listhen@1.10.1: + resolution: {integrity: sha512-6nt/86SkqUQSLW1ofz8MxC6RhRMqOl3ONISe6qqvJ3xj09aJWQx6DhgSZpugs3PX4PXdOas/WD6A9jx6J2N19A==} + hasBin: true + peerDependencies: + '@parcel/watcher': ^2.5.6 + peerDependenciesMeta: + '@parcel/watcher': + optional: true + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + 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==} + + magic-string-ast@0.7.1: + resolution: {integrity: sha512-ub9iytsEbT7Yw/Pd29mSo/cNQpaEu67zR1VVcXDiYjSFwzeBxNdTd0FMnSslLQXiRj8uGPzwsaoefrMD5XAmdw==} + engines: {node: '>=16.14.0'} + + magic-string-ast@1.0.3: + resolution: {integrity: sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==} + engines: {node: '>=20.19.0'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magic-string@1.4.1: + resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==} + + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mocked-exports@0.1.1: + resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.19: + resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanotar@0.3.0: + resolution: {integrity: sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + nitropack@2.13.4: + resolution: {integrity: sha512-tX7bT6zxNeMwkc6hxHiZeUoTOjVrcjoh1Z3cmxOlodIqjl4HISgqfGOmkWSayky3Nv9Z5+KQH52F8nmXJY5AAA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + xml2js: ^0.6.2 + peerDependenciesMeta: + xml2js: + optional: true + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-forge@1.4.0: + resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} + engines: {node: '>= 6.13.0'} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-mock-http@1.0.5: + resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==} + + node-releases@2.0.55: + resolution: {integrity: sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==} + engines: {node: '>=18'} + + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nostics@1.2.0: + resolution: {integrity: sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg==} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nuxt@3.21.11: + resolution: {integrity: sha512-/RlSSvx2ne/vXbeEy+ZWZ0uVgXyiadVkrK5hMx7XsDk7R6q2o4qln2JxoQqILe7K6HzbWM9/0YFS00bTRj/kEw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@parcel/watcher': ^2.1.0 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + peerDependenciesMeta: + '@parcel/watcher': + optional: true + '@types/node': + optional: true + + nypm@0.6.10: + resolution: {integrity: sha512-W72Hrj1petq+b3Hk2aAC+9zswetlIFTnDW4s5djseZh2nYqBbyQLOtj472HwcbcWykPBUW1WpWpjOd4nK6gMRw==} + engines: {node: '>=18'} + hasBin: true + + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.12: + resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} + + on-change@6.0.2: + resolution: {integrity: sha512-08+12qcOVEA0fS9g/VxKS27HaT94nRutUT77J2dr8zv/unzXopvhBuF8tNLWsoLQ5IgrQ6eptGeGqUYat82U1w==} + engines: {node: '>=20'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + open@11.0.4: + resolution: {integrity: sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==} + engines: {node: '>=20'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + oxc-minify@0.143.0: + resolution: {integrity: sha512-6P7PFKZpZkI14ez9duBfVWTKLBgJfJMtdPlGGUmTIXiwMWcxS4Qy4+65qWePmYyksuzhaI5AS660V2/UjaveMA==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-parser@0.143.0: + resolution: {integrity: sha512-ov0NzaDCOInknS7mP1cwKdJERt3utPW8ldjtdUXQ8Ty0GEFD08wk422vCUN0d7pST6kqtV7dxoI9w1Zi0l/9TA==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-parser@0.70.0: + resolution: {integrity: sha512-YbqTuQDDIYwQF/li0VFK5uTbmHV4jWFeQQONkPdf77vz+JMiq7SusmcSVZ4hBrGM+3WyLdKH5S7spnvz4XVVzQ==} + engines: {node: '>=14.0.0'} + + oxc-transform@0.143.0: + resolution: {integrity: sha512-DBx6urRQRwA2pu3sMxmmVONu2fFlOoi3cU63DGyNsuB5YuAeR/AujdfBv7qqRRq0SnWlPsrHNrzoF8Zf43fIsg==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-walker@1.1.1: + resolution: {integrity: sha512-Hwd7dq28zu/Er99+bpWp16CGwFrhyalJh0W3JOB7XpPvgWo3MqMi2ksWGKuzzA9zt50mJ2pIUwR5lpAdZ9ACNQ==} + peerDependencies: + '@oxc-project/types': '>=0.98.0' + oxc-parser: '>=0.98.0' + rolldown: '>=1.0.0' + peerDependenciesMeta: + '@oxc-project/types': + optional: true + oxc-parser: + optional: true + rolldown: + optional: true + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + 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} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + pinia@2.3.1: + resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} + peerDependencies: + typescript: '>=4.4.4' + vue: ^2.7.0 || ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.3: + resolution: {integrity: sha512-j/lCFdcppV0JxWpCEITdbDltBxPP6cHT+yNJ6Go2OgoSA9518X847X9z0p6LtA4Nc16+eQzCZjRrWanTGvHJ5w==} + + postcss-calc@10.1.1: + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} + engines: {node: ^18.12 || ^20.9 || >=22.0} + peerDependencies: + postcss: ^8.4.38 + + postcss-colormin@7.0.10: + resolution: {integrity: sha512-yFr6JezOolHLta/buLE71VKPh2mXursp4saVe98/ol8ZnEWhL+racShqPKlvd/DKWLre/39B6HhcMXf7RZ3hxg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-convert-values@7.0.12: + resolution: {integrity: sha512-xurKu5qqk4viR3Cp3p4xBR4KfnZm4w4ys6+UBwBmeuBSNkH7+DtLnYOYnOffgtE4yx8sH9S1VZ6RAAvROXzP2Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-discard-comments@7.0.8: + resolution: {integrity: sha512-CvvS5S9WrXblFXCEJ9nVo+4z+eA7zSC7Z88V1HEJuwlQhlFnYTIjg1xJY+BCUiG2bvICap2tXii4mP22BD108Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-discard-duplicates@7.0.4: + resolution: {integrity: sha512-VBNn1+EuMZkeGVVtz0gRfbNGtx9IFgAsAV+E2pHtXPrp4qfGBkhTIiAuE/wrb+Y6Pakg9NewAlfTpYIFAWODtw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-discard-empty@7.0.3: + resolution: {integrity: sha512-M2pyjQCU+/7cMHVtL6bKTHjv0lZnPLMpicgr67Dlth7AbuV9gjVTtUqaRwn6Pp6BwSDspUzhz8SaUrRykJU5Dw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-discard-overridden@7.0.3: + resolution: {integrity: sha512-aNovXo9UsZuRNLzHJtp13lHIvinDPfiXBPePpXkSjCbgp++iU2FqE+YxvjIsg6EdyPZsASFbfu+JcBFVsErXIQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-merge-longhand@7.0.7: + resolution: {integrity: sha512-b3mfYUxR388u5Pt0HPcVIUtUDn/k15UfTY9M+ORW+meCR6JLNxoZffiYvXyOYQoRYQNZyX/UFkMCM/mNHxe1qA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-merge-rules@7.0.11: + resolution: {integrity: sha512-SJUPM18g2BmPhf8BVlbwqWz4aK3pLu6u6xjfwEzra7xL6IBR10sUaiB++EzqcVfadPHrKBSMlNdP+XieykhI+Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-minify-font-values@7.0.3: + resolution: {integrity: sha512-yilG/VOaNI74IylQvAQQxm3/wZVBkXyYUqNUAdxqwtbWUXPsbK1q8Ms0mL83v+f8YicgcyfYCRZtWACUdYajpA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-minify-gradients@7.0.5: + resolution: {integrity: sha512-YraROyQRg3BI1+Hg8E05B/JPdnTm8EDSVu4P2BxdM+CRiOyfmou809+chGIqo6fQqwjPGQ947nbGncSjmTU1WQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-minify-params@7.0.9: + resolution: {integrity: sha512-R8itbB8BhlpoYyBm1ou0dD+vJnQ3F6adQipR4UnkCHUwlo+S9WXJaDRg1RHjC8YVAtIdrQzSWvJl40HnGDTKjA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-minify-selectors@7.1.2: + resolution: {integrity: sha512-aQtrEWKwqafNlExcKHQvPGsXR2+vlUqqJtf5XsCQcgsSb5PL4wlujWBYDJuWsP4UnQX1YHDHU8qRlD+1PzTQ+Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-charset@7.0.3: + resolution: {integrity: sha512-NoBfZu8PR4c2NlmjvrqQTzCzLY79hwcSRgNQ3ZiNK0ABzf9kYKloE/jNj+/8GQY1wsm8pRRgANk6ydLH8cwo0Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-display-values@7.0.3: + resolution: {integrity: sha512-ldsCX0QIt05pKIOobZtVQ48wXJecr+czw4+e1/YjVhLMqslShgpVxgPtI2CefURR8oyVoYaU/l829MMwExDMLw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-positions@7.0.4: + resolution: {integrity: sha512-VEvlpeGd3Ju1Hqa/oN4jaP3+ms4laYwkEL9N9u+B6k54PZjXbW1n6wI+aVprf1BQXlCYpS5+1pl/7/vHiKgARg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-repeat-style@7.0.4: + resolution: {integrity: sha512-6mPKlY/8cSaDHxX502wERADarJsccwlky6yIrOapHH2ZgfoKAV94SbiTKfKEs4EEpdazuc3J72WsqeYk7hp9+Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-string@7.0.3: + resolution: {integrity: sha512-HnEQPUchi1eznmDKEYrKUTqrprEq97SrpUYClgUkv7V2zRODD9DFoUsYU+m9ZOetmD5ku7fEMZB/lwy8IT6xVQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-timing-functions@7.0.3: + resolution: {integrity: sha512-zmEzHdvpZBZu0OKlbJSfgASQvaayyAoVuWtvyr34IJ/LyS+DaOKvvR3EvFJ9RWWtNIx+CMvO125OVophaxNYew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-unicode@7.0.9: + resolution: {integrity: sha512-DRAdWfeh/TjmhLJsw91vdiWCnUod9iwvM7xyS02/nF/sLsCR3A8l3pztrSUrWG8DSBqfX7yEk9FM0USaVJ2mSg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-url@7.0.3: + resolution: {integrity: sha512-CL93wmloq5qsffmFv+bw24MIRbmhHrp53qoh1LDAb/5TtjWEXI/np4xcP/Gw9oWCb2XyWnqHYLDUwiKRoJBA1Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-normalize-whitespace@7.0.3: + resolution: {integrity: sha512-FdHjjn+Ht5Z2ZRjNOmeCbNq6lq09sUYKpmlF/Aq0XjVNSLTL6fmHlA/3swN2wP2caY9GV/tjSDcIIyS7aN7W0A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-ordered-values@7.0.4: + resolution: {integrity: sha512-nubSi49hDHQk4E8KIj+IbLY8Bg+8OcSUEhgyolgM+atnOvXjV7EjaR6bac4YGZoFyPa9mWoAF3EaYbWdFkKqVg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-reduce-initial@7.0.9: + resolution: {integrity: sha512-ztTNPdIxXTxtBcG03E9u8v44M4ElXbMIRT7pf2onlquGula0Y83nKKxqM22FA/hMgkfCjN7ohevkVlaNwI8iOQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-reduce-transforms@7.0.3: + resolution: {integrity: sha512-FXsnN9ZwcZTT8Yf8cAHA8qIGUXcX6WfLd9JoYhrdDfmvsVhhfqkkv7m4AC3rwFOfz+GzkUa87OCKF9dUcicd+g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-selector-parser@7.1.6: + resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==} + engines: {node: '>=4'} + + postcss-svgo@7.1.3: + resolution: {integrity: sha512-2QfoFOYMcj8lwcVEf9WeTlkVIAm7u2QvOEhMzkQU3KUhhGX/l8hVV9EtjMv4iq3E9iI3OeeMN0YoMLbGusuigw==} + engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + peerDependencies: + postcss: ^8.5.13 + + postcss-unique-selectors@7.0.7: + resolution: {integrity: sha512-d+sCkaRnSefghOUdH8CMJZV9yUQhj2ojpe8Nw/lA+LV1UOfeleGkLTl6XdCFFSai9UJ+DJPb69FFuqthXYsY8w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} + + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + + powershell-utils@0.2.1: + resolution: {integrity: sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==} + engines: {node: '>=20'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + pretty-bytes@7.1.3: + resolution: {integrity: sha512-U2KZ675nqba6XSBppSjU2pRgc9Ffx9+uUtd/RTWYmOawVkZuUbBYuwdtFZQmLv+yMgQ2TQxWWuOpyNje67J9tg==} + engines: {node: '>=20'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + rc9@3.1.0: + resolution: {integrity: sha512-ufjkNVzbRHKcCOmTahZkmVsyc3W+MSk3jY03m+a7tGHkIsdVMG9l10/3HvFbWkkKzY5VFp3pkRsIo/UYgmFL7Q==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup-plugin-visualizer@7.1.1: + resolution: {integrity: sha512-ThaGiHTU8XW02OkK80TrTHATraJmM9OAduU4otal+7gyXLpYEtmGBLfx5kW+EHvvLwn03YGW2NnwKUIqsYlJAA==} + engines: {node: '>=22'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta || ^1.0.0-rc + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@4.63.3: + resolution: {integrity: sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rou3@0.9.2: + resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serialize-javascript@7.1.1: + resolution: {integrity: sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==} + engines: {node: '>=20.0.0'} + + seroval@1.6.7: + resolution: {integrity: sha512-AeDcLh0yO2SFm9W71essgnSzLV9DI8ZH0x0knXn2DMnUZj728mpLbxjlbB6IqKCmqh8JA3cEqRyGoNkt584JcQ==} + engines: {node: '>=10'} + + serve-placeholder@2.0.2: + resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.10.0: + resolution: {integrity: sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-git@3.36.0: + resolution: {integrity: sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q==} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + smob@1.6.2: + resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} + engines: {node: '>=20.0.0'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + source-map@0.8.0: + resolution: {integrity: sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==} + engines: {node: '>= 12'} + + srvx@0.11.22: + resolution: {integrity: sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==} + engines: {node: '>=20.16.0'} + hasBin: true + + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + + streamx@2.28.1: + resolution: {integrity: sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==} + + string-width@4.2.3: + 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-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.2: + resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} + engines: {node: '>=20'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-literal@4.0.0: + resolution: {integrity: sha512-PaqAvfUZKBwc/SLmNZtHmzK+v19Z4O4eS3cKPeGvbIv/U3pnyEq4Tuw3/4v/FwfM8VQaEawsyCcOQ0P+kpwWWw==} + + structured-clone-es@2.0.1: + resolution: {integrity: sha512-10ZL5r77LhknxlP1FBiCW+VdnuWOEFLdSS2SKtjyEV+L4qP1hUEIMIZW94LC3jKxRmT/Dj7KkD1mqh/IY6lhKQ==} + + stylehacks@7.0.11: + resolution: {integrity: sha512-iODNfhXVLqc5LADs+Y6Oh5wJuK5ZcHbVng8aiK3y9pjMQdc5hLrBW0eFU6FtnpNrE6PoEg/MmFTU4waotj5WNg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.5.13 + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svgo@4.1.0: + resolution: {integrity: sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==} + engines: {node: '>=16'} + hasBin: true + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tar-stream@3.2.1: + resolution: {integrity: sha512-nqsEO8zLZJvrOMdEwkA0QdCLFbetHMn95Zqu4fKwX+hkaTWJPZZOrxx/PwtxoK0MMGQmBQNRW3CPs8IFYQz4cQ==} + + tar@7.5.22: + resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} + engines: {node: '>=18'} + + teex@1.0.1: + resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} + + terser@5.51.2: + resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==} + engines: {node: '>=10'} + hasBin: true + + text-decoder@1.2.7: + resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinyclip@0.1.15: + resolution: {integrity: sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==} + engines: {node: ^16.14.0 || >= 17.3.0} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tosource@2.0.0-alpha.3: + resolution: {integrity: sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==} + engines: {node: '>=10'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@5.9.0: + resolution: {integrity: sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==} + engines: {node: '>=20'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + ultrahtml@1.7.0: + resolution: {integrity: sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} + + unctx@3.0.1: + resolution: {integrity: sha512-5RAt2etv7g362RXyd33R82gm9u/kbtQlpoaOs9Bgm4E32GRMJ0xjbZyvdxUTmiuHk3V1IQb1aUNrp5IWY+JaWw==} + peerDependencies: + magic-string: '>=0.30.21' + oxc-parser: '>=0.140.0' + rolldown: ^1.1.5 + unplugin: ^3.3.0 + peerDependenciesMeta: + magic-string: + optional: true + oxc-parser: + optional: true + rolldown: + optional: true + unplugin: + optional: true + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unhead@2.1.17: + resolution: {integrity: sha512-HLMKXOszRhAPBrr6VlqCeVeJq2kbC4kXwzGLEZvvojPLWNYTJw22xG7Bfwhsvs31+IBet3Wl8ADg9dwYdyphfQ==} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + + unimport@6.5.0: + resolution: {integrity: sha512-t0KLJLRbebz3f7NrQe+vy2ObeugVeM1XqI2oeYnauddmHSglYj3U6bxOJ65IbXmOFkcAGFJK2OyGH7aqHPM6Ug==} + engines: {node: '>=18.12.0'} + peerDependencies: + oxc-parser: '*' + rolldown: ^1.0.0 + peerDependenciesMeta: + oxc-parser: + optional: true + rolldown: + optional: true + + unplugin-utils@0.2.5: + resolution: {integrity: sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==} + engines: {node: '>=18.12.0'} + + unplugin-utils@0.3.2: + resolution: {integrity: sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==} + engines: {node: '>=20.19.0'} + + unplugin-vue-router@0.12.0: + resolution: {integrity: sha512-xjgheKU0MegvXQcy62GVea0LjyOdMxN0/QH+ijN29W62ZlMhG7o7K+0AYqfpprvPwpWtuRjiyC5jnV2SxWye2w==} + deprecated: 'Merged into vuejs/router. Migrate: https://router.vuejs.org/guide/migration/v4-to-v5.html' + peerDependencies: + vue-router: ^4.4.0 + peerDependenciesMeta: + vue-router: + optional: true + + unplugin-vue-router@0.19.2: + resolution: {integrity: sha512-u5dgLBarxE5cyDK/hzJGfpCTLIAyiTXGlo85COuD4Nssj6G7NxS+i9mhCWz/1p/ud1eMwdcUbTXehQe41jYZUA==} + deprecated: 'Merged into vuejs/router. Migrate: https://router.vuejs.org/guide/migration/v4-to-v5.html' + peerDependencies: + '@vue/compiler-sfc': ^3.5.17 + vue-router: ^4.6.0 + peerDependenciesMeta: + vue-router: + optional: true + + unplugin@1.16.1: + resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} + engines: {node: '>=14.0.0'} + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unplugin@3.4.0: + resolution: {integrity: sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@farmfe/core': '*' + '@rsbuild/core': '*' + '@rspack/core': '*' + bun-types-no-globals: '*' + esbuild: '*' + rolldown: '*' + rollup: '*' + unloader: '*' + vite: '*' + webpack: '*' + peerDependenciesMeta: + '@farmfe/core': + optional: true + '@rsbuild/core': + optional: true + '@rspack/core': + optional: true + bun-types-no-globals: + optional: true + esbuild: + optional: true + rolldown: + optional: true + rollup: + optional: true + unloader: + optional: true + vite: + optional: true + webpack: + optional: true + + unstorage@1.17.5: + resolution: {integrity: sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + untun@0.2.2: + resolution: {integrity: sha512-+NnOJcSiEtYsVgJmXUzQbJeRAFXJC4yPJYuh6kF9B0Rm6zunXcs/3GZOTllyocSbUDIxD6Bj7e/4ATw7sph1Sw==} + hasBin: true + + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true + + unwasm@0.5.3: + resolution: {integrity: sha512-keBgTSfp3r6+s9ZcSma+0chwxQdmLbB5+dAD9vjtB21UTMYuKAxHXCU1K2CbCtnP09EaWeRvACnXk0EJtUx+hw==} + + update-browserslist-db@1.3.3: + resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uqr@0.1.3: + resolution: {integrity: sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + verkit@0.3.2: + resolution: {integrity: sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==} + engines: {node: '>=18.12.0'} + + vite-dev-rpc@2.0.0: + resolution: {integrity: sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0 + + vite-hot-client@2.2.0: + resolution: {integrity: sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0 + + vite-node@5.3.0: + resolution: {integrity: sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + vite-plugin-checker@0.14.5: + resolution: {integrity: sha512-c9lQ92eisUO+F7Fd93aelojmiOS+NQpPgQ1XR2LTQHox1/laZf4yAoQj+L3RA9Vgh10e2nFd9b8r2LLyYZsbpA==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@biomejs/biome': '>=2.4.12' + eslint: '>=9.39.4' + meow: ^13.2.0 || ^14.0.0 + optionator: ^0.9.4 + oxlint: '>=1' + stylelint: '>=16.26.1' + typescript: '*' + vite: '>=5.4.21' + vue-tsc: ~2.2.10 || ^3.0.0 + peerDependenciesMeta: + '@biomejs/biome': + optional: true + eslint: + optional: true + meow: + optional: true + optionator: + optional: true + oxlint: + optional: true + stylelint: + optional: true + typescript: + optional: true + vue-tsc: + optional: true + + vite-plugin-inspect@11.4.1: + resolution: {integrity: sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^6.0.0 || ^7.0.0-0 || ^8.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + vite-plugin-vue-tracer@1.5.0: + resolution: {integrity: sha512-G2aQ676fLBPnYhRi5lsARoL4hbtc/sx6fVzO7p44AB+1xQXo2UuiRgv7K26UdijrNzmuQprmJ121n3rdjBk1CA==} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.5.0 + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vue-bundle-renderer@2.4.0: + resolution: {integrity: sha512-IxHopQZgzTGBiuGERrQrAS7Lr3dCv+qxvgirEgCUFGAD4gYNfiaGYzC1DDojeZmJAmehp9gG8+17PGuVP6Ab2Q==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-devtools-stub@0.1.0: + resolution: {integrity: sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==} + + vue-i18n@10.0.8: + resolution: {integrity: sha512-mIjy4utxMz9lMMo6G9vYePv7gUFt4ztOMhY9/4czDJxZ26xPeJ49MAGa9wBAE3XuXbYCrtVPmPxNjej7JJJkZQ==} + engines: {node: '>= 16'} + deprecated: v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html + peerDependencies: + vue: ^3.0.0 + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 + + vue@3.5.42: + resolution: {integrity: sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@6.0.1: + resolution: {integrity: sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + wsl-utils@1.0.0: + resolution: {integrity: sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==} + engines: {node: '>=20'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml-eslint-parser@1.3.2: + resolution: {integrity: sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==} + engines: {node: ^14.17.0 || >=16.0.0} + + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs@18.1.0: + resolution: {integrity: sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.1: + resolution: {integrity: sha512-mxW3qiSnl+GRxXsaUMzv2Mbada1Y8CDltET9UxejDQe6DBYlSekghl5U5K0ReAikcHDi0G1vKZEmmo/NWAGKLA==} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + +snapshots: + + '@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.29.7': {} + + '@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.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.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-annotate-as-pure@7.29.7': + dependencies: + '@babel/types': 7.29.8 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/traverse': 7.29.8 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-member-expression-to-functions@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@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-optimise-call-expression@7.29.7': + dependencies: + '@babel/types': 7.29.8 + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7 + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + transitivePeerDependencies: + - supports-color + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@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.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bomb.sh/tab@0.0.19(cac@6.7.14)(citty@0.2.2)': + optionalDependencies: + cac: 6.7.14 + citty: 0.2.2 + + '@cacheable/memory@2.2.0': + dependencies: + '@cacheable/utils': 2.5.0 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 + + '@cacheable/utils@2.5.0': + dependencies: + hashery: 1.5.1 + keyv: 5.6.0 + + '@clack/core@1.5.1': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.8.1': + dependencies: + '@clack/core': 1.5.1 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@cloudflare/kv-asset-handler@0.4.2': {} + + '@colordx/core@5.8.0': {} + + '@dxup/nuxt@0.5.10(esbuild@0.28.2)(magicast@0.5.5)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))': + dependencies: + '@dxup/unimport': 0.1.2 + '@nuxt/kit': 4.5.2(magic-string@1.4.1)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))) + '@vue/compiler-dom': 3.5.42 + chokidar: 5.0.0 + knitwork: 1.3.0 + magic-string: 1.4.1 + pathe: 2.0.3 + tinyglobby: 0.2.17 + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + transitivePeerDependencies: + - '@farmfe/core' + - '@rsbuild/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - magicast + - oxc-parser + - rolldown + - rollup + - unloader + - vite + - webpack + + '@dxup/unimport@0.1.2': {} + + '@emnapi/core@1.11.3': + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@eslint-community/eslint-utils@4.10.1(eslint@10.10.0(jiti@2.7.0))': + dependencies: + eslint: 10.10.0(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.5': + dependencies: + '@eslint/object-schema': 3.0.5 + debug: 4.4.3 + minimatch: 10.2.6 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.7.0': + dependencies: + '@eslint/core': 1.2.1 + + '@eslint/core@1.2.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/object-schema@3.0.5': {} + + '@eslint/plugin-kit@0.7.3': + dependencies: + '@eslint/core': 1.2.1 + levn: 0.4.1 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@intlify/bundle-utils@10.0.1(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)))': + dependencies: + '@intlify/message-compiler': 11.4.12 + '@intlify/shared': 11.4.12 + acorn: 8.18.0 + escodegen: 2.1.0 + estree-walker: 2.0.2 + jsonc-eslint-parser: 2.4.2 + mlly: 1.8.2 + source-map-js: 1.2.1 + yaml-eslint-parser: 1.3.2 + optionalDependencies: + vue-i18n: 10.0.8(vue@3.5.42(typescript@5.9.3)) + + '@intlify/core-base@10.0.8': + dependencies: + '@intlify/message-compiler': 10.0.8 + '@intlify/shared': 10.0.8 + + '@intlify/core@10.0.8': + dependencies: + '@intlify/core-base': 10.0.8 + '@intlify/shared': 10.0.8 + + '@intlify/h3@0.6.1': + dependencies: + '@intlify/core': 10.0.8 + '@intlify/utils': 0.13.0 + + '@intlify/message-compiler@10.0.8': + dependencies: + '@intlify/shared': 10.0.8 + source-map-js: 1.2.1 + + '@intlify/message-compiler@11.4.12': + dependencies: + '@intlify/shared': 11.4.12 + source-map-js: 1.2.1 + + '@intlify/shared@10.0.8': {} + + '@intlify/shared@11.4.12': {} + + '@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(rollup@4.63.3)(typescript@5.9.3)(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.10.0(jiti@2.7.0)) + '@intlify/bundle-utils': 10.0.1(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3))) + '@intlify/shared': 11.4.12 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.4.12)(@vue/compiler-dom@3.5.42)(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)) + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(typescript@5.9.3) + debug: 4.4.3 + fast-glob: 3.3.3 + js-yaml: 4.3.2 + json5: 2.2.3 + pathe: 1.1.2 + picocolors: 1.1.1 + source-map-js: 1.2.1 + unplugin: 1.16.1 + vue: 3.5.42(typescript@5.9.3) + optionalDependencies: + vue-i18n: 10.0.8(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/compiler-dom' + - eslint + - rollup + - supports-color + - typescript + + '@intlify/utils@0.13.0': {} + + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.4.12)(@vue/compiler-dom@3.5.42)(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@babel/parser': 7.29.8 + optionalDependencies: + '@intlify/shared': 11.4.12 + '@vue/compiler-dom': 3.5.42 + vue: 3.5.42(typescript@5.9.3) + vue-i18n: 10.0.8(vue@3.5.42(typescript@5.9.3)) + + '@ioredis/commands@1.10.0': {} + + '@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 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.6.0 + + '@keyv/bigmap@1.3.1(keyv@5.6.0)': + dependencies: + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} + + '@kwsites/file-exists@1.1.1': + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@kwsites/promise-deferred@1.1.1': {} + + '@mapbox/node-pre-gyp@2.0.3': + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.8.5 + tar: 7.5.22 + transitivePeerDependencies: + - encoding + - supports-color + + '@miyaneee/rollup-plugin-json5@1.2.0(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + json5: 2.2.3 + rollup: 4.63.3 + + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.3 + + '@nuxt/cli@3.37.0(@nuxt/schema@3.21.11)(cac@6.7.14)(magicast@0.5.5)': + dependencies: + '@bomb.sh/tab': 0.0.19(cac@6.7.14)(citty@0.2.2) + '@clack/prompts': 1.8.1 + c12: 3.3.4(magicast@0.5.5) + citty: 0.2.2 + confbox: 0.2.4 + consola: 3.4.2 + debug: 4.4.3 + defu: 6.1.7 + exsolve: 1.1.1 + fuse.js: 7.5.0 + fzf: 0.5.2 + giget: 3.3.1 + jiti: 2.7.0 + listhen: 1.10.1(srvx@0.11.22) + nypm: 0.6.10 + ofetch: 1.5.1 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + scule: 1.3.0 + semver: 7.8.5 + srvx: 0.11.22 + std-env: 4.2.0 + tinyclip: 0.1.15 + tinyexec: 1.3.1 + ufo: 1.6.4 + youch: 4.1.1 + optionalDependencies: + '@nuxt/schema': 3.21.11 + transitivePeerDependencies: + - '@parcel/watcher' + - cac + - commander + - magicast + - supports-color + + '@nuxt/devalue@2.0.2': {} + + '@nuxt/devtools-kit@3.4.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))': + dependencies: + '@nuxt/kit': 4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)) + execa: 8.0.1 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + + '@nuxt/devtools-wizard@3.4.2': + dependencies: + '@clack/prompts': 1.8.1 + consola: 3.4.2 + diff: 8.0.4 + execa: 8.0.1 + magicast: 0.5.5 + pathe: 2.0.3 + pkg-types: 2.3.3 + semver: 7.8.5 + + '@nuxt/devtools@3.4.2(db0@0.3.4)(ioredis@5.11.1)(magic-string@0.30.21)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@nuxt/devtools-kit': 3.4.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + '@nuxt/devtools-wizard': 3.4.2 + '@nuxt/kit': 4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)) + '@vue/devtools-core': 8.2.1(vue@3.5.42(typescript@5.9.3)) + '@vue/devtools-kit': 8.2.1 + birpc: 4.2.0 + consola: 3.4.2 + destr: 2.0.5 + error-stack-parser-es: 2.0.1 + execa: 8.0.1 + fast-npm-meta: 2.2.0 + get-port-please: 3.2.0 + hookable: 6.1.1 + image-meta: 0.2.2 + is-installed-globally: 1.0.0 + launch-editor: 2.14.1 + local-pkg: 1.2.1 + magicast: 0.5.5 + nypm: 0.6.10 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + semver: 7.8.5 + simple-git: 3.36.0 + sirv: 3.0.2 + structured-clone-es: 2.0.1 + tinyglobby: 0.2.17 + unstorage: 1.17.5(db0@0.3.4)(ioredis@5.11.1) + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-plugin-inspect: 11.4.1(@nuxt/kit@4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + vite-plugin-vue-tracer: 1.5.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + which: 6.0.1 + ws: 8.21.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - idb-keyval + - ioredis + - magic-string + - oxc-parser + - rolldown + - supports-color + - unplugin + - uploadthing + - utf-8-validate + - vue + + '@nuxt/kit@3.21.11(magicast@0.5.5)': + dependencies: + c12: 3.3.4(magicast@0.5.5) + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + errx: 0.1.2 + exsolve: 1.1.1 + ignore: 7.0.9 + jiti: 2.7.0 + klona: 2.0.6 + knitwork: 1.3.0 + mlly: 1.8.2 + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.3 + rc9: 3.1.0 + scule: 1.3.0 + semver: 7.8.5 + tinyglobby: 0.2.17 + ufo: 1.6.4 + unctx: 2.5.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + + '@nuxt/kit@4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3))': + dependencies: + c12: 3.3.4(magicast@0.5.5) + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + errx: 0.1.2 + exsolve: 1.1.1 + ignore: 7.0.9 + jiti: 2.7.0 + klona: 2.0.6 + mlly: 1.8.2 + nostics: 1.2.0 + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.3 + rc9: 3.1.0 + scule: 1.3.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + unctx: 3.0.1(magic-string@0.30.21)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)) + untyped: 2.0.0 + verkit: 0.3.2 + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + + '@nuxt/kit@4.5.2(magic-string@1.4.1)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))': + dependencies: + c12: 3.3.4(magicast@0.5.5) + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + errx: 0.1.2 + exsolve: 1.1.1 + ignore: 7.0.9 + jiti: 2.7.0 + klona: 2.0.6 + mlly: 1.8.2 + nostics: 1.2.0 + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.3 + rc9: 3.1.0 + scule: 1.3.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + unctx: 3.0.1(magic-string@1.4.1)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))) + untyped: 2.0.0 + verkit: 0.3.2 + transitivePeerDependencies: + - magic-string + - magicast + - oxc-parser + - rolldown + - unplugin + + '@nuxt/nitro-server@3.21.11(db0@0.3.4)(esbuild@0.28.2)(ioredis@5.11.1)(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))(oxc-parser@0.143.0)(rollup@4.63.3)(srvx@0.11.22)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))': + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@unhead/vue': 2.1.17(vue@3.5.42(typescript@5.9.3)) + '@vue/shared': 3.5.42 + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + devalue: 5.9.2 + errx: 0.1.2 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + h3: 1.15.11 + impound: 1.2.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + klona: 2.0.6 + mocked-exports: 0.1.1 + nitropack: 2.13.4(oxc-parser@0.143.0)(srvx@0.11.22)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + nuxt: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1) + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.3 + rou3: 0.9.2 + std-env: 4.2.0 + ufo: 1.6.4 + unctx: 2.5.0 + unstorage: 1.17.5(db0@0.3.4)(ioredis@5.11.1) + vue: 3.5.42(typescript@5.9.3) + vue-bundle-renderer: 2.4.0 + vue-devtools-stub: 0.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@farmfe/core' + - '@libsql/client' + - '@netlify/blobs' + - '@parcel/watcher' + - '@planetscale/database' + - '@rsbuild/core' + - '@rspack/core' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bun-types-no-globals + - db0 + - drizzle-orm + - encoding + - esbuild + - idb-keyval + - ioredis + - magicast + - mysql2 + - oxc-parser + - react-native-b4a + - rolldown + - rollup + - sqlite3 + - srvx + - supports-color + - typescript + - unloader + - uploadthing + - vite + - webpack + - xml2js + + '@nuxt/nitro-server@3.21.11(db0@0.3.4)(esbuild@0.28.2)(ioredis@5.11.1)(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1))(oxc-parser@0.143.0)(rollup@4.63.3)(typescript@5.9.3)': + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@unhead/vue': 2.1.17(vue@3.5.42(typescript@5.9.3)) + '@vue/shared': 3.5.42 + consola: 3.4.2 + defu: 6.1.7 + destr: 2.0.5 + devalue: 5.9.2 + errx: 0.1.2 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + h3: 1.15.11 + impound: 1.2.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + klona: 2.0.6 + mocked-exports: 0.1.1 + nitropack: 2.13.4(oxc-parser@0.143.0)(srvx@0.11.22)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + nuxt: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1) + ohash: 2.0.12 + pathe: 2.0.3 + pkg-types: 2.3.3 + rou3: 0.9.2 + std-env: 4.2.0 + ufo: 1.6.4 + unctx: 2.5.0 + unstorage: 1.17.5(db0@0.3.4)(ioredis@5.11.1) + vue: 3.5.42(typescript@5.9.3) + vue-bundle-renderer: 2.4.0 + vue-devtools-stub: 0.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@farmfe/core' + - '@libsql/client' + - '@netlify/blobs' + - '@parcel/watcher' + - '@planetscale/database' + - '@rsbuild/core' + - '@rspack/core' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bun-types-no-globals + - db0 + - drizzle-orm + - encoding + - esbuild + - idb-keyval + - ioredis + - magicast + - mysql2 + - oxc-parser + - react-native-b4a + - rolldown + - rollup + - sqlite3 + - srvx + - supports-color + - typescript + - unloader + - uploadthing + - vite + - webpack + - xml2js + + '@nuxt/schema@3.21.11': + dependencies: + '@vue/shared': 3.5.42 + defu: 6.1.7 + pathe: 2.0.3 + pkg-types: 2.3.3 + std-env: 4.2.0 + + '@nuxt/telemetry@2.9.1(@nuxt/kit@3.21.11(magicast@0.5.5))': + dependencies: + '@nuxt/kit': 3.21.11(magicast@0.5.5) + citty: 0.2.2 + consola: 3.4.2 + rc9: 3.1.0 + std-env: 4.2.0 + + '@nuxt/vite-builder@3.21.11(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))(yaml@2.9.1)': + dependencies: + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@rollup/plugin-replace': 6.0.3(rollup@4.63.3) + '@vitejs/plugin-vue': 6.0.9(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': 5.1.6(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + autoprefixer: 10.6.1(postcss@8.5.28) + consola: 3.4.2 + cssnano: 7.1.9(postcss@8.5.28) + defu: 6.1.7 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + externality: 1.0.2 + generic-names: 4.0.0 + get-port-please: 3.2.0 + jiti: 2.7.0 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + mocked-exports: 0.1.1 + nuxt: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1) + nypm: 0.6.10 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + postcss: 8.5.28 + seroval: 1.6.7 + std-env: 4.2.0 + ufo: 1.6.4 + unenv: 2.0.0-rc.24 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-node: 5.3.0(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-plugin-checker: 0.14.5(eslint@10.10.0(jiti@2.7.0))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + vue: 3.5.42(typescript@5.9.3) + vue-bundle-renderer: 2.4.0 + optionalDependencies: + rollup-plugin-visualizer: 7.1.1(rollup@4.63.3) + transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - oxlint + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - vue-tsc + - yaml + + '@nuxt/vite-builder@3.21.11(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1))(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))(yaml@2.9.1)': + dependencies: + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@rollup/plugin-replace': 6.0.3(rollup@4.63.3) + '@vitejs/plugin-vue': 6.0.9(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': 5.1.6(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + autoprefixer: 10.6.1(postcss@8.5.28) + consola: 3.4.2 + cssnano: 7.1.9(postcss@8.5.28) + defu: 6.1.7 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + externality: 1.0.2 + generic-names: 4.0.0 + get-port-please: 3.2.0 + jiti: 2.7.0 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + mocked-exports: 0.1.1 + nuxt: 3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1) + nypm: 0.6.10 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + postcss: 8.5.28 + seroval: 1.6.7 + std-env: 4.2.0 + ufo: 1.6.4 + unenv: 2.0.0-rc.24 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-node: 5.3.0(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-plugin-checker: 0.14.5(eslint@10.10.0(jiti@2.7.0))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + vue: 3.5.42(typescript@5.9.3) + vue-bundle-renderer: 2.4.0 + optionalDependencies: + rollup-plugin-visualizer: 7.1.1(rollup@4.63.3) + transitivePeerDependencies: + - '@biomejs/biome' + - '@types/node' + - eslint + - less + - lightningcss + - magicast + - meow + - optionator + - oxlint + - rollup + - sass + - sass-embedded + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - vue-tsc + - yaml + + '@nuxtjs/i18n@9.5.6(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(rollup@4.63.3)(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@intlify/h3': 0.6.1 + '@intlify/shared': 10.0.8 + '@intlify/unplugin-vue-i18n': 6.0.8(@vue/compiler-dom@3.5.42)(eslint@10.10.0(jiti@2.7.0))(rollup@4.63.3)(typescript@5.9.3)(vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)) + '@intlify/utils': 0.13.0 + '@miyaneee/rollup-plugin-json5': 1.2.0(rollup@4.63.3) + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@oxc-parser/wasm': 0.60.0 + '@rollup/plugin-yaml': 4.1.2(rollup@4.63.3) + '@vue/compiler-sfc': 3.5.42 + debug: 4.4.3 + defu: 6.1.7 + esbuild: 0.25.12 + estree-walker: 3.0.3 + h3: 1.15.11 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + oxc-parser: 0.70.0 + pathe: 2.0.3 + typescript: 5.9.3 + ufo: 1.6.4 + unplugin: 2.3.11 + unplugin-vue-router: 0.12.0(vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)) + vue-i18n: 10.0.8(vue@3.5.42(typescript@5.9.3)) + vue-router: 4.6.4(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/compiler-dom' + - eslint + - magicast + - petite-vue-i18n + - rollup + - supports-color + - vue + + '@oxc-minify/binding-android-arm-eabi@0.143.0': + optional: true + + '@oxc-minify/binding-android-arm64@0.143.0': + optional: true + + '@oxc-minify/binding-darwin-arm64@0.143.0': + optional: true + + '@oxc-minify/binding-darwin-x64@0.143.0': + optional: true + + '@oxc-minify/binding-freebsd-x64@0.143.0': + optional: true + + '@oxc-minify/binding-linux-arm-gnueabihf@0.143.0': + optional: true + + '@oxc-minify/binding-linux-arm-musleabihf@0.143.0': + optional: true + + '@oxc-minify/binding-linux-arm64-gnu@0.143.0': + optional: true + + '@oxc-minify/binding-linux-arm64-musl@0.143.0': + optional: true + + '@oxc-minify/binding-linux-ppc64-gnu@0.143.0': + optional: true + + '@oxc-minify/binding-linux-riscv64-gnu@0.143.0': + optional: true + + '@oxc-minify/binding-linux-riscv64-musl@0.143.0': + optional: true + + '@oxc-minify/binding-linux-s390x-gnu@0.143.0': + optional: true + + '@oxc-minify/binding-linux-x64-gnu@0.143.0': + optional: true + + '@oxc-minify/binding-linux-x64-musl@0.143.0': + optional: true + + '@oxc-minify/binding-openharmony-arm64@0.143.0': + optional: true + + '@oxc-minify/binding-win32-arm64-msvc@0.143.0': + optional: true + + '@oxc-minify/binding-win32-ia32-msvc@0.143.0': + optional: true + + '@oxc-minify/binding-win32-x64-msvc@0.143.0': + optional: true + + '@oxc-parser/binding-android-arm-eabi@0.143.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.143.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.143.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.70.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.143.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.70.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.143.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.70.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.143.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.70.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.143.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.70.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.143.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.70.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.143.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.70.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.143.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.143.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.70.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.143.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.143.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.70.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.143.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.70.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.143.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.70.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.143.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.70.0': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.143.0': + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.70.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.143.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.143.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.70.0': + optional: true + + '@oxc-parser/wasm@0.60.0': + dependencies: + '@oxc-project/types': 0.60.0 + + '@oxc-project/types@0.143.0': {} + + '@oxc-project/types@0.60.0': {} + + '@oxc-project/types@0.70.0': {} + + '@oxc-transform/binding-android-arm-eabi@0.143.0': + optional: true + + '@oxc-transform/binding-android-arm64@0.143.0': + optional: true + + '@oxc-transform/binding-darwin-arm64@0.143.0': + optional: true + + '@oxc-transform/binding-darwin-x64@0.143.0': + optional: true + + '@oxc-transform/binding-freebsd-x64@0.143.0': + optional: true + + '@oxc-transform/binding-linux-arm-gnueabihf@0.143.0': + optional: true + + '@oxc-transform/binding-linux-arm-musleabihf@0.143.0': + optional: true + + '@oxc-transform/binding-linux-arm64-gnu@0.143.0': + optional: true + + '@oxc-transform/binding-linux-arm64-musl@0.143.0': + optional: true + + '@oxc-transform/binding-linux-ppc64-gnu@0.143.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-gnu@0.143.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-musl@0.143.0': + optional: true + + '@oxc-transform/binding-linux-s390x-gnu@0.143.0': + optional: true + + '@oxc-transform/binding-linux-x64-gnu@0.143.0': + optional: true + + '@oxc-transform/binding-linux-x64-musl@0.143.0': + optional: true + + '@oxc-transform/binding-openharmony-arm64@0.143.0': + optional: true + + '@oxc-transform/binding-win32-arm64-msvc@0.143.0': + optional: true + + '@oxc-transform/binding-win32-ia32-msvc@0.143.0': + optional: true + + '@oxc-transform/binding-win32-x64-msvc@0.143.0': + optional: true + + '@parcel/watcher-wasm@2.6.0': + dependencies: + is-glob: 4.0.3 + picomatch: 4.0.7 + + '@pinia/nuxt@0.10.1(magicast@0.5.5)(pinia@2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)))': + dependencies: + '@nuxt/kit': 3.21.11(magicast@0.5.5) + pinia: 2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - magicast + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@polka/url@1.0.0-next.29': {} + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.7.0': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/plugin-alias@6.0.0(rollup@4.63.3)': + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-commonjs@29.0.3(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.7) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.7 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-inject@5.0.5(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + estree-walker: 2.0.2 + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-json@6.1.0(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-node-resolve@16.0.3(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.12 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-replace@6.0.3(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-terser@1.0.0(rollup@4.63.3)': + dependencies: + serialize-javascript: 7.1.1 + smob: 1.6.2 + terser: 5.51.2 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/plugin-yaml@4.1.2(rollup@4.63.3)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + js-yaml: 4.3.2 + tosource: 2.0.0-alpha.3 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/pluginutils@5.4.0(rollup@4.63.3)': + dependencies: + '@types/estree': 1.0.9 + estree-walker: 2.0.2 + picomatch: 4.0.7 + optionalDependencies: + rollup: 4.63.3 + + '@rollup/rollup-android-arm-eabi@4.63.3': + optional: true + + '@rollup/rollup-android-arm64@4.63.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.3': + optional: true + + '@rollup/rollup-darwin-x64@4.63.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.63.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.63.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.63.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.63.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.63.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.63.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.63.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.63.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.63.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.63.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.63.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.63.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.63.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.63.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.63.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.63.3': + optional: true + + '@simple-git/args-pathspec@1.0.3': {} + + '@simple-git/argv-parser@1.1.1': + dependencies: + '@simple-git/args-pathspec': 1.0.3 + + '@sindresorhus/is@7.2.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@speed-highlight/core@1.2.24': {} + + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/resolve@1.20.2': {} + + '@typescript-eslint/project-service@8.70.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@5.9.3) + '@typescript-eslint/types': 8.70.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + + '@typescript-eslint/tsconfig-utils@8.70.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/types@8.70.0': {} + + '@typescript-eslint/typescript-estree@8.70.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.70.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@5.9.3) + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + eslint-visitor-keys: 5.0.1 + + '@unhead/vue@2.1.17(vue@3.5.42(typescript@5.9.3))': + dependencies: + hookable: 6.1.1 + unhead: 2.1.17 + vue: 3.5.42(typescript@5.9.3) + + '@vercel/nft@1.11.0(rollup@4.63.3)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + acorn: 8.18.0 + acorn-import-attributes: 1.9.5(acorn@8.18.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 13.0.6 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.7 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vitejs/plugin-vue-jsx@5.1.6(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.1 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.7) + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vue: 3.5.42(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@6.0.9(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vue: 3.5.42(typescript@5.9.3) + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@vue-macros/common@1.16.1(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@vue/compiler-sfc': 3.5.42 + ast-kit: 1.4.3 + local-pkg: 1.2.1 + magic-string-ast: 0.7.1 + pathe: 2.0.3 + picomatch: 4.0.7 + optionalDependencies: + vue: 3.5.42(typescript@5.9.3) + + '@vue-macros/common@3.1.4(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@vue/compiler-sfc': 3.5.42 + ast-kit: 2.2.0 + local-pkg: 1.2.1 + magic-string-ast: 1.0.3 + unplugin-utils: 0.3.2 + optionalDependencies: + vue: 3.5.42(typescript@5.9.3) + + '@vue/babel-helper-vue-transform-on@2.0.1': {} + + '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.7)': + dependencies: + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@vue/babel-helper-vue-transform-on': 2.0.1 + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.7) + '@vue/shared': 3.5.42 + optionalDependencies: + '@babel/core': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.7)': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/parser': 7.29.8 + '@vue/compiler-sfc': 3.5.42 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.42': + dependencies: + '@babel/parser': 7.29.8 + '@vue/shared': 3.5.42 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.42': + dependencies: + '@vue/compiler-core': 3.5.42 + '@vue/shared': 3.5.42 + + '@vue/compiler-sfc@3.5.42': + dependencies: + '@babel/parser': 7.29.8 + '@vue/compiler-core': 3.5.42 + '@vue/compiler-dom': 3.5.42 + '@vue/compiler-ssr': 3.5.42 + '@vue/shared': 3.5.42 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.28 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.42': + dependencies: + '@vue/compiler-dom': 3.5.42 + '@vue/shared': 3.5.42 + + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-core@8.2.1(vue@3.5.42(typescript@5.9.3))': + dependencies: + '@vue/devtools-kit': 8.2.1 + '@vue/devtools-shared': 8.2.1 + vue: 3.5.42(typescript@5.9.3) + + '@vue/devtools-kit@8.2.1': + dependencies: + '@vue/devtools-shared': 8.2.1 + birpc: 2.9.0 + hookable: 5.5.3 + perfect-debounce: 2.1.0 + + '@vue/devtools-shared@8.2.1': {} + + '@vue/language-core@3.3.11': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.42 + '@vue/shared': 3.5.42 + alien-signals: 3.2.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.7 + + '@vue/reactivity@3.5.42': + dependencies: + '@vue/shared': 3.5.42 + + '@vue/runtime-core@3.5.42': + dependencies: + '@vue/reactivity': 3.5.42 + '@vue/shared': 3.5.42 + + '@vue/runtime-dom@3.5.42': + dependencies: + '@vue/reactivity': 3.5.42 + '@vue/runtime-core': 3.5.42 + '@vue/shared': 3.5.42 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.42': + dependencies: + '@vue/compiler-ssr': 3.5.42 + '@vue/runtime-dom': 3.5.42 + '@vue/shared': 3.5.42 + + '@vue/shared@3.5.42': {} + + abbrev@3.0.1: {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-import-attributes@1.9.5(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn-jsx@5.3.2(acorn@8.18.0): + dependencies: + acorn: 8.18.0 + + acorn@8.18.0: {} + + agent-base@7.1.4: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + alien-signals@3.2.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.3.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.4.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.18.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.2.1 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + argparse@2.0.1: {} + + ast-kit@1.4.3: + dependencies: + '@babel/parser': 7.29.8 + pathe: 2.0.3 + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.29.8 + pathe: 2.0.3 + + ast-walker-scope@0.6.2: + dependencies: + '@babel/parser': 7.29.8 + ast-kit: 1.4.3 + + ast-walker-scope@0.8.3: + dependencies: + '@babel/parser': 7.29.8 + ast-kit: 2.2.0 + + async-sema@3.1.1: {} + + async@3.2.6: {} + + autoprefixer@10.6.1(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + caniuse-lite: 1.0.30001810 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + b4a@1.9.0: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + bare-events@2.9.2: {} + + bare-fs@4.8.1: + dependencies: + bare-events: 2.9.2 + bare-path: 3.1.2 + bare-stream: 2.13.4(bare-events@2.9.2) + bare-url: 2.5.4 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + bare-path@3.1.2: {} + + bare-stream@2.13.4(bare-events@2.9.2): + dependencies: + b4a: 1.9.0 + streamx: 2.28.1 + teex: 1.0.1 + optionalDependencies: + bare-events: 2.9.2 + transitivePeerDependencies: + - react-native-b4a + + bare-url@2.5.4: + dependencies: + bare-path: 3.1.2 + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.11.24: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + birpc@2.9.0: {} + + birpc@4.2.0: {} + + boolbase@1.0.0: {} + + brace-expansion@2.1.7: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.29.0: + dependencies: + baseline-browser-mapping: 2.11.24 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.430 + node-releases: 2.0.55 + update-browserslist-db: 1.3.3(browserslist@4.29.0) + + buffer-crc32@1.0.0: {} + + buffer-from@1.1.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + c12@3.3.4(magicast@0.5.5): + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.1.1 + giget: 3.3.1 + jiti: 2.7.0 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + rc9: 3.1.0 + optionalDependencies: + magicast: 0.5.5 + + cac@6.7.14: {} + + cac@7.0.0: {} + + cacheable@2.5.0: + dependencies: + '@cacheable/memory': 2.2.0 + '@cacheable/utils': 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.29.0 + caniuse-lite: 1.0.30001810 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001810: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + + chownr@3.0.0: {} + + citty@0.1.6: + dependencies: + consola: 3.4.2 + + citty@0.2.2: {} + + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + + cluster-key-slot@1.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commander@11.1.0: {} + + commander@2.20.3: {} + + commondir@1.0.1: {} + + compatx@0.2.0: {} + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + confbox@0.3.1: {} + + consola@3.4.2: {} + + convert-source-map@2.0.0: {} + + cookie-es@1.2.3: {} + + cookie-es@2.0.1: {} + + cookie-es@3.1.1: {} + + core-util-is@1.0.3: {} + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + + croner@10.0.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + crossws@0.4.12(srvx@0.11.22): + optionalDependencies: + srvx: 0.11.22 + + css-declaration-sorter@7.4.0(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@7.0.0: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@7.0.17(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + css-declaration-sorter: 7.4.0(postcss@8.5.28) + cssnano-utils: 5.0.3(postcss@8.5.28) + postcss: 8.5.28 + postcss-calc: 10.1.1(postcss@8.5.28) + postcss-colormin: 7.0.10(postcss@8.5.28) + postcss-convert-values: 7.0.12(postcss@8.5.28) + postcss-discard-comments: 7.0.8(postcss@8.5.28) + postcss-discard-duplicates: 7.0.4(postcss@8.5.28) + postcss-discard-empty: 7.0.3(postcss@8.5.28) + postcss-discard-overridden: 7.0.3(postcss@8.5.28) + postcss-merge-longhand: 7.0.7(postcss@8.5.28) + postcss-merge-rules: 7.0.11(postcss@8.5.28) + postcss-minify-font-values: 7.0.3(postcss@8.5.28) + postcss-minify-gradients: 7.0.5(postcss@8.5.28) + postcss-minify-params: 7.0.9(postcss@8.5.28) + postcss-minify-selectors: 7.1.2(postcss@8.5.28) + postcss-normalize-charset: 7.0.3(postcss@8.5.28) + postcss-normalize-display-values: 7.0.3(postcss@8.5.28) + postcss-normalize-positions: 7.0.4(postcss@8.5.28) + postcss-normalize-repeat-style: 7.0.4(postcss@8.5.28) + postcss-normalize-string: 7.0.3(postcss@8.5.28) + postcss-normalize-timing-functions: 7.0.3(postcss@8.5.28) + postcss-normalize-unicode: 7.0.9(postcss@8.5.28) + postcss-normalize-url: 7.0.3(postcss@8.5.28) + postcss-normalize-whitespace: 7.0.3(postcss@8.5.28) + postcss-ordered-values: 7.0.4(postcss@8.5.28) + postcss-reduce-initial: 7.0.9(postcss@8.5.28) + postcss-reduce-transforms: 7.0.3(postcss@8.5.28) + postcss-svgo: 7.1.3(postcss@8.5.28) + postcss-unique-selectors: 7.0.7(postcss@8.5.28) + + cssnano-utils@5.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + cssnano@7.1.9(postcss@8.5.28): + dependencies: + cssnano-preset-default: 7.0.17(postcss@8.5.28) + lilconfig: 3.1.3 + postcss: 8.5.28 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + csstype@3.2.3: {} + + db0@0.3.4: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-lazy-prop@3.0.0: {} + + defu@6.1.7: {} + + denque@2.1.0: {} + + depd@2.0.0: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + devalue@5.9.2: {} + + diff@8.0.4: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-prop@10.2.0: + dependencies: + type-fest: 5.9.0 + + dotenv@17.4.2: {} + + duplexer@0.1.2: {} + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.430: {} + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.25.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@4.5.0: {} + + entities@7.0.1: {} + + error-stack-parser-es@1.0.5: {} + + error-stack-parser-es@2.0.1: {} + + errx@0.1.2: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.3.2: {} + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@10.10.0(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.10.0(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.3 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 11.1.5 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.6 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@11.2.0: + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + eslint-visitor-keys: 5.0.1 + + espree@9.6.1: + dependencies: + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + events-universal@1.0.1: + dependencies: + bare-events: 2.9.2 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + exsolve@1.1.1: {} + + externality@1.0.2: + dependencies: + enhanced-resolve: 5.25.1 + mlly: 1.8.2 + pathe: 1.1.2 + ufo: 1.6.4 + + fast-deep-equal@3.1.3: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-npm-meta@2.2.0: + dependencies: + cac: 7.0.0 + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + + fastq@1.20.3: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + file-entry-cache@11.1.5: + dependencies: + flat-cache: 6.1.23 + + file-uri-to-path@1.0.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@6.1.23: + dependencies: + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 + + flatted@3.4.4: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@5.3.4: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + fuse.js@7.5.0: {} + + fzf@0.5.2: {} + + generic-names@4.0.0: + dependencies: + loader-utils: 3.3.1 + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.6.0: {} + + get-port-please@3.2.0: {} + + get-stream@8.0.1: {} + + giget@3.3.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + 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 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + globby@16.2.4: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.9 + is-path-inside: 4.0.0 + micromatch: 4.0.8 + slash: 5.1.0 + unicorn-magic: 0.4.0 + + graceful-fs@4.2.11: {} + + gzip-size@7.0.0: + dependencies: + duplexer: 0.1.2 + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.5 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + + hashery@1.5.1: + dependencies: + hookified: 1.15.1 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hookable@5.5.3: {} + + hookable@6.1.1: {} + + hookified@1.15.1: {} + + hookified@2.2.0: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-shutdown@1.2.2: {} + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + httpxy@0.5.5: {} + + human-signals@5.0.0: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.9: {} + + image-meta@0.2.2: {} + + impound@1.2.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + es-module-lexer: 2.3.2 + pathe: 2.0.3 + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin-utils: 0.3.2 + transitivePeerDependencies: + - '@farmfe/core' + - '@rsbuild/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup + - unloader + - vite + - webpack + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ini@4.1.1: {} + + ioredis@5.11.1: + dependencies: + '@ioredis/commands': 1.10.0 + cluster-key-slot: 1.1.1 + debug: 4.4.3 + denque: 2.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + iron-webcrypto@1.2.1: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + is-docker@3.0.0: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-installed-globally@1.0.0: + dependencies: + global-directory: 4.0.1 + is-path-inside: 4.0.0 + + is-module@1.0.0: {} + + is-number@7.0.0: {} + + is-path-inside@4.0.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.9 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + isexe@4.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@2.7.0: {} + + js-tokens@10.0.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.3.2: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonc-eslint-parser@2.4.2: + dependencies: + acorn: 8.18.0 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + semver: 7.8.5 + + keyv@5.6.0: + dependencies: + '@keyv/serialize': 1.1.1 + + kleur@4.1.5: {} + + klona@2.0.6: {} + + knitwork@1.3.0: {} + + launch-editor@2.14.1: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.10.0 + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + listhen@1.10.1(srvx@0.11.22): + dependencies: + '@parcel/watcher-wasm': 2.6.0 + citty: 0.2.2 + consola: 3.4.2 + crossws: 0.4.12(srvx@0.11.22) + defu: 6.1.7 + get-port-please: 3.2.0 + h3: 1.15.11 + http-shutdown: 1.2.2 + jiti: 2.7.0 + node-forge: 1.4.0 + pathe: 2.0.3 + std-env: 4.2.0 + tinyclip: 0.1.15 + ufo: 1.6.4 + untun: 0.2.2 + uqr: 0.1.3 + transitivePeerDependencies: + - srvx + + loader-utils@3.3.1: {} + + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.3 + quansync: 0.2.11 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.memoize@4.1.2: {} + + lodash.uniq@4.5.0: {} + + lodash@4.18.1: {} + + lru-cache@10.4.3: {} + + lru-cache@11.5.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string-ast@0.7.1: + dependencies: + magic-string: 0.30.21 + + magic-string-ast@1.0.3: + dependencies: + magic-string: 0.30.21 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + magic-string@1.4.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + magicast@0.5.5: + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + source-map-js: 1.2.1 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@4.1.0: {} + + mimic-fn@4.0.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.7 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.7 + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mlly@1.8.2: + dependencies: + acorn: 8.18.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + mocked-exports@0.1.1: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.19: {} + + nanotar@0.3.0: {} + + natural-compare@1.4.0: {} + + nitropack@2.13.4(oxc-parser@0.143.0)(srvx@0.11.22)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@cloudflare/kv-asset-handler': 0.4.2 + '@rollup/plugin-alias': 6.0.0(rollup@4.63.3) + '@rollup/plugin-commonjs': 29.0.3(rollup@4.63.3) + '@rollup/plugin-inject': 5.0.5(rollup@4.63.3) + '@rollup/plugin-json': 6.1.0(rollup@4.63.3) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.63.3) + '@rollup/plugin-replace': 6.0.3(rollup@4.63.3) + '@rollup/plugin-terser': 1.0.0(rollup@4.63.3) + '@vercel/nft': 1.11.0(rollup@4.63.3) + archiver: 7.0.1 + c12: 3.3.4(magicast@0.5.5) + chokidar: 5.0.0 + citty: 0.2.2 + compatx: 0.2.0 + confbox: 0.2.4 + consola: 3.4.2 + cookie-es: 2.0.1 + croner: 10.0.1 + crossws: 0.3.5 + db0: 0.3.4 + defu: 6.1.7 + destr: 2.0.5 + dot-prop: 10.2.0 + esbuild: 0.28.2 + escape-string-regexp: 5.0.0 + etag: 1.8.1 + exsolve: 1.1.1 + globby: 16.2.4 + gzip-size: 7.0.0 + h3: 1.15.11 + hookable: 5.5.3 + httpxy: 0.5.5 + ioredis: 5.11.1 + jiti: 2.7.0 + klona: 2.0.6 + knitwork: 1.3.0 + listhen: 1.10.1(srvx@0.11.22) + magic-string: 0.30.21 + magicast: 0.5.5 + mime: 4.1.0 + mlly: 1.8.2 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.5 + ofetch: 1.5.1 + ohash: 2.0.12 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + pretty-bytes: 7.1.3 + radix3: 1.1.2 + rollup: 4.63.3 + rollup-plugin-visualizer: 7.1.1(rollup@4.63.3) + scule: 1.3.0 + semver: 7.8.5 + serve-placeholder: 2.0.2 + serve-static: 2.2.1 + source-map: 0.7.6 + std-env: 4.2.0 + ufo: 1.6.4 + ultrahtml: 1.7.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unenv: 2.0.0-rc.24 + unimport: 6.5.0(esbuild@0.28.2)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin-utils: 0.3.2 + unstorage: 1.17.5(db0@0.3.4)(ioredis@5.11.1) + untyped: 2.0.0 + unwasm: 0.5.3 + youch: 4.1.1 + youch-core: 0.3.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@farmfe/core' + - '@libsql/client' + - '@netlify/blobs' + - '@parcel/watcher' + - '@planetscale/database' + - '@rsbuild/core' + - '@rspack/core' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bun-types-no-globals + - drizzle-orm + - encoding + - idb-keyval + - mysql2 + - oxc-parser + - react-native-b4a + - rolldown + - sqlite3 + - srvx + - supports-color + - unloader + - uploadthing + - vite + - webpack + + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-forge@1.4.0: {} + + node-gyp-build@4.8.4: {} + + node-mock-http@1.0.5: {} + + node-releases@2.0.55: {} + + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + + normalize-path@3.0.0: {} + + nostics@1.2.0: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1): + dependencies: + '@dxup/nuxt': 0.5.10(esbuild@0.28.2)(magicast@0.5.5)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + '@nuxt/cli': 3.37.0(@nuxt/schema@3.21.11)(cac@6.7.14)(magicast@0.5.5) + '@nuxt/devtools': 3.4.2(db0@0.3.4)(ioredis@5.11.1)(magic-string@0.30.21)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@nuxt/nitro-server': 3.21.11(db0@0.3.4)(esbuild@0.28.2)(ioredis@5.11.1)(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))(oxc-parser@0.143.0)(rollup@4.63.3)(srvx@0.11.22)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + '@nuxt/schema': 3.21.11 + '@nuxt/telemetry': 2.9.1(@nuxt/kit@3.21.11(magicast@0.5.5)) + '@nuxt/vite-builder': 3.21.11(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(srvx@0.11.22)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))(yaml@2.9.1) + '@unhead/vue': 2.1.17(vue@3.5.42(typescript@5.9.3)) + '@vue/shared': 3.5.42 + c12: 3.3.4(magicast@0.5.5) + chokidar: 5.0.0 + compatx: 0.2.0 + consola: 3.4.2 + cookie-es: 2.0.1 + defu: 6.1.7 + destr: 2.0.5 + devalue: 5.9.2 + errx: 0.1.2 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + h3: 1.15.11 + hookable: 5.5.3 + ignore: 7.0.9 + impound: 1.2.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + jiti: 2.7.0 + klona: 2.0.6 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + nanotar: 0.3.0 + nypm: 0.6.10 + ofetch: 1.5.1 + ohash: 2.0.12 + on-change: 6.0.2 + oxc-minify: 0.143.0 + oxc-parser: 0.143.0 + oxc-transform: 0.143.0 + oxc-walker: 1.1.1(@oxc-project/types@0.143.0)(oxc-parser@0.143.0) + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + rou3: 0.9.2 + scule: 1.3.0 + semver: 7.8.5 + std-env: 4.2.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + ultrahtml: 1.7.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unimport: 6.5.0(esbuild@0.28.2)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin-vue-router: 0.19.2(@vue/compiler-sfc@3.5.42)(vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)) + untyped: 2.0.0 + vue: 3.5.42(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@farmfe/core' + - '@libsql/client' + - '@netlify/blobs' + - '@oxc-project/types' + - '@planetscale/database' + - '@rsbuild/core' + - '@rspack/core' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bufferutil + - bun-types-no-globals + - cac + - commander + - db0 + - drizzle-orm + - encoding + - esbuild + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - mysql2 + - optionator + - oxlint + - react-native-b4a + - rolldown + - rollup + - rollup-plugin-visualizer + - sass + - sass-embedded + - sqlite3 + - srvx + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - unloader + - uploadthing + - utf-8-validate + - vite + - vue-tsc + - webpack + - xml2js + - yaml + + nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1): + dependencies: + '@dxup/nuxt': 0.5.10(esbuild@0.28.2)(magicast@0.5.5)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + '@nuxt/cli': 3.37.0(@nuxt/schema@3.21.11)(cac@6.7.14)(magicast@0.5.5) + '@nuxt/devtools': 3.4.2(db0@0.3.4)(ioredis@5.11.1)(magic-string@0.30.21)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)) + '@nuxt/kit': 3.21.11(magicast@0.5.5) + '@nuxt/nitro-server': 3.21.11(db0@0.3.4)(esbuild@0.28.2)(ioredis@5.11.1)(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1))(oxc-parser@0.143.0)(rollup@4.63.3)(typescript@5.9.3) + '@nuxt/schema': 3.21.11 + '@nuxt/telemetry': 2.9.1(@nuxt/kit@3.21.11(magicast@0.5.5)) + '@nuxt/vite-builder': 3.21.11(eslint@10.10.0(jiti@2.7.0))(magicast@0.5.5)(nuxt@3.21.11(@oxc-project/types@0.143.0)(@vue/compiler-sfc@3.5.42)(cac@6.7.14)(db0@0.3.4)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0))(ioredis@5.11.1)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(yaml@2.9.1))(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.63.3))(rollup@4.63.3)(terser@5.51.2)(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3))(yaml@2.9.1) + '@unhead/vue': 2.1.17(vue@3.5.42(typescript@5.9.3)) + '@vue/shared': 3.5.42 + c12: 3.3.4(magicast@0.5.5) + chokidar: 5.0.0 + compatx: 0.2.0 + consola: 3.4.2 + cookie-es: 2.0.1 + defu: 6.1.7 + destr: 2.0.5 + devalue: 5.9.2 + errx: 0.1.2 + escape-string-regexp: 5.0.0 + exsolve: 1.1.1 + h3: 1.15.11 + hookable: 5.5.3 + ignore: 7.0.9 + impound: 1.2.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + jiti: 2.7.0 + klona: 2.0.6 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + nanotar: 0.3.0 + nypm: 0.6.10 + ofetch: 1.5.1 + ohash: 2.0.12 + on-change: 6.0.2 + oxc-minify: 0.143.0 + oxc-parser: 0.143.0 + oxc-transform: 0.143.0 + oxc-walker: 1.1.1(@oxc-project/types@0.143.0)(oxc-parser@0.143.0) + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.3 + rou3: 0.9.2 + scule: 1.3.0 + semver: 7.8.5 + std-env: 4.2.0 + tinyglobby: 0.2.17 + ufo: 1.6.4 + ultrahtml: 1.7.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unimport: 6.5.0(esbuild@0.28.2)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin-vue-router: 0.19.2(@vue/compiler-sfc@3.5.42)(vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)) + untyped: 2.0.0 + vue: 3.5.42(typescript@5.9.3) + vue-router: 4.6.4(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@farmfe/core' + - '@libsql/client' + - '@netlify/blobs' + - '@oxc-project/types' + - '@planetscale/database' + - '@rsbuild/core' + - '@rspack/core' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - '@vue/compiler-sfc' + - aws4fetch + - bare-abort-controller + - bare-buffer + - better-sqlite3 + - bufferutil + - bun-types-no-globals + - cac + - commander + - db0 + - drizzle-orm + - encoding + - esbuild + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - mysql2 + - optionator + - oxlint + - react-native-b4a + - rolldown + - rollup + - rollup-plugin-visualizer + - sass + - sass-embedded + - sqlite3 + - srvx + - stylelint + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - unloader + - uploadthing + - utf-8-validate + - vite + - vue-tsc + - webpack + - xml2js + - yaml + + nypm@0.6.10: + dependencies: + citty: 0.2.2 + pathe: 2.0.3 + tinyexec: 1.3.1 + + obug@2.2.1: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.12: {} + + on-change@6.0.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + open@11.0.4: + dependencies: + default-browser: 5.5.1 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.2.1 + wsl-utils: 1.0.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + oxc-minify@0.143.0: + optionalDependencies: + '@oxc-minify/binding-android-arm-eabi': 0.143.0 + '@oxc-minify/binding-android-arm64': 0.143.0 + '@oxc-minify/binding-darwin-arm64': 0.143.0 + '@oxc-minify/binding-darwin-x64': 0.143.0 + '@oxc-minify/binding-freebsd-x64': 0.143.0 + '@oxc-minify/binding-linux-arm-gnueabihf': 0.143.0 + '@oxc-minify/binding-linux-arm-musleabihf': 0.143.0 + '@oxc-minify/binding-linux-arm64-gnu': 0.143.0 + '@oxc-minify/binding-linux-arm64-musl': 0.143.0 + '@oxc-minify/binding-linux-ppc64-gnu': 0.143.0 + '@oxc-minify/binding-linux-riscv64-gnu': 0.143.0 + '@oxc-minify/binding-linux-riscv64-musl': 0.143.0 + '@oxc-minify/binding-linux-s390x-gnu': 0.143.0 + '@oxc-minify/binding-linux-x64-gnu': 0.143.0 + '@oxc-minify/binding-linux-x64-musl': 0.143.0 + '@oxc-minify/binding-openharmony-arm64': 0.143.0 + '@oxc-minify/binding-win32-arm64-msvc': 0.143.0 + '@oxc-minify/binding-win32-ia32-msvc': 0.143.0 + '@oxc-minify/binding-win32-x64-msvc': 0.143.0 + + oxc-parser@0.143.0: + dependencies: + '@oxc-project/types': 0.143.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.143.0 + '@oxc-parser/binding-android-arm64': 0.143.0 + '@oxc-parser/binding-darwin-arm64': 0.143.0 + '@oxc-parser/binding-darwin-x64': 0.143.0 + '@oxc-parser/binding-freebsd-x64': 0.143.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.143.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.143.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.143.0 + '@oxc-parser/binding-linux-arm64-musl': 0.143.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.143.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.143.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.143.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.143.0 + '@oxc-parser/binding-linux-x64-gnu': 0.143.0 + '@oxc-parser/binding-linux-x64-musl': 0.143.0 + '@oxc-parser/binding-openharmony-arm64': 0.143.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.143.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.143.0 + '@oxc-parser/binding-win32-x64-msvc': 0.143.0 + + oxc-parser@0.70.0: + dependencies: + '@oxc-project/types': 0.70.0 + optionalDependencies: + '@oxc-parser/binding-darwin-arm64': 0.70.0 + '@oxc-parser/binding-darwin-x64': 0.70.0 + '@oxc-parser/binding-freebsd-x64': 0.70.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.70.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.70.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.70.0 + '@oxc-parser/binding-linux-arm64-musl': 0.70.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.70.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.70.0 + '@oxc-parser/binding-linux-x64-gnu': 0.70.0 + '@oxc-parser/binding-linux-x64-musl': 0.70.0 + '@oxc-parser/binding-wasm32-wasi': 0.70.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.70.0 + '@oxc-parser/binding-win32-x64-msvc': 0.70.0 + + oxc-transform@0.143.0: + optionalDependencies: + '@oxc-transform/binding-android-arm-eabi': 0.143.0 + '@oxc-transform/binding-android-arm64': 0.143.0 + '@oxc-transform/binding-darwin-arm64': 0.143.0 + '@oxc-transform/binding-darwin-x64': 0.143.0 + '@oxc-transform/binding-freebsd-x64': 0.143.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.143.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.143.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.143.0 + '@oxc-transform/binding-linux-arm64-musl': 0.143.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.143.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.143.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.143.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.143.0 + '@oxc-transform/binding-linux-x64-gnu': 0.143.0 + '@oxc-transform/binding-linux-x64-musl': 0.143.0 + '@oxc-transform/binding-openharmony-arm64': 0.143.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.143.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.143.0 + '@oxc-transform/binding-win32-x64-msvc': 0.143.0 + + oxc-walker@1.1.1(@oxc-project/types@0.143.0)(oxc-parser@0.143.0): + optionalDependencies: + '@oxc-project/types': 0.143.0 + oxc-parser: 0.143.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} + + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + 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 + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + perfect-debounce@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.7: {} + + pinia@2.3.1(typescript@5.9.3)(vue@3.5.42(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.42(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.42(typescript@5.9.3)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@vue/composition-api' + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.3: + dependencies: + confbox: 0.3.1 + exsolve: 1.1.1 + pathe: 2.0.3 + + postcss-calc@10.1.1(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + postcss-value-parser: 4.2.0 + + postcss-colormin@7.0.10(postcss@8.5.28): + dependencies: + '@colordx/core': 5.8.0 + browserslist: 4.29.0 + caniuse-api: 3.0.0 + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-convert-values@7.0.12(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-discard-comments@7.0.8(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-discard-duplicates@7.0.4(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-discard-empty@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-discard-overridden@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-merge-longhand@7.0.7(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + stylehacks: 7.0.11(postcss@8.5.28) + + postcss-merge-rules@7.0.11(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.3(postcss@8.5.28) + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-minify-font-values@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@7.0.5(postcss@8.5.28): + dependencies: + '@colordx/core': 5.8.0 + cssnano-utils: 5.0.3(postcss@8.5.28) + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-minify-params@7.0.9(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + cssnano-utils: 5.0.3(postcss@8.5.28) + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@7.1.2(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + caniuse-api: 3.0.0 + cssesc: 3.0.0 + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-normalize-charset@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + + postcss-normalize-display-values@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@7.0.4(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@7.0.4(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@7.0.9(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-ordered-values@7.0.4(postcss@8.5.28): + dependencies: + cssnano-utils: 5.0.3(postcss@8.5.28) + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-reduce-initial@7.0.9(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + caniuse-api: 3.0.0 + postcss: 8.5.28 + + postcss-reduce-transforms@7.0.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@7.1.6: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@7.1.3(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-value-parser: 4.2.0 + svgo: 4.1.0 + + postcss-unique-selectors@7.0.7(postcss@8.5.28): + dependencies: + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.28: + dependencies: + nanoid: 3.3.19 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + powershell-utils@0.1.0: {} + + powershell-utils@0.2.1: {} + + prelude-ls@1.2.1: {} + + pretty-bytes@7.1.3: {} + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + punycode@2.3.1: {} + + qified@0.10.1: + dependencies: + hookified: 2.2.0 + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + radix3@1.1.2: {} + + range-parser@1.3.0: {} + + rc9@3.1.0: + dependencies: + defu: 6.1.7 + destr: 2.0.5 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.9 + + readdirp@4.1.2: {} + + readdirp@5.1.1: {} + + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + + resolve-from@5.0.0: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + retry@0.12.0: {} + + reusify@1.1.0: {} + + rollup-plugin-visualizer@7.1.1(rollup@4.63.3): + dependencies: + open: 11.0.4 + picomatch: 4.0.7 + source-map: 0.8.0 + yargs: 18.1.0 + optionalDependencies: + rollup: 4.63.3 + + rollup@4.63.3: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.3 + '@rollup/rollup-android-arm64': 4.63.3 + '@rollup/rollup-darwin-arm64': 4.63.3 + '@rollup/rollup-darwin-x64': 4.63.3 + '@rollup/rollup-freebsd-arm64': 4.63.3 + '@rollup/rollup-freebsd-x64': 4.63.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.3 + '@rollup/rollup-linux-arm-musleabihf': 4.63.3 + '@rollup/rollup-linux-arm64-gnu': 4.63.3 + '@rollup/rollup-linux-arm64-musl': 4.63.3 + '@rollup/rollup-linux-loong64-gnu': 4.63.3 + '@rollup/rollup-linux-loong64-musl': 4.63.3 + '@rollup/rollup-linux-ppc64-gnu': 4.63.3 + '@rollup/rollup-linux-ppc64-musl': 4.63.3 + '@rollup/rollup-linux-riscv64-gnu': 4.63.3 + '@rollup/rollup-linux-riscv64-musl': 4.63.3 + '@rollup/rollup-linux-s390x-gnu': 4.63.3 + '@rollup/rollup-linux-x64-gnu': 4.63.3 + '@rollup/rollup-linux-x64-musl': 4.63.3 + '@rollup/rollup-openbsd-x64': 4.63.3 + '@rollup/rollup-openharmony-arm64': 4.63.3 + '@rollup/rollup-win32-arm64-msvc': 4.63.3 + '@rollup/rollup-win32-ia32-msvc': 4.63.3 + '@rollup/rollup-win32-x64-gnu': 4.63.3 + '@rollup/rollup-win32-x64-msvc': 4.63.3 + fsevents: 2.3.3 + + rou3@0.9.2: {} + + run-applescript@7.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + sax@1.6.1: {} + + scule@1.3.0: {} + + semver@6.3.1: {} + + semver@7.8.5: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-javascript@7.1.1: {} + + seroval@1.6.7: {} + + serve-placeholder@2.0.2: + dependencies: + defu: 6.1.7 + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.10.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + simple-git@3.36.0: + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + '@simple-git/args-pathspec': 1.0.3 + '@simple-git/argv-parser': 1.1.1 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + sisteransi@1.0.5: {} + + slash@5.1.0: {} + + smob@1.6.2: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + source-map@0.8.0: {} + + srvx@0.11.22: {} + + standard-as-callback@2.1.0: {} + + statuses@2.0.2: {} + + std-env@4.2.0: {} + + streamx@2.28.1: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + 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-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string-width@8.2.2: + dependencies: + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.3.0 + + strip-final-newline@3.0.0: {} + + strip-literal@4.0.0: + dependencies: + js-tokens: 10.0.0 + + structured-clone-es@2.0.1: {} + + stylehacks@7.0.11(postcss@8.5.28): + dependencies: + browserslist: 4.29.0 + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 + + supports-color@10.2.2: {} + + supports-preserve-symlinks-flag@1.0.0: {} + + svgo@4.1.0: + dependencies: + commander: 11.1.0 + css-select: 6.0.0 + css-tree: 3.2.1 + css-what: 7.0.0 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + + tagged-tag@1.0.0: {} + + tapable@2.3.3: {} + + tar-stream@3.2.1: + dependencies: + b4a: 1.9.0 + bare-fs: 4.8.1 + fast-fifo: 1.3.2 + streamx: 2.28.1 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar@7.5.22: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + teex@1.0.1: + dependencies: + streamx: 2.28.1 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + terser@5.51.2: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.18.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + text-decoder@1.2.7: + dependencies: + b4a: 1.9.0 + transitivePeerDependencies: + - react-native-b4a + + tiny-invariant@1.3.3: {} + + tinyclip@0.1.15: {} + + tinyexec@1.3.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tosource@2.0.0-alpha.3: {} + + totalist@3.0.1: {} + + tr46@0.0.3: {} + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + tslib@2.8.1: + optional: true + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@5.9.0: + dependencies: + tagged-tag: 1.0.0 + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + ultrahtml@1.7.0: {} + + uncrypto@0.1.3: {} + + unctx@2.5.0: + dependencies: + acorn: 8.18.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + unplugin: 2.3.11 + + unctx@3.0.1(magic-string@0.30.21)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)): + optionalDependencies: + magic-string: 0.30.21 + oxc-parser: 0.143.0 + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + + unctx@3.0.1(magic-string@1.4.1)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))): + optionalDependencies: + magic-string: 1.4.1 + oxc-parser: 0.143.0 + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unhead@2.1.17: + dependencies: + hookable: 6.1.1 + + unicorn-magic@0.3.0: {} + + unicorn-magic@0.4.0: {} + + unimport@6.5.0(esbuild@0.28.2)(oxc-parser@0.143.0)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + acorn: 8.18.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.2.1 + magic-string: 1.4.1 + mlly: 1.8.2 + pathe: 2.0.3 + picomatch: 4.0.7 + pkg-types: 2.3.3 + scule: 1.3.0 + strip-literal: 4.0.0 + tinyglobby: 0.2.17 + unplugin: 3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + unplugin-utils: 0.3.2 + optionalDependencies: + oxc-parser: 0.143.0 + transitivePeerDependencies: + - '@farmfe/core' + - '@rsbuild/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rollup + - unloader + - vite + - webpack + + unplugin-utils@0.2.5: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.7 + + unplugin-utils@0.3.2: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.7 + + unplugin-vue-router@0.12.0(vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)): + dependencies: + '@babel/types': 7.29.8 + '@vue-macros/common': 1.16.1(vue@3.5.42(typescript@5.9.3)) + ast-walker-scope: 0.6.2 + chokidar: 4.0.3 + fast-glob: 3.3.3 + json5: 2.2.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + micromatch: 4.0.8 + mlly: 1.8.2 + pathe: 2.0.3 + scule: 1.3.0 + unplugin: 2.3.11 + unplugin-utils: 0.2.5 + yaml: 2.9.1 + optionalDependencies: + vue-router: 4.6.4(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - vue + + unplugin-vue-router@0.19.2(@vue/compiler-sfc@3.5.42)(vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)))(vue@3.5.42(typescript@5.9.3)): + dependencies: + '@babel/generator': 7.29.8 + '@vue-macros/common': 3.1.4(vue@3.5.42(typescript@5.9.3)) + '@vue/compiler-sfc': 3.5.42 + '@vue/language-core': 3.3.11 + ast-walker-scope: 0.8.3 + chokidar: 5.0.0 + json5: 2.2.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + muggle-string: 0.4.1 + pathe: 2.0.3 + picomatch: 4.0.7 + scule: 1.3.0 + tinyglobby: 0.2.17 + unplugin: 2.3.11 + unplugin-utils: 0.3.2 + yaml: 2.9.1 + optionalDependencies: + vue-router: 4.6.4(vue@3.5.42(typescript@5.9.3)) + transitivePeerDependencies: + - vue + + unplugin@1.16.1: + dependencies: + acorn: 8.18.0 + webpack-virtual-modules: 0.6.2 + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.18.0 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + + unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.7 + webpack-virtual-modules: 0.6.2 + optionalDependencies: + esbuild: 0.28.2 + rollup: 4.63.3 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + + unstorage@1.17.5(db0@0.3.4)(ioredis@5.11.1): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.2 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + optionalDependencies: + db0: 0.3.4 + ioredis: 5.11.1 + + untun@0.2.2: {} + + untyped@2.0.0: + dependencies: + citty: 0.1.6 + defu: 6.1.7 + jiti: 2.7.0 + knitwork: 1.3.0 + scule: 1.3.0 + + unwasm@0.5.3: + dependencies: + exsolve: 1.1.1 + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.2 + pathe: 2.0.3 + pkg-types: 2.3.3 + + update-browserslist-db@1.3.3(browserslist@4.29.0): + dependencies: + browserslist: 4.29.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uqr@0.1.3: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + verkit@0.3.2: {} + + vite-dev-rpc@2.0.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + birpc: 4.2.0 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-hot-client: 2.2.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + + vite-hot-client@2.2.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + + vite-node@5.3.0(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1): + dependencies: + cac: 6.7.14 + es-module-lexer: 2.3.2 + obug: 2.2.1 + pathe: 2.0.3 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + vite-plugin-checker@0.14.5(eslint@10.10.0(jiti@2.7.0))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + '@babel/code-frame': 7.29.7 + chokidar: 5.0.0 + npm-run-path: 6.0.0 + picocolors: 1.1.1 + picomatch: 4.0.7 + proper-lockfile: 4.1.2 + tiny-invariant: 1.3.3 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + optionalDependencies: + eslint: 10.10.0(jiti@2.7.0) + optionator: 0.9.4 + typescript: 5.9.3 + + vite-plugin-inspect@11.4.1(@nuxt/kit@4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))))(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)): + dependencies: + ansis: 4.4.0 + error-stack-parser-es: 1.0.5 + obug: 2.2.1 + ohash: 2.0.12 + open: 11.0.4 + perfect-debounce: 2.1.0 + sirv: 3.0.2 + unplugin-utils: 0.3.2 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vite-dev-rpc: 2.0.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1)) + optionalDependencies: + '@nuxt/kit': 4.5.2(magic-string@0.30.21)(magicast@0.5.5)(oxc-parser@0.143.0)(unplugin@3.4.0(esbuild@0.28.2)(rollup@4.63.3)) + + vite-plugin-vue-tracer@1.5.0(vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1))(vue@3.5.42(typescript@5.9.3)): + dependencies: + estree-walker: 3.0.3 + exsolve: 1.1.1 + magic-string: 1.4.1 + pathe: 2.0.3 + source-map-js: 1.2.1 + vite: 7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1) + vue: 3.5.42(typescript@5.9.3) + + vite@7.3.6(jiti@2.7.0)(terser@5.51.2)(yaml@2.9.1): + dependencies: + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + postcss: 8.5.28 + rollup: 4.63.3 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.7.0 + terser: 5.51.2 + yaml: 2.9.1 + + vue-bundle-renderer@2.4.0: + dependencies: + ufo: 1.6.4 + + vue-demi@0.14.10(vue@3.5.42(typescript@5.9.3)): + dependencies: + vue: 3.5.42(typescript@5.9.3) + + vue-devtools-stub@0.1.0: {} + + vue-i18n@10.0.8(vue@3.5.42(typescript@5.9.3)): + dependencies: + '@intlify/core-base': 10.0.8 + '@intlify/shared': 10.0.8 + '@vue/devtools-api': 6.6.4 + vue: 3.5.42(typescript@5.9.3) + + vue-router@4.6.4(vue@3.5.42(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.42(typescript@5.9.3) + + vue@3.5.42(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.42 + '@vue/compiler-sfc': 3.5.42 + '@vue/runtime-dom': 3.5.42 + '@vue/server-renderer': 3.5.42 + '@vue/shared': 3.5.42 + optionalDependencies: + typescript: 5.9.3 + + webidl-conversions@3.0.1: {} + + webpack-virtual-modules@0.6.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@6.0.1: + dependencies: + isexe: 4.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.2.0 + + ws@8.21.3: {} + + wsl-utils@1.0.0: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@5.0.0: {} + + yaml-eslint-parser@1.3.2: + dependencies: + eslint-visitor-keys: 3.4.3 + yaml: 2.9.1 + + yaml@2.9.1: {} + + yargs-parser@22.0.0: {} + + yargs@18.1.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 8.2.2 + y18n: 5.0.8 + yargs-parser: 22.0.0 + + yocto-queue@0.1.0: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.1: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.7.0 + '@speed-highlight/core': 1.2.24 + cookie-es: 3.1.1 + youch-core: 0.3.3 + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..3ff5faa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*"