diff --git a/.github/workflows/frontend-check.yml b/.github/workflows/frontend-check.yml new file mode 100644 index 000000000..9dfe1fe11 --- /dev/null +++ b/.github/workflows/frontend-check.yml @@ -0,0 +1,30 @@ +name: Frontend build check + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + frontend-check: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./apps/desktop-client + steps: + # Checkout source code + - name: Checkout code + uses: actions/checkout@v3 + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 23 + cache: 'npm' + cache-dependency-path: './apps/desktop-client/package-lock.json' + - name: Install dependencies + run: npm install + - name: Lint + run: npm run lint + - name: Build + run: npm run build \ No newline at end of file diff --git a/.gitignore b/.gitignore index 009c20e5e..0ec086432 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ data +dist _notebooks *.wasm Makefile.dev .env +.vscode # Added by cargo target diff --git a/Cargo.lock b/Cargo.lock index 3b29fe95a..fb82d1ecb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,12 +194,6 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - [[package]] name = "arbitrary" version = "1.3.2" @@ -674,15 +668,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bindgen" version = "0.64.0" @@ -805,12 +790,6 @@ dependencies = [ "piper", ] -[[package]] -name = "boolinator" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" - [[package]] name = "brotli" version = "7.0.0" @@ -1294,16 +1273,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -2527,7 +2496,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers 0.2.6", + "gloo-timers", "send_wrapper", ] @@ -2883,229 +2852,6 @@ dependencies = [ "regex-syntax 0.8.5", ] -[[package]] -name = "gloo" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" -dependencies = [ - "gloo-console 0.2.3", - "gloo-dialogs 0.1.1", - "gloo-events 0.1.2", - "gloo-file 0.2.3", - "gloo-history 0.1.5", - "gloo-net 0.3.1", - "gloo-render 0.1.1", - "gloo-storage 0.2.2", - "gloo-timers 0.2.6", - "gloo-utils 0.1.7", - "gloo-worker 0.2.1", -] - -[[package]] -name = "gloo" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249" -dependencies = [ - "gloo-console 0.3.0", - "gloo-dialogs 0.2.0", - "gloo-events 0.2.0", - "gloo-file 0.3.0", - "gloo-history 0.2.2", - "gloo-net 0.4.0", - "gloo-render 0.2.0", - "gloo-storage 0.3.0", - "gloo-timers 0.3.0", - "gloo-utils 0.2.0", - "gloo-worker 0.4.0", -] - -[[package]] -name = "gloo" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15282ece24eaf4bd338d73ef580c6714c8615155c4190c781290ee3fa0fd372" -dependencies = [ - "gloo-console 0.3.0", - "gloo-dialogs 0.2.0", - "gloo-events 0.2.0", - "gloo-file 0.3.0", - "gloo-history 0.2.2", - "gloo-net 0.5.0", - "gloo-render 0.2.0", - "gloo-storage 0.3.0", - "gloo-timers 0.3.0", - "gloo-utils 0.2.0", - "gloo-worker 0.5.0", -] - -[[package]] -name = "gloo-console" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" -dependencies = [ - "gloo-utils 0.1.7", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-console" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261" -dependencies = [ - "gloo-utils 0.2.0", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" -dependencies = [ - "gloo-events 0.1.2", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f" -dependencies = [ - "futures-channel", - "gloo-events 0.2.0", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-history" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" -dependencies = [ - "gloo-events 0.1.2", - "gloo-utils 0.1.7", - "serde", - "serde-wasm-bindgen 0.5.0", - "serde_urlencoded", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-history" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6" -dependencies = [ - "getrandom 0.2.15", - "gloo-events 0.2.0", - "gloo-utils 0.2.0", - "serde", - "serde-wasm-bindgen 0.6.5", - "serde_urlencoded", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-net" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils 0.1.7", - "http 0.2.12", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-net" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils 0.2.0", - "http 0.2.12", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "gloo-net" version = "0.5.0" @@ -3115,7 +2861,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils 0.2.0", + "gloo-utils", "http 0.2.12", "js-sys", "pin-project", @@ -3127,56 +2873,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-render" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-render" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" -dependencies = [ - "gloo-utils 0.1.7", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" -dependencies = [ - "gloo-utils 0.2.0", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "gloo-timers" version = "0.2.6" @@ -3189,31 +2885,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "gloo-utils" version = "0.2.0" @@ -3227,73 +2898,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-worker" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" -dependencies = [ - "anymap2", - "bincode", - "gloo-console 0.2.3", - "gloo-utils 0.1.7", - "js-sys", - "serde", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-worker" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" -dependencies = [ - "bincode", - "futures", - "gloo-utils 0.2.0", - "gloo-worker-macros", - "js-sys", - "pinned", - "serde", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-worker" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "085f262d7604911c8150162529cefab3782e91adb20202e8658f7275d2aefe5d" -dependencies = [ - "bincode", - "futures", - "gloo-utils 0.2.0", - "gloo-worker-macros", - "js-sys", - "pinned", - "serde", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-worker-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 2.0.85", -] - [[package]] name = "gobject-sys" version = "0.18.0" @@ -3444,20 +3048,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "handlebars" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" -dependencies = [ - "log", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "hard-xml" version = "0.0.0" @@ -3964,26 +3554,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" -[[package]] -name = "implicit-clone" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a9aa791c7b5a71b636b7a68207fdebf171ddfc593d9c8506ec4cbc527b6a84" -dependencies = [ - "implicit-clone-derive", - "indexmap 2.6.0", -] - -[[package]] -name = "implicit-clone-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" -dependencies = [ - "quote", - "syn 2.0.85", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -4339,7 +3909,7 @@ dependencies = [ "base64 0.22.1", "futures-channel", "futures-util", - "gloo-net 0.5.0", + "gloo-net", "http 1.1.0", "jsonrpsee-core", "pin-project", @@ -6234,17 +5804,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pinned" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" -dependencies = [ - "futures", - "rustversion", - "thiserror", -] - [[package]] name = "piper" version = "0.2.4" @@ -6355,16 +5914,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prettyplease" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" -dependencies = [ - "proc-macro2", - "syn 2.0.85", -] - [[package]] name = "primal-check" version = "0.3.4" @@ -6495,23 +6044,6 @@ dependencies = [ "syn 2.0.85", ] -[[package]] -name = "prokio" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" -dependencies = [ - "futures", - "gloo 0.8.1", - "num_cpus", - "once_cell", - "pin-project", - "pinned", - "tokio", - "tokio-stream", - "wasm-bindgen-futures", -] - [[package]] name = "prost" version = "0.13.3" @@ -7788,28 +7320,6 @@ dependencies = [ "typeid", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde_derive" version = "1.0.214" @@ -8017,6 +7527,7 @@ dependencies = [ "spyglass-lens 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.26.3", "strum_macros 0.26.4", + "ts-rs", "url", "uuid 1.11.0", ] @@ -8337,31 +7848,6 @@ dependencies = [ "windows 0.39.0", ] -[[package]] -name = "spyglass-client" -version = "0.1.0" -dependencies = [ - "gloo 0.11.0", - "handlebars", - "js-sys", - "log", - "num-format", - "serde", - "serde-wasm-bindgen 0.6.5", - "serde_json", - "shared", - "strum 0.26.3", - "strum_macros 0.26.4", - "ui-components", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-logger", - "web-sys", - "yew", - "yew-router", -] - [[package]] name = "spyglass-lens" version = "0.1.7" @@ -9817,6 +9303,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "texting_robots" version = "0.2.2" @@ -10341,6 +9836,29 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ts-rs" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a2f31991cee3dce1ca4f929a8a04fdd11fd8801aac0f2030b0fa8a0a3fef6b9" +dependencies = [ + "lazy_static", + "thiserror", + "ts-rs-macros", +] + +[[package]] +name = "ts-rs-macros" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea0b99e8ec44abd6f94a18f28f7934437809dd062820797c52401298116f70e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.85", + "termcolor", +] + [[package]] name = "tungstenite" version = "0.21.0" @@ -10399,17 +9917,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ui-components" -version = "0.1.0" -dependencies = [ - "js-sys", - "shared", - "url", - "wasm-bindgen-futures", - "yew", -] - [[package]] name = "uncased" version = "0.9.10" @@ -10535,12 +10042,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "urlpattern" version = "0.3.0" @@ -10800,17 +10301,6 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" -[[package]] -name = "wasm-logger" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" -dependencies = [ - "log", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.4.2" @@ -11692,76 +11182,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -[[package]] -name = "yew" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac" -dependencies = [ - "console_error_panic_hook", - "futures", - "gloo 0.10.0", - "implicit-clone", - "indexmap 2.6.0", - "js-sys", - "prokio", - "rustversion", - "serde", - "slab", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew-macro", -] - -[[package]] -name = "yew-macro" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2" -dependencies = [ - "boolinator", - "once_cell", - "prettyplease", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.85", -] - -[[package]] -name = "yew-router" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca1d5052c96e6762b4d6209a8aded597758d442e6c479995faf0c7b5538e0c6" -dependencies = [ - "gloo 0.10.0", - "js-sys", - "route-recognizer", - "serde", - "serde_urlencoded", - "tracing", - "urlencoding", - "wasm-bindgen", - "web-sys", - "yew", - "yew-router-macro", -] - -[[package]] -name = "yew-router-macro" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bfd190a07ca8cfde7cd4c52b3ac463803dc07323db8c34daa697e86365978c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.85", -] - [[package]] name = "zbus" version = "4.4.0" diff --git a/Cargo.toml b/Cargo.toml index 1a374e7ec..32dc439d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,15 @@ [workspace] resolver = "2" members = [ - "crates/*", + "crates/entities", + "crates/migrations", + "crates/shared", + "crates/spyglass", + "crates/spyglass-lens", + "crates/spyglass-processor", + "crates/spyglass-rpc", + "crates/spyglass-searcher", + "apps/tauri" ] diff --git a/Makefile b/Makefile index 8c0f1ffd7..a8cd486b1 100644 --- a/Makefile +++ b/Makefile @@ -103,4 +103,8 @@ upload-debug-symbols-windows: cd crates/client && trunk build cargo build -p spyglass-app --profile sentry npx sentry-cli difutil check target/sentry/spyglass-app.exe - npx sentry-cli upload-dif -o spyglass -p spyglass-frontend --include-sources target/sentry/spyglass-app.exe \ No newline at end of file + npx sentry-cli upload-dif -o spyglass -p spyglass-frontend --include-sources target/sentry/spyglass-app.exe + + +generate-bindings: + TS_RS_EXPORT_DIR="../../apps/desktop-client/src/bindings" cargo test -p shared \ No newline at end of file diff --git a/apps/desktop-client/.gitignore b/apps/desktop-client/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/apps/desktop-client/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/apps/desktop-client/.prettierignore b/apps/desktop-client/.prettierignore new file mode 100644 index 000000000..7e7c9c73c --- /dev/null +++ b/apps/desktop-client/.prettierignore @@ -0,0 +1,3 @@ +build +coverage +src/bindings \ No newline at end of file diff --git a/apps/desktop-client/.prettierrc b/apps/desktop-client/.prettierrc new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/apps/desktop-client/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/apps/desktop-client/dist/.gitkeep b/apps/desktop-client/dist/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/apps/desktop-client/eslint.config.js b/apps/desktop-client/eslint.config.js new file mode 100644 index 000000000..79a552ea9 --- /dev/null +++ b/apps/desktop-client/eslint.config.js @@ -0,0 +1,28 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist"] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + }, +); diff --git a/apps/desktop-client/index.html b/apps/desktop-client/index.html new file mode 100644 index 000000000..e4b78eae1 --- /dev/null +++ b/apps/desktop-client/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/apps/desktop-client/package-lock.json b/apps/desktop-client/package-lock.json new file mode 100644 index 000000000..be313e5b1 --- /dev/null +++ b/apps/desktop-client/package-lock.json @@ -0,0 +1,4158 @@ +{ + "name": "desktop-client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "desktop-client", + "version": "0.0.0", + "dependencies": { + "@heroicons/react": "^2.1.5", + "@icons-pack/react-simple-icons": "^10.1.0", + "@tauri-apps/api": "^2.0.3", + "handlebars": "^4.7.8", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.27.0" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@tailwindcss/forms": "^0.5.9", + "@types/node": "^22.8.6", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", + "@vitejs/plugin-react-swc": "^3.5.0", + "autoprefixer": "^10.4.20", + "eslint": "^9.13.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "globals": "^15.11.0", + "postcss": "^8.4.47", + "prettier": "3.3.3", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.2", + "typescript-eslint": "^8.11.0", + "vite": "^5.4.10" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", + "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@heroicons/react": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", + "integrity": "sha512-FuzFN+BsHa+7OxbvAERtgBTNeZpUjgM/MIizfVkSCL2/edriN0Hx/DWRCR//aPYwO5QX/YlgLGXk+E3PcfZwjA==", + "license": "MIT", + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@icons-pack/react-simple-icons": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@icons-pack/react-simple-icons/-/react-simple-icons-10.1.0.tgz", + "integrity": "sha512-sZ2oDkYaVAci7GuNL8okERJn4Ej0INbeCwtIDVuwWfO5zILW7j5frvKQbozTB+fLtZqEwAP9KkNp7oR8WeHaIg==", + "license": "MIT", + "peerDependencies": { + "react": "^16.13 || ^17 || ^18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@remix-run/router": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.20.0.tgz", + "integrity": "sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.3.tgz", + "integrity": "sha512-ufb2CH2KfBWPJok95frEZZ82LtDl0A6QKTa8MoM+cWwDZvVGl5/jNb79pIhRvAalUu+7LD91VYR0nwRD799HkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.3.tgz", + "integrity": "sha512-iAHpft/eQk9vkWIV5t22V77d90CRofgR2006UiCjHcHJFVI1E0oBkQIAbz+pLtthFw3hWEmVB4ilxGyBf48i2Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.3.tgz", + "integrity": "sha512-QPW2YmkWLlvqmOa2OwrfqLJqkHm7kJCIMq9kOz40Zo9Ipi40kf9ONG5Sz76zszrmIZZ4hgRIkez69YnTHgEz1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.3.tgz", + "integrity": "sha512-KO0pN5x3+uZm1ZXeIfDqwcvnQ9UEGN8JX5ufhmgH5Lz4ujjZMAnxQygZAVGemFWn+ZZC0FQopruV4lqmGMshow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.24.3.tgz", + "integrity": "sha512-CsC+ZdIiZCZbBI+aRlWpYJMSWvVssPuWqrDy/zi9YfnatKKSLFCe6fjna1grHuo/nVaHG+kiglpRhyBQYRTK4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.24.3.tgz", + "integrity": "sha512-F0nqiLThcfKvRQhZEzMIXOQG4EeX61im61VYL1jo4eBxv4aZRmpin6crnBJQ/nWnCsjH5F6J3W6Stdm0mBNqBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.3.tgz", + "integrity": "sha512-KRSFHyE/RdxQ1CSeOIBVIAxStFC/hnBgVcaiCkQaVC+EYDtTe4X7z5tBkFyRoBgUGtB6Xg6t9t2kulnX6wJc6A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.3.tgz", + "integrity": "sha512-h6Q8MT+e05zP5BxEKz0vi0DhthLdrNEnspdLzkoFqGwnmOzakEHSlXfVyA4HJ322QtFy7biUAVFPvIDEDQa6rw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.3.tgz", + "integrity": "sha512-fKElSyXhXIJ9pqiYRqisfirIo2Z5pTTve5K438URf08fsypXrEkVmShkSfM8GJ1aUyvjakT+fn2W7Czlpd/0FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.3.tgz", + "integrity": "sha512-YlddZSUk8G0px9/+V9PVilVDC6ydMz7WquxozToozSnfFK6wa6ne1ATUjUvjin09jp34p84milxlY5ikueoenw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.3.tgz", + "integrity": "sha512-yNaWw+GAO8JjVx3s3cMeG5Esz1cKVzz8PkTJSfYzE5u7A+NvGmbVFEHP+BikTIyYWuz0+DX9kaA3pH9Sqxp69g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.3.tgz", + "integrity": "sha512-lWKNQfsbpv14ZCtM/HkjCTm4oWTKTfxPmr7iPfp3AHSqyoTz5AgLemYkWLwOBWc+XxBbrU9SCokZP0WlBZM9lA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.3.tgz", + "integrity": "sha512-HoojGXTC2CgCcq0Woc/dn12wQUlkNyfH0I1ABK4Ni9YXyFQa86Fkt2Q0nqgLfbhkyfQ6003i3qQk9pLh/SpAYw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.3.tgz", + "integrity": "sha512-mnEOh4iE4USSccBOtcrjF5nj+5/zm6NcNhbSEfR3Ot0pxBwvEn5QVUXcuOwwPkapDtGZ6pT02xLoPaNv06w7KQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.3.tgz", + "integrity": "sha512-rMTzawBPimBQkG9NKpNHvquIUTQPzrnPxPbCY1Xt+mFkW7pshvyIS5kYgcf74goxXOQk0CP3EoOC1zcEezKXhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.3.tgz", + "integrity": "sha512-2lg1CE305xNvnH3SyiKwPVsTVLCg4TmNCF1z7PSHX2uZY2VbUpdkgAllVoISD7JO7zu+YynpWNSKAtOrX3AiuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.3.tgz", + "integrity": "sha512-9SjYp1sPyxJsPWuhOCX6F4jUMXGbVVd5obVpoVEi8ClZqo52ViZewA6eFz85y8ezuOA+uJMP5A5zo6Oz4S5rVQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.3.tgz", + "integrity": "sha512-HGZgRFFYrMrP3TJlq58nR1xy8zHKId25vhmm5S9jETEfDf6xybPxsavFTJaufe2zgOGYJBskGlj49CwtEuFhWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.42.tgz", + "integrity": "sha512-iQrRk3SKndQZ4ptJv1rzeQSiCYQIhMjiO97QXOlCcCoaazOLKPnLnXzU4Kv0FuBFyYfG2FE94BoR0XI2BN02qw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.13" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.7.42", + "@swc/core-darwin-x64": "1.7.42", + "@swc/core-linux-arm-gnueabihf": "1.7.42", + "@swc/core-linux-arm64-gnu": "1.7.42", + "@swc/core-linux-arm64-musl": "1.7.42", + "@swc/core-linux-x64-gnu": "1.7.42", + "@swc/core-linux-x64-musl": "1.7.42", + "@swc/core-win32-arm64-msvc": "1.7.42", + "@swc/core-win32-ia32-msvc": "1.7.42", + "@swc/core-win32-x64-msvc": "1.7.42" + }, + "peerDependencies": { + "@swc/helpers": "*" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.42.tgz", + "integrity": "sha512-fWhaCs2+8GDRIcjExVDEIfbptVrxDqG8oHkESnXgymmvqTWzWei5SOnPNMS8Q+MYsn/b++Y2bDxkcwmq35Bvxg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.7.42.tgz", + "integrity": "sha512-ZaVHD2bijrlkCyD7NDzLmSK849Jgcx+6DdL4x1dScoz1slJ8GTvLtEu0JOUaaScQwA+cVlhmrmlmi9ssjbRLGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.42.tgz", + "integrity": "sha512-iF0BJj7hVTbY/vmbvyzVTh/0W80+Q4fbOYschdUM3Bsud39TA+lSaPOefOHywkNH58EQ1z3EAxYcJOWNES7GFQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.42.tgz", + "integrity": "sha512-xGu8j+DOLYTLkVmsfZPJbNPW1EkiWgSucT0nOlz77bLxImukt/0+HVm2hOwHSKuArQ8C3cjahAMY3b/s4VH2ww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.42.tgz", + "integrity": "sha512-qtW3JNO7i1yHEko59xxz+jY38+tYmB96JGzj6XzygMbYJYZDYbrOpXQvKbMGNG3YeTDan7Fp2jD0dlKf7NgDPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.42.tgz", + "integrity": "sha512-F9WY1TN+hhhtiEzZjRQziNLt36M5YprMeOBHjsLVNqwgflzleSI7ulgnlQECS8c8zESaXj3ksGduAoJYtPC1cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.42.tgz", + "integrity": "sha512-7YMdOaYKLMQ8JGfnmRDwidpLFs/6ka+80zekeM0iCVO48yLrJR36G0QGXzMjKsXI0BPhq+mboZRRENK4JfQnEA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.42.tgz", + "integrity": "sha512-C5CYWaIZEyqPl5W/EwcJ/mLBJFHVoUEa/IwWi0b4q2fCXcSCktQGwKXOQ+d67GneiZoiq0HasgcdMmMpGS9YRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.42.tgz", + "integrity": "sha512-3j47seZ5pO62mbrqvPe1iwhe2BXnM5q7iB+n2xgA38PCGYt0mnaJafqmpCXm/uYZOCMqSNynaoOWCMMZm4sqtA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.7.42", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.42.tgz", + "integrity": "sha512-FXl9MdeUogZLGDcLr6QIRdDVkpG0dkN4MLM4dwQ5kcAk+XfKPrQibX6M2kcfhsCx+jtBqtK7hRFReRXPWJZGbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz", + "integrity": "sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz", + "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" + } + }, + "node_modules/@tauri-apps/api": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.0.3.tgz", + "integrity": "sha512-840qk6n8rbXBXMA5/aAgTYsg5JAubKO0nXw5wf7IzGnUuYKGbB4oFBIZtXOIWy+E0kNTDI3qhq5iqsoMJfwp8g==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.8.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.6.tgz", + "integrity": "sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.8" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", + "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/type-utils": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", + "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", + "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", + "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.12.2", + "@typescript-eslint/utils": "8.12.2", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", + "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", + "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/visitor-keys": "8.12.2", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", + "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.12.2", + "@typescript-eslint/types": "8.12.2", + "@typescript-eslint/typescript-estree": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", + "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.12.2", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.1.tgz", + "integrity": "sha512-vgWOY0i1EROUK0Ctg1hwhtC3SdcDjZcdit4Ups4aPkDcB1jYhmo+RMYWY87cmXMhvtD5uf8lV89j2w16vkdSVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.7.26" + }, + "peerDependencies": { + "vite": "^4 || ^5" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/autoprefixer": { + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001676", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", + "integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.50", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.50.tgz", + "integrity": "sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", + "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.13.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.5", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.1.0", + "eslint-visitor-keys": "^4.1.0", + "espree": "^10.2.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", + "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz", + "integrity": "sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "15.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", + "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", + "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-router": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.27.0.tgz", + "integrity": "sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==", + "dependencies": { + "@remix-run/router": "1.20.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.27.0.tgz", + "integrity": "sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==", + "dependencies": { + "@remix-run/router": "1.20.0", + "react-router": "6.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.3.tgz", + "integrity": "sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.24.3", + "@rollup/rollup-android-arm64": "4.24.3", + "@rollup/rollup-darwin-arm64": "4.24.3", + "@rollup/rollup-darwin-x64": "4.24.3", + "@rollup/rollup-freebsd-arm64": "4.24.3", + "@rollup/rollup-freebsd-x64": "4.24.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.3", + "@rollup/rollup-linux-arm-musleabihf": "4.24.3", + "@rollup/rollup-linux-arm64-gnu": "4.24.3", + "@rollup/rollup-linux-arm64-musl": "4.24.3", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.3", + "@rollup/rollup-linux-riscv64-gnu": "4.24.3", + "@rollup/rollup-linux-s390x-gnu": "4.24.3", + "@rollup/rollup-linux-x64-gnu": "4.24.3", + "@rollup/rollup-linux-x64-musl": "4.24.3", + "@rollup/rollup-win32-arm64-msvc": "4.24.3", + "@rollup/rollup-win32-ia32-msvc": "4.24.3", + "@rollup/rollup-win32-x64-msvc": "4.24.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", + "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.12.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.12.2.tgz", + "integrity": "sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.12.2", + "@typescript-eslint/parser": "8.12.2", + "@typescript-eslint/utils": "8.12.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vite": { + "version": "5.4.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", + "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yaml": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/apps/desktop-client/package.json b/apps/desktop-client/package.json new file mode 100644 index 000000000..1bcc669e3 --- /dev/null +++ b/apps/desktop-client/package.json @@ -0,0 +1,42 @@ +{ + "name": "desktop-client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "fmt": "prettier --write .", + "preview": "vite preview" + }, + "dependencies": { + "@heroicons/react": "^2.1.5", + "@icons-pack/react-simple-icons": "^10.1.0", + "@tauri-apps/api": "^2.0.3", + "handlebars": "^4.7.8", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.27.0" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@tailwindcss/forms": "^0.5.9", + "@types/node": "^22.8.6", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", + "@vitejs/plugin-react-swc": "^3.5.0", + "autoprefixer": "^10.4.20", + "eslint": "^9.13.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.14", + "globals": "^15.11.0", + "postcss": "^8.4.47", + "prettier": "3.3.3", + "tailwindcss": "^3.4.14", + "typescript": "~5.6.2", + "typescript-eslint": "^8.11.0", + "vite": "^5.4.10" + } +} diff --git a/apps/desktop-client/postcss.config.js b/apps/desktop-client/postcss.config.js new file mode 100644 index 000000000..2aa7205d4 --- /dev/null +++ b/apps/desktop-client/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/apps/desktop-client/public/vite.svg b/apps/desktop-client/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/apps/desktop-client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/desktop-client/src/App.css b/apps/desktop-client/src/App.css new file mode 100644 index 000000000..b9d355df2 --- /dev/null +++ b/apps/desktop-client/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/apps/desktop-client/src/App.tsx b/apps/desktop-client/src/App.tsx new file mode 100644 index 000000000..e25f329e2 --- /dev/null +++ b/apps/desktop-client/src/App.tsx @@ -0,0 +1,35 @@ +import { useState } from "react"; +import reactLogo from "./assets/react.svg"; +import viteLogo from "/vite.svg"; +import "./App.css"; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> +
+ + Vite logo + + + React logo + +
+

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ); +} + +export default App; diff --git a/apps/desktop-client/src/bindings/ClientEvent.ts b/apps/desktop-client/src/bindings/ClientEvent.ts new file mode 100644 index 000000000..79d6cfac2 --- /dev/null +++ b/apps/desktop-client/src/bindings/ClientEvent.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ClientEvent = "ClearSearch" | "FocusWindow" | "FolderChosen" | "Navigate" | "RefreshConnections" | "RefreshDiscover" | "RefreshLensLibrary" | "RefreshPluginManager" | "RefreshSearchResults" | "StartupProgress" | "UpdateLensFinished"; diff --git a/apps/desktop-client/src/bindings/ClientInvoke.ts b/apps/desktop-client/src/bindings/ClientInvoke.ts new file mode 100644 index 000000000..aff9ca163 --- /dev/null +++ b/apps/desktop-client/src/bindings/ClientInvoke.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ClientInvoke = "authorize_connection" | "choose_folder" | "default_indices" | "escape" | "open_plugins_folder" | "get_library_stats" | "get_shortcut" | "plugin:tauri-plugin-startup|get_startup_progress" | "plugin:lens-updater|install_lens" | "list_connections" | "plugin:lens-updater|list_installed_lenses" | "plugin:lens-updater|list_installable_lenses" | "list_plugins" | "load_user_settings" | "load_action_settings" | "resize_window" | "resync_connection" | "revoke_connection" | "plugin:lens-updater|run_lens_updater" | "search_docs" | "search_lenses" | "open_folder_path" | "open_lens_folder" | "open_result" | "copy_to_clipboard" | "open_settings_folder" | "plugin:lens-updater|uninstall_lens" | "update_and_restart" | "wizard_finished" | "navigate"; diff --git a/apps/desktop-client/src/bindings/ContextActions.ts b/apps/desktop-client/src/bindings/ContextActions.ts new file mode 100644 index 000000000..032209106 --- /dev/null +++ b/apps/desktop-client/src/bindings/ContextActions.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ContextFilter } from "./ContextFilter"; +import type { UserActionDefinition } from "./UserActionDefinition"; + +export type ContextActions = { context: ContextFilter, actions: Array, }; diff --git a/apps/desktop-client/src/bindings/ContextFilter.ts b/apps/desktop-client/src/bindings/ContextFilter.ts new file mode 100644 index 000000000..1cf57ed14 --- /dev/null +++ b/apps/desktop-client/src/bindings/ContextFilter.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ContextFilter = { has_tag: Array<[string, string]> | null, has_tag_type: Array | null, exclude_tag: Array<[string, string]> | null, exclude_tag_type: Array | null, url_like: Array | null, }; diff --git a/apps/desktop-client/src/bindings/InstallStatus.ts b/apps/desktop-client/src/bindings/InstallStatus.ts new file mode 100644 index 000000000..df0504fbb --- /dev/null +++ b/apps/desktop-client/src/bindings/InstallStatus.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type InstallStatus = "NotInstalled" | { "Finished": { num_docs: number, } } | { "Installing": { percent: number, status: string, } }; diff --git a/apps/desktop-client/src/bindings/LensResult.ts b/apps/desktop-client/src/bindings/LensResult.ts new file mode 100644 index 000000000..8e28a9ad4 --- /dev/null +++ b/apps/desktop-client/src/bindings/LensResult.ts @@ -0,0 +1,29 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { InstallStatus } from "./InstallStatus"; +import type { LensType } from "./LensType"; + +export type LensResult = { +/** + * Author of this lens + */ +author: string, +/** + * Unique identifier + */ +name: string, +/** + * Human readable label + */ +label: string, +/** + * Huamn readable description of the lens + */ +description: string, +/** + * Used to determine whether a lens needs an update + */ +hash: string, +/** + * For installed lenses. + */ +file_path: string | null, categories: Array, html_url: string | null, download_url: string | null, progress: InstallStatus, lens_type: LensType, }; diff --git a/apps/desktop-client/src/bindings/LensType.ts b/apps/desktop-client/src/bindings/LensType.ts new file mode 100644 index 000000000..343bd4e72 --- /dev/null +++ b/apps/desktop-client/src/bindings/LensType.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type LensType = "Lens" | "Plugin" | "API" | "Internal"; diff --git a/apps/desktop-client/src/bindings/SearchMeta.ts b/apps/desktop-client/src/bindings/SearchMeta.ts new file mode 100644 index 000000000..04806f636 --- /dev/null +++ b/apps/desktop-client/src/bindings/SearchMeta.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SearchMeta = { query: string, num_docs: number, wall_time_ms: number, }; diff --git a/apps/desktop-client/src/bindings/SearchResult.ts b/apps/desktop-client/src/bindings/SearchResult.ts new file mode 100644 index 000000000..89fb775ca --- /dev/null +++ b/apps/desktop-client/src/bindings/SearchResult.ts @@ -0,0 +1,11 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SearchResult = { +/** + * Document ID + */ +doc_id: string, +/** + * URI used to crawl this result + */ +crawl_uri: string, domain: string, title: string, description: string, url: string, tags: Array<[string, string]>, score: number, }; diff --git a/apps/desktop-client/src/bindings/SearchResults.ts b/apps/desktop-client/src/bindings/SearchResults.ts new file mode 100644 index 000000000..3f2aa450c --- /dev/null +++ b/apps/desktop-client/src/bindings/SearchResults.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SearchMeta } from "./SearchMeta"; +import type { SearchResult } from "./SearchResult"; + +export type SearchResults = { results: Array, meta: SearchMeta, }; diff --git a/apps/desktop-client/src/bindings/UserAction.ts b/apps/desktop-client/src/bindings/UserAction.ts new file mode 100644 index 000000000..666582f17 --- /dev/null +++ b/apps/desktop-client/src/bindings/UserAction.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type UserAction = { "OpenApplication": [string, string] } | { "OpenUrl": string } | { "CopyToClipboard": string }; diff --git a/apps/desktop-client/src/bindings/UserActionDefinition.ts b/apps/desktop-client/src/bindings/UserActionDefinition.ts new file mode 100644 index 000000000..cc899230a --- /dev/null +++ b/apps/desktop-client/src/bindings/UserActionDefinition.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { UserAction } from "./UserAction"; + +export type UserActionDefinition = { label: string, status_msg: string | null, action: UserAction, key_binding: string, }; diff --git a/apps/desktop-client/src/bindings/UserActionSettings.ts b/apps/desktop-client/src/bindings/UserActionSettings.ts new file mode 100644 index 000000000..d7f77f75a --- /dev/null +++ b/apps/desktop-client/src/bindings/UserActionSettings.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { ContextActions } from "./ContextActions"; +import type { UserActionDefinition } from "./UserActionDefinition"; + +export type UserActionSettings = { actions: Array, context_actions: Array, }; diff --git a/apps/desktop-client/src/components/ConnectionIcon.tsx b/apps/desktop-client/src/components/ConnectionIcon.tsx new file mode 100644 index 000000000..34defe8ae --- /dev/null +++ b/apps/desktop-client/src/components/ConnectionIcon.tsx @@ -0,0 +1,30 @@ +import { ShareIcon } from "@heroicons/react/24/solid"; +import { + SiGithub, + SiGmail, + SiGooglecalendar, + SiGoogledrive, + SiReddit, +} from "@icons-pack/react-simple-icons"; + +interface Props { + connection: string; + className: string; +} + +export function ConnectionIcon({ connection, className }: Props) { + switch (connection) { + case "calendar.google.com": + return ; + case "drive.google.com": + return ; + case "mail.google.com": + return ; + case "api.github.com": + return ; + case "oauth.reddit.com": + return ; + default: + return ; + } +} diff --git a/apps/desktop-client/src/components/FileExtIcon.tsx b/apps/desktop-client/src/components/FileExtIcon.tsx new file mode 100644 index 000000000..467c787a3 --- /dev/null +++ b/apps/desktop-client/src/components/FileExtIcon.tsx @@ -0,0 +1,107 @@ +interface Props { + className: string; + filePath: string; +} + +export function FileExtIcon({ className, filePath }: Props) { + const ext = filePath.split(".").pop() ?? "txt"; + // audio files + if ( + ["aac", "avi", "flac", "m4a", "mp3", "ogg", "wav", "webm"].includes(ext) + ) { + return ( + + + + + + + + ); + } else if (["doc", "docx"].includes(ext)) { + return ( + + + + ); + } else if (["md"].includes(ext)) { + return ( + + + + ); + } else if (["ppt", "pptx"].includes(ext)) { + return ( + + + + ); + } else if (["xls", "xlsx"].includes(ext)) { + return ( + + + + ); + } else if (["pdf"].includes(ext)) { + return ( + + + + ); + } else { + return ( + + + + ); + } +} diff --git a/apps/desktop-client/src/components/KeyComponent.tsx b/apps/desktop-client/src/components/KeyComponent.tsx new file mode 100644 index 000000000..309fe170f --- /dev/null +++ b/apps/desktop-client/src/components/KeyComponent.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from "react"; + +interface Props { + children: ReactNode; +} + +export function KeyComponent({ children }: Props) { + return ( +
+ {children} +
+ ); +} diff --git a/apps/desktop-client/src/error-page.tsx b/apps/desktop-client/src/error-page.tsx new file mode 100644 index 000000000..bc24eb3e5 --- /dev/null +++ b/apps/desktop-client/src/error-page.tsx @@ -0,0 +1,15 @@ +import { ErrorResponse, useRouteError } from "react-router-dom"; + +export default function ErrorPage() { + const error = useRouteError() as Error | ErrorResponse; + console.error(error); + return ( +
+

Oops!

+

Sorry, an unexpected error has occurred.

+

+ {"statusText" in error ? error.statusText : error.message} +

+
+ ); +} diff --git a/apps/desktop-client/src/glue.ts b/apps/desktop-client/src/glue.ts new file mode 100644 index 000000000..994ae6f61 --- /dev/null +++ b/apps/desktop-client/src/glue.ts @@ -0,0 +1,30 @@ +import { + InvokeArgs, + InvokeOptions, + invoke as tauriInvoke, +} from "@tauri-apps/api/core"; +import { + EventCallback, + Options, + listen as tauriListen, + UnlistenFn, +} from "@tauri-apps/api/event"; +import { ClientInvoke } from "./bindings/ClientInvoke"; +import { ClientEvent } from "./bindings/ClientEvent"; + +export async function invoke( + cmd: ClientInvoke, + args?: InvokeArgs, + opts?: InvokeOptions, +): Promise { + return tauriInvoke(cmd, args, opts); +} + +// Some wrappers around tauri functions to make them more type aware. +export async function listen( + event: ClientEvent, + handler: EventCallback, + opts?: Options, +): Promise { + return tauriListen(event, handler, opts); +} diff --git a/apps/desktop-client/src/index.css b/apps/desktop-client/src/index.css new file mode 100644 index 000000000..2ff6f0f5e --- /dev/null +++ b/apps/desktop-client/src/index.css @@ -0,0 +1,46 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +input:checked ~ .dot { + transform: translateX(100%); + background-color: #48bb78; +} + +* { + scrollbar-width: thin; + scrollbar-color: #404040 #171717; +} + +*::-webkit-scrollbar { + width: 10px; +} + +*::-webkit-scrollbar-track { + background: #171717; +} + +*::-webkit-scrollbar-thumb { + background: #404040; + border-radius: 100vh; + border: 2px solid #171717; +} + +*::-webkit-scrollbar-thumb:hover { + background: #164e63; +} + +mark { + color: rgb(255 255 255); + background-color: rgb(14 116 144 / var(--tw-bg-opacity)); + padding-left: 0.125rem; + padding-right: 0.125rem; +} diff --git a/apps/desktop-client/src/main.tsx b/apps/desktop-client/src/main.tsx new file mode 100644 index 000000000..494a90e79 --- /dev/null +++ b/apps/desktop-client/src/main.tsx @@ -0,0 +1,40 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import { SearchPage } from "./pages/search/index.tsx"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import ErrorPage from "./error-page.tsx"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + errorElement: , + }, + { + path: "/progress", + element:
Progress Popup
, + }, + { + path: "/settings:tab", + element:
settings tab
, + }, + { + path: "/startup", + element:
startup
, + }, + { + path: "/updater", + element:
updater
, + }, + { + path: "/wizard", + element:
wizard
, + }, +]); + +createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/apps/desktop-client/src/pages/search/ActionsList.tsx b/apps/desktop-client/src/pages/search/ActionsList.tsx new file mode 100644 index 000000000..2a6ca6509 --- /dev/null +++ b/apps/desktop-client/src/pages/search/ActionsList.tsx @@ -0,0 +1,122 @@ +import { BookOpenIcon } from "@heroicons/react/16/solid"; +import { UserActionDefinition } from "../../bindings/UserActionDefinition"; +import { KeyComponent } from "../../components/KeyComponent"; +import { DEFAULT_ACTION } from "./constants"; + +interface ActionListButtonProps { + isActive: boolean; + onClick?: () => void; +} +export function ActionListButton({ + isActive, + onClick = () => {}, +}: ActionListButtonProps) { + const classes = [ + "flex", + "flex-row", + "items-center", + "border-l", + "text-sm", + "text-neutral-500", + "border-neutral-700", + "px-3", + "ml-3", + "h-8", + isActive ? "bg-stone-800" : "bg-neutral-900", + "hover:bg-stone-800", + ]; + return ( + + ); +} + +interface ActionListProps { + actions: UserActionDefinition[]; + selectedActionIdx: number; + onClick?: (action: UserActionDefinition) => void; +} + +export function ActionsList({ + actions, + selectedActionIdx, + onClick = () => {}, +}: ActionListProps) { + const classes = [ + "absolute", + "bottom-8", + "h-32", + "max-h-screen", + "w-1/2", + "right-0", + "z-20", + "flex", + "flex-col", + "overflow-hidden", + "rounded-tl-lg", + "bg-stone-800", + "border-t-2", + "border-l-2", + "border-neutral-900", + "p-1", + ]; + + return ( +
+
+ onClick(DEFAULT_ACTION)} + /> + {actions.map((action, idx) => ( + onClick(action)} + /> + ))} +
+
+ ); +} + +interface UserActionProps { + action: UserActionDefinition; + isSelected: boolean; + actionId: string; + onClick?: () => void; +} + +function UserActionComponent({ + action, + isSelected, + onClick = () => {}, +}: UserActionProps) { + const classes = [ + "flex", + "flex-col", + "py-2", + "text-sm", + "text-white", + "cursor-pointer", + "active:bg-cyan-900", + "rounded", + isSelected ? "bg-cyan-900" : "bg-stone-800", + ]; + + return ( +
+
+ + {action.label} +
+
+ ); +} diff --git a/apps/desktop-client/src/pages/search/DocumentResultItem.tsx b/apps/desktop-client/src/pages/search/DocumentResultItem.tsx new file mode 100644 index 000000000..08d769ccb --- /dev/null +++ b/apps/desktop-client/src/pages/search/DocumentResultItem.tsx @@ -0,0 +1,150 @@ +import { MagnifyingGlassCircleIcon, StarIcon } from "@heroicons/react/24/solid"; +import { SearchResult } from "../../bindings/SearchResult"; +import { ReactNode } from "react"; +import { FolderIcon } from "@heroicons/react/24/solid"; +import { FileExtIcon } from "../../components/FileExtIcon"; +import { ConnectionIcon } from "../../components/ConnectionIcon"; + +interface Props { + id: string; + onClick: () => void; + result: SearchResult; + isSelected: boolean; +} + +export function DocumentResultItem({ id, onClick, result, isSelected }: Props) { + const url = new URL(result.crawl_uri); + const styles = [ + "flex", + "flex-row", + "gap-4", + "rounded", + "py-2", + "pr-2", + "mt-2", + "text-white", + "cursor-pointer", + "active:bg-cyan-900", + "scroll-mt-2", + isSelected ? "bg-cyan-900" : "bg-neutral-800", + ]; + + return ( + +
+
+ +
+
+
+
{url.hostname}
+

+ {result.title} +

+
+ +
+
+ ); +} + +function DocumentIcon({ result }: { result: SearchResult }) { + const url = new URL(result.crawl_uri); + const iconStyles = ["w-8", "h-8", "m-auto", "mt-2"]; + + // Third-party connections like Reddit/Gmail/etc. + if (url.protocol === "api") { + return ( + + ); + } else if (url.protocol === "file") { + const isDirectory = result.tags + .map( + ([label, value]) => + label.toLowerCase() === "type" && value.toLowerCase() === "directory", + ) + .reduce((prev, cur) => prev || cur, false); + + return isDirectory ? ( + + ) : ( + + ); + } + + return ( + Website + ); +} + +function DocumentMeta({ result }: { result: SearchResult }) { + const priorityTags: ReactNode[] = []; + const normalTags: ReactNode[] = []; + + const types = result.tags.flatMap(([label, value]) => + label.toLowerCase() === "type" ? [value] : [], + ); + + result.tags.forEach(([label, value]) => { + const tag = label.toLowerCase(); + if (tag === "source" || tag === "mimetype") { + return; + } + + if ( + types.findIndex((type) => type === "repository") && + tag === "repository" + ) { + return; + } + + const tagComponent = ( + + ); + if (tag === "favorited") { + priorityTags.push(tagComponent); + } else { + normalTags.push(tagComponent); + } + }); + + return ( +
+ {[...priorityTags, ...normalTags]} +
+ ); +} + +function DocumentTag({ label, value }: { label: string; value: string }) { + if (label.toLowerCase() === "favorited") { + return ( +
+ +
+ ); + } + + const tagLabel = + label === "lens" ? ( + + ) : ( + <>{label} + ); + + return ( +
+
{tagLabel}
+
{value}
+
+ ); +} diff --git a/apps/desktop-client/src/pages/search/LensResultItem.tsx b/apps/desktop-client/src/pages/search/LensResultItem.tsx new file mode 100644 index 000000000..be4eb7113 --- /dev/null +++ b/apps/desktop-client/src/pages/search/LensResultItem.tsx @@ -0,0 +1,21 @@ +import { LensResult } from "../../bindings/LensResult"; + +interface LensResultItemProps { + id: string; + lens: LensResult; + isSelected: boolean; +} + +export function LensResultItem({ id, lens, isSelected }: LensResultItemProps) { + return ( +
+

{lens.label}

+
+ {lens.description} +
+
+ ); +} diff --git a/apps/desktop-client/src/pages/search/SearchStatus.tsx b/apps/desktop-client/src/pages/search/SearchStatus.tsx new file mode 100644 index 000000000..ef827256c --- /dev/null +++ b/apps/desktop-client/src/pages/search/SearchStatus.tsx @@ -0,0 +1,56 @@ +import { ArrowPathIcon } from "@heroicons/react/24/solid"; +import { SearchMeta } from "../../bindings/SearchMeta"; +import { KeyComponent } from "../../components/KeyComponent"; +import { ArrowDownIcon, ArrowUpIcon } from "@heroicons/react/16/solid"; + +interface Props { + meta: SearchMeta | null; + isThinking: boolean; +} + +export function SearchStatus({ meta, isThinking }: Props) { + if (isThinking) { + return ( + <> +
+ + {"Searching..."} +
+
+ {"Use"} + {"/"} + {"to select a lens. Type to search"} +
+ + ); + } + + if (meta) { + return ( +
+
+ {"Searched "} + {meta.num_docs} + {" documents in "} + + {meta.wall_time_ms} + {" ms."} + +
+
+ {"Use"} + + + + {"and"} + + + + {"to select."} +
+
+ ); + } else { + return null; + } +} diff --git a/apps/desktop-client/src/pages/search/SelectedLens.tsx b/apps/desktop-client/src/pages/search/SelectedLens.tsx new file mode 100644 index 000000000..6b2f27d0e --- /dev/null +++ b/apps/desktop-client/src/pages/search/SelectedLens.tsx @@ -0,0 +1,22 @@ +interface Props { + lenses: string[]; +} + +export function SelectedLenses({ lenses }: Props) { + if (lenses.length === 0) { + return null; + } + + return ( +
    + {lenses.map((lens) => ( +
  • + {lens} +
  • + ))} +
+ ); +} diff --git a/apps/desktop-client/src/pages/search/constants.tsx b/apps/desktop-client/src/pages/search/constants.tsx new file mode 100644 index 000000000..2021f9d76 --- /dev/null +++ b/apps/desktop-client/src/pages/search/constants.tsx @@ -0,0 +1,8 @@ +import { UserActionDefinition } from "../../bindings/UserActionDefinition"; + +export const DEFAULT_ACTION: UserActionDefinition = { + action: { OpenApplication: ["default", ""] }, + key_binding: "Enter", + label: "Open with default app", + status_msg: "OpenDefaultApplication", +}; diff --git a/apps/desktop-client/src/pages/search/index.tsx b/apps/desktop-client/src/pages/search/index.tsx new file mode 100644 index 000000000..c7cacc242 --- /dev/null +++ b/apps/desktop-client/src/pages/search/index.tsx @@ -0,0 +1,362 @@ +import { KeyboardEvent, useCallback, useEffect, useRef, useState } from "react"; +import { invoke, listen } from "../../glue"; +import { UserActionDefinition } from "../../bindings/UserActionDefinition"; +import { LensResult } from "../../bindings/LensResult"; +import { SearchResults } from "../../bindings/SearchResults"; +import { SearchMeta } from "../../bindings/SearchMeta"; +import { SearchResult } from "../../bindings/SearchResult"; +import { SelectedLenses } from "./SelectedLens"; +import { SearchStatus } from "./SearchStatus"; +import { DocumentResultItem } from "./DocumentResultItem"; +import { LensResultItem } from "./LensResultItem"; +import { UserActionSettings } from "../../bindings/UserActionSettings"; +import { ActionListButton, ActionsList } from "./ActionsList"; +import { DEFAULT_ACTION } from "./constants"; +import Handlebars from "handlebars"; + +const LENS_SEARCH_PREFIX: string = "/"; +const QUERY_DEBOUNCE_MS: number = 256; +const SEARCH_MIN_CHARS: number = 2; + +enum ResultDisplay { + None, + Documents, + Lenses, +} + +// pressed_key: None, +// executed_key: None, +// executed_action: None, +// modifier: ModifiersState::empty(), +// show_actions: false, +// selected_action_idx: 0, +// action_menu_button_selected: false, + +export function SearchPage() { + const searchInput = useRef(null); + const searchWrapperRef = useRef(null); + + const [selectedIdx, setSelectedIdx] = useState(0); + const [selectedLenses, setSelectedLenses] = useState([]); + + const [docResults, setDocResults] = useState([]); + const [lensResults, setLensResults] = useState([]); + const [resultMode, setResultMode] = useState( + ResultDisplay.None, + ); + + const [isThinking, setIsThinking] = useState(false); + const [showActions, setShowActions] = useState(false); + + const [userActions, setUserActions] = useState([]); + + const [selectedActionIdx, setSelectedActionIdx] = useState(0); + const [searchMeta, setSearchMeta] = useState(null); + + const [query, setQuery] = useState(""); + + const requestResize = async () => { + if (searchWrapperRef.current) { + const height = searchWrapperRef.current.offsetHeight; + await invoke("resize_window", { height }); + } + }; + + // Clear search results + const clearResults = useCallback(async () => { + setResultMode(ResultDisplay.None); + setSelectedIdx(0); + setDocResults([]); + setLensResults([]); + setShowActions(false); + setSelectedActionIdx(0); + setSearchMeta(null); + await requestResize(); + }, []); + + // Clear search queries & results + const clearQuery = useCallback(async () => { + setQuery(""); + await clearResults(); + + if (searchInput.current) { + searchInput.current.value = ""; + } + await requestResize(); + }, [clearResults, searchInput]); + + const moveSelectionUp = () => { + if (showActions) { + // Actions start at idx 1 since the default action (open) is always 0 + setSelectedActionIdx((idx) => (idx > 0 ? idx - 1 : idx)); + } else { + // notihng to do + if (resultMode === ResultDisplay.None) { + return; + } + setSelectedIdx((idx) => (idx > 0 ? idx - 1 : idx)); + } + }; + + const moveSelectionDown = () => { + if (showActions) { + // default + number of actions + const max = 1 + (userActions.length - 1); + setSelectedActionIdx((idx) => (idx < max ? idx + 1 : max)); + } else { + let max = 0; + if (resultMode === ResultDisplay.Documents) { + max = docResults.length - 1; + } else if (resultMode === ResultDisplay.Lenses) { + max = lensResults.length - 1; + } + setSelectedIdx((idx) => (idx < max ? idx + 1 : max)); + } + }; + + const handleKeyEvent = async (event: KeyboardEvent) => { + if (event.type === "keydown") { + const key = event.key; + if ( + // ArrowXX: Prevent cursor from moving around + key === "ArrowUp" || + key === "ArrowDown" || + // Tab: Prevent search box from losing focus + key === "Tab" + ) { + event.preventDefault(); + } + + switch (event.key) { + case "ArrowUp": + moveSelectionUp(); + break; + case "ArrowDown": + moveSelectionDown(); + break; + case "Enter": + // do action or handle selection + if (showActions) { + // handle whichever action is selected. + const action = + selectedActionIdx === 0 + ? DEFAULT_ACTION + : userActions[selectedActionIdx - 1]; + handleSelectedAction(action); + } else { + if (resultMode === ResultDisplay.Documents) { + const selected = docResults[selectedIdx]; + await invoke("open_result", { url: selected.url }); + clearQuery(); + await invoke("escape"); + } else if (resultMode === ResultDisplay.Lenses) { + const selected = lensResults[selectedIdx]; + setSelectedLenses((lenses) => [...lenses, selected.label]); + clearQuery(); + } + } + break; + case "Escape": + // Close action menu if we're in it. + if (showActions) { + setShowActions(false); + // otherwise close the window. + } else { + clearQuery(); + await invoke("escape"); + } + break; + case "Backspace": + // handle clearing lenses + if (query.length === 0 && selectedLenses.length > 0) { + setSelectedLenses([]); + } + break; + case "Tab": + // Handle tab completion for len search/results + if (resultMode === ResultDisplay.Lenses) { + const selected = lensResults[selectedIdx]; + setSelectedLenses((lenses) => [...lenses, selected.label]); + clearQuery(); + // Jump to action menu + } else if (resultMode === ResultDisplay.Documents) { + setShowActions(true); + } + break; + } + } else if (event.type === "keyup") { + // handle keyup events. + } + }; + + const handleSelectedAction = async (action: UserActionDefinition) => { + console.debug("handling action: ", action); + // Get the context for the action execution + const selectedDoc = docResults[selectedIdx]; + // open in application + if ("OpenApplication" in action.action) { + const url = selectedDoc.url; + const [app] = action.action.OpenApplication; + await invoke("open_result", { url, application: app }); + // Open url + } else if ("OpenUrl" in action.action) { + const url = action.action.OpenUrl; + await invoke("open_result", { url, application: null }); + } else if ("CopyToClipboard" in action.action) { + const template = Handlebars.compile(action.action.CopyToClipboard); + await invoke("copy_to_clipboard", { txt: template(selectedDoc) }); + } + + setShowActions(false); + }; + + const handleUpdateQuery = () => { + if (searchInput.current) { + setQuery(searchInput.current.value); + } + }; + + // when the query changes shoot it over to the server. + useEffect(() => { + if (query.length === 0) { + clearResults(); + } + + const timer = setTimeout(async () => { + if (query.startsWith(LENS_SEARCH_PREFIX)) { + setIsThinking(true); + // search lenses. + const trimmedQuery = query.substring( + LENS_SEARCH_PREFIX.length, + query.length, + ); + const results = await invoke("search_lenses", { + query: trimmedQuery, + }); + setResultMode(ResultDisplay.Lenses); + setLensResults(results); + setIsThinking(false); + } else if (query.length >= SEARCH_MIN_CHARS) { + setIsThinking(true); + // search docs + const resp = await invoke("search_docs", { + query, + lenses: selectedLenses, + }); + setResultMode(ResultDisplay.Documents); + setDocResults(resp.results); + setSearchMeta(resp.meta); + setIsThinking(false); + } + }, QUERY_DEBOUNCE_MS); + return () => clearTimeout(timer); + }, [query, selectedLenses, clearQuery, clearResults]); + + useEffect(() => { + requestResize(); + }, [docResults, lensResults]); + + // Scroll to the current selected result. + useEffect(() => { + const element = document.getElementById(`result-${selectedIdx}`); + if (element) { + element.scrollIntoView(true); + } + }, [selectedIdx]); + + useEffect(() => { + // get_action_list + const fetchUserActions = async () => { + const userActions = await invoke( + "load_action_settings", + ); + setUserActions(userActions.actions); + }; + + const initialize = async () => { + // Listen to refresh search results event + await listen("RefreshSearchResults", () => { + console.log("refreshsearchresults received"); + }); + await listen("ClearSearch", () => { + clearResults(); + }); + await listen("FocusWindow", () => { + searchInput.current?.focus(); + }); + + await fetchUserActions(); + }; + initialize().catch(console.error); + }); + + return ( +
searchInput.current?.focus()} + > +
+ + searchInput.current?.focus()} + spellCheck={false} + tabIndex={-1} + /> +
+ {resultMode === ResultDisplay.Documents ? ( +
+
+ {docResults.map((doc, idx) => ( + {}} + result={doc} + isSelected={selectedIdx === idx} + /> + ))} +
+
+ ) : null} + {resultMode === ResultDisplay.Lenses ? ( +
+
+ {lensResults.map((lens, idx) => ( + + ))} +
+
+ ) : null} +
+ + {searchMeta ? ( + setShowActions((val) => !val)} + /> + ) : null} +
+ {showActions ? ( + + ) : null} +
+ ); +} diff --git a/apps/desktop-client/src/vite-env.d.ts b/apps/desktop-client/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/apps/desktop-client/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/desktop-client/tailwind.config.js b/apps/desktop-client/tailwind.config.js new file mode 100644 index 000000000..7552d9565 --- /dev/null +++ b/apps/desktop-client/tailwind.config.js @@ -0,0 +1,51 @@ +/** @type {import('tailwindcss').Config} */ +import formsPlugin from "@tailwindcss/forms"; + +export default { + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + theme: { + minWidth: { + 4: "1rem", + 5: "1.25rem", + }, + extend: { + keyframes: { + "fade-in": { + "0%": { + opacity: "0", + transform: "translateY(10px)", + }, + "100%": { + opacity: "1", + transform: "translateY(0)", + }, + }, + wiggle: { + "0%, 100%": { transform: "rotate(-6deg)" }, + "50%": { transform: "rotate(6deg)" }, + }, + }, + animation: { + "fade-in": "fade-in 0.5s ease-out", + "wiggle-short": "wiggle 1s ease-in-out 10", + wiggle: "wiggle 1s ease-in-out infinite", + }, + }, + fontSize: { + // 10px + xs: "0.625rem", + // 12px + sm: "0.75rem", + // 14px + base: "0.875rem", + // 16px + lg: "1rem", + xl: "1.125rem", + "2xl": "1.25rem", + "3xl": "1.5rem", + "4xl": "1.875rem", + "5xl": "2rem", + }, + }, + plugins: [formsPlugin], +}; diff --git a/apps/desktop-client/tsconfig.app.json b/apps/desktop-client/tsconfig.app.json new file mode 100644 index 000000000..f867de0dd --- /dev/null +++ b/apps/desktop-client/tsconfig.app.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/apps/desktop-client/tsconfig.json b/apps/desktop-client/tsconfig.json new file mode 100644 index 000000000..1ffef600d --- /dev/null +++ b/apps/desktop-client/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/apps/desktop-client/tsconfig.node.json b/apps/desktop-client/tsconfig.node.json new file mode 100644 index 000000000..abcd7f0da --- /dev/null +++ b/apps/desktop-client/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/apps/desktop-client/vite.config.ts b/apps/desktop-client/vite.config.ts new file mode 100644 index 000000000..ed45ac97b --- /dev/null +++ b/apps/desktop-client/vite.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; + +const host = process.env.TAURI_DEV_HOST; + +// https://vite.dev/config/ +export default defineConfig({ + // prevent vite from obscuring rust errors + clearScreen: false, + // Env variables starting with the item of `envPrefix` will be exposed in tauri's source code through `import.meta.env`. + envPrefix: ["VITE_", "TAURI_ENV_*"], + build: { + outDir: "dist", + // Tauri uses Chromium on Windows and WebKit on macOS and Linux + target: + process.env.TAURI_ENV_PLATFORM == "windows" ? "chrome105" : "safari13", + // don't minify for debug builds + minify: !process.env.TAURI_ENV_DEBUG ? "esbuild" : false, + // produce sourcemaps for debug builds + sourcemap: !!process.env.TAURI_ENV_DEBUG, + }, + plugins: [react()], + server: { + // Tauri expects a fixed port, fail if that port is not available + strictPort: true, + // if the host Tauri is expecting is set, use it + host: host || false, + port: 5173, + }, +}); diff --git a/apps/tauri/src/window.rs b/apps/tauri/src/window.rs index dcce4052d..4df69b2d5 100644 --- a/apps/tauri/src/window.rs +++ b/apps/tauri/src/window.rs @@ -97,7 +97,7 @@ pub fn get_searchbar(app: &AppHandle) -> WebviewWindow { .title("Spyglass") .decorations(false) .transparent(true) - .visible(false) + .visible(true) // .disable_file_drop_handler() .inner_size(640.0, 108.0) .build() diff --git a/apps/tauri/tauri.conf.json b/apps/tauri/tauri.conf.json index 8d1c0f007..83108a7d7 100644 --- a/apps/tauri/tauri.conf.json +++ b/apps/tauri/tauri.conf.json @@ -33,10 +33,10 @@ "createUpdaterArtifacts": "v1Compatible" }, "build": { - "devUrl": "http://localhost:8080", - "frontendDist": "../../crates/client/dist", - "beforeDevCommand": "cd ../../crates/client && trunk serve", - "beforeBuildCommand": "cd ../../crates/client && trunk build" + "devUrl": "http://localhost:5173", + "frontendDist": "../desktop-client/dist", + "beforeDevCommand": "cd ../desktop-client && npm run dev", + "beforeBuildCommand": "cd ../desktop-client && npm run build" }, "productName": "Spyglass", "mainBinaryName": "Spyglass", diff --git a/apps/web/.cargo/config.toml b/apps/web/.cargo/config.toml deleted file mode 100644 index aa59d2ee1..000000000 --- a/apps/web/.cargo/config.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build] -target = "wasm32-unknown-unknown" - diff --git a/apps/web/.gitignore b/apps/web/.gitignore deleted file mode 100644 index d17452757..000000000 --- a/apps/web/.gitignore +++ /dev/null @@ -1 +0,0 @@ -public/main.css diff --git a/apps/web/Cargo.lock b/apps/web/Cargo.lock deleted file mode 100644 index 490729e3e..000000000 --- a/apps/web/Cargo.lock +++ /dev/null @@ -1,2009 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" - -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[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 = "boolinator" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "console_log" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" -dependencies = [ - "log", - "web-sys", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "diff-struct" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a699d33d273c6226fd3e8f310a9c90ca94f72be84f7aed95b22bb676f34fc90" -dependencies = [ - "diff_derive", - "num", - "serde", -] - -[[package]] -name = "diff_derive" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe165e7ead196bbbf44c7ce11a7a21157b5c002ce46d7098ff9c556784a4912d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "directories" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[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.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "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.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gloo" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" -dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", -] - -[[package]] -name = "gloo-console" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" -dependencies = [ - "futures-channel", - "gloo-events", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-history" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7" -dependencies = [ - "gloo-events", - "gloo-utils", - "serde", - "serde-wasm-bindgen 0.4.5", - "serde_urlencoded", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-net" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-render" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-worker" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" -dependencies = [ - "anymap2", - "bincode", - "gloo-console", - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "h2" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "implicit-clone" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" -dependencies = [ - "indexmap", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "ipnet" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" - -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "markdown" -version = "1.0.0-alpha.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de49c677e95e00eaa74c42a0b07ea55e1e0b1ebca5b2cbc7657f288cd714eb" -dependencies = [ - "unicode-id", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.45.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-format" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" -dependencies = [ - "arrayvec", - "itoa", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "openssl" -version = "0.10.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "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.15", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinned" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" -dependencies = [ - "futures", - "rustversion", - "thiserror", -] - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prokio" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" -dependencies = [ - "futures", - "gloo", - "num_cpus", - "once_cell", - "pin-project", - "pinned", - "tokio", - "tokio-stream", - "wasm-bindgen-futures", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "reqwest" -version = "0.11.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" -dependencies = [ - "base64 0.21.0", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "ron" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" -dependencies = [ - "base64 0.13.1", - "bitflags", - "serde", -] - -[[package]] -name = "route-recognizer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" - -[[package]] -name = "rustix" -version = "0.37.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] - -[[package]] -name = "security-framework" -version = "2.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[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 = "shared" -version = "0.1.0" -dependencies = [ - "anyhow", - "bitflags", - "diff-struct", - "directories", - "log", - "num-format", - "regex", - "ron", - "serde", - "serde_json", - "spyglass-lens", - "strum", - "strum_macros", - "url", - "uuid", -] - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spyglass-lens" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2ebbd0eff5a2ebf86cdc693c1b314722aee201702f9746b6309c43e4867f70" -dependencies = [ - "anyhow", - "blake2", - "hex", - "regex", - "ron", - "serde", -] - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.45.0", -] - -[[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-stream" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "ui-components" -version = "0.1.0" -dependencies = [ - "js-sys", - "shared", - "url", - "wasm-bindgen-futures", - "yew", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-id" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "uuid" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb" -dependencies = [ - "getrandom", - "serde", - "wasm-bindgen", -] - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "web" -version = "0.1.0" -dependencies = [ - "console_log", - "futures", - "gloo", - "gloo-net", - "log", - "markdown", - "reqwest", - "serde", - "serde-wasm-bindgen 0.5.0", - "serde_json", - "shared", - "strum", - "strum_macros", - "thiserror", - "ui-components", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew", - "yew-router", -] - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[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.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "yew" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" -dependencies = [ - "console_error_panic_hook", - "futures", - "gloo", - "implicit-clone", - "indexmap", - "js-sys", - "prokio", - "rustversion", - "serde", - "slab", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew-macro", -] - -[[package]] -name = "yew-macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" -dependencies = [ - "boolinator", - "once_cell", - "prettyplease", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "yew-router" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426ee0486d2572a6c5e39fbdbc48b58d59bb555f3326f54631025266cf04146e" -dependencies = [ - "gloo", - "js-sys", - "route-recognizer", - "serde", - "serde_urlencoded", - "tracing", - "wasm-bindgen", - "web-sys", - "yew", - "yew-router-macro", -] - -[[package]] -name = "yew-router-macro" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b249cdb39e0cddaf0644dedc781854524374664793479fdc01e6a65d6e6ae3" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] diff --git a/apps/web/Cargo.toml b/apps/web/Cargo.toml deleted file mode 100644 index df8c447c7..000000000 --- a/apps/web/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "web" -version = "0.1.0" -edition = "2021" - -[dependencies] -dotenv_codegen = "0.15.0" -"shared" = { path = "../../crates/shared" } -chrono = { workspace = true } -console_log = "1.0" -futures = "0.3" -gloo = "0.8.0" -js-sys = "0.3" -log = { workspace = true } -markdown = "1.0.0-alpha.7" -reqwest = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -strum = { workspace = true } -strum_macros = { workspace = true } -thiserror = "1.0" -ui-components = { path = "../../crates/ui-components" } -url = "2.3" -wasm-bindgen = "0.2.83" -wasm-bindgen-futures = "0.4.33" -serde-wasm-bindgen = "0.5" -uuid = { workspace =true, features = ["v4"], default-features = false } -web-sys = { version = "0.3.60", features = ["History", "Navigator", "VisibilityState"] } -yew = { version = "0.20.0", features = ["csr"] } -yew-hooks = "0.2" -yew-router = "0.17" \ No newline at end of file diff --git a/apps/web/Makefile b/apps/web/Makefile deleted file mode 100644 index 970c24dad..000000000 --- a/apps/web/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -.PHONY: deploy - -deploy: - npm run build - trunk build --release - aws s3 cp --recursive dist s3://search.spyglass.fyi diff --git a/apps/web/Trunk.toml b/apps/web/Trunk.toml deleted file mode 100644 index 0292379e0..000000000 --- a/apps/web/Trunk.toml +++ /dev/null @@ -1,4 +0,0 @@ - -[build] -target = "index.html" -dist = "dist" \ No newline at end of file diff --git a/apps/web/build.rs b/apps/web/build.rs deleted file mode 100644 index 590a363af..000000000 --- a/apps/web/build.rs +++ /dev/null @@ -1,38 +0,0 @@ -// build.rs -use std::{ - path::{Path, PathBuf}, - process::Command, -}; - -// https://stackoverflow.com/questions/43577885/is-there-a-cargo-environment-variable-for-the-workspace-directory -fn workspace_dir() -> PathBuf { - let output = std::process::Command::new(env!("CARGO")) - .arg("locate-project") - .arg("--workspace") - .arg("--message-format=plain") - .output() - .unwrap() - .stdout; - let cargo_path = Path::new(std::str::from_utf8(&output).unwrap().trim()); - cargo_path.parent().unwrap().to_path_buf() -} - -fn main() { - let output = Command::new("git") - .args(["rev-parse", "--short", "HEAD"]) - .output(); - let git_hash = if let Ok(Ok(output)) = output.map(|x| String::from_utf8(x.stdout)) { - output - } else { - String::from("N/A") - }; - - let workspace = workspace_dir(); - - // Check for the .env file, and if not present, copy in the template. - if !workspace.join(".env").exists() { - std::fs::copy(workspace.join(".env.template"), workspace.join(".env")).unwrap(); - } - - println!("cargo:rustc-env=GIT_HASH={}", git_hash); -} diff --git a/apps/web/index.html b/apps/web/index.html deleted file mode 100644 index 9f455b796..000000000 --- a/apps/web/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Spyglass Search - - - - - - - - - - - - - - - - - - - diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json deleted file mode 100644 index a80566a03..000000000 --- a/apps/web/package-lock.json +++ /dev/null @@ -1,1820 +0,0 @@ -{ - "name": "web", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "devDependencies": { - "@tailwindcss/forms": "^0.5.2", - "@tailwindcss/typography": "^0.5.9", - "tailwindcss": "^3.0.24" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "dependencies": { - "mini-svg-data-uri": "^1.2.3" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" - } - }, - "node_modules/@tailwindcss/typography": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.9.tgz", - "integrity": "sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==", - "dev": true, - "dependencies": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "postcss-selector-parser": "6.0.10" - }, - "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" - } - }, - "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "dev": true, - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true, - "bin": { - "mini-svg-data-uri": "cli.js" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", - "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", - "dev": true, - "dependencies": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.17.2", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1", - "sucrase": "^3.29.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - } - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tailwindcss/forms": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.3.tgz", - "integrity": "sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==", - "dev": true, - "requires": { - "mini-svg-data-uri": "^1.2.3" - } - }, - "@tailwindcss/typography": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.9.tgz", - "integrity": "sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==", - "dev": true, - "requires": { - "lodash.castarray": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.merge": "^4.6.2", - "postcss-selector-parser": "6.0.10" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", - "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "dev": true - }, - "lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "lodash.castarray": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", - "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-import": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", - "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - } - }, - "postcss-nested": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", - "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.10" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "requires": { - "pify": "^2.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dev": true, - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tailwindcss": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", - "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", - "dev": true, - "requires": { - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.17.2", - "lilconfig": "^2.0.6", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.0.9", - "postcss-import": "^14.1.0", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.4", - "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.1", - "sucrase": "^3.29.0" - } - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - } - } -} diff --git a/apps/web/package.json b/apps/web/package.json deleted file mode 100644 index 02cf44a4e..000000000 --- a/apps/web/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "scripts": { - "build": "tailwindcss -i src-css/main.css -o ./public/main.css --minify", - "watch": "tailwindcss -i src-css/main.css -o ./public/main.css --minify --watch" - }, - "devDependencies": { - "@tailwindcss/forms": "^0.5.2", - "@tailwindcss/typography": "^0.5.9", - "tailwindcss": "^3.0.24" - } -} diff --git a/apps/web/public/auth.js b/apps/web/public/auth.js deleted file mode 100644 index 6d83d6175..000000000 --- a/apps/web/public/auth.js +++ /dev/null @@ -1,61 +0,0 @@ -export function init_env(domain, client_id, redirect_uri, audience) { - window.AUTH0 = { - domain, - client_id, - redirect_uri, - audience - }; -} - -async function get_client() { - let client = await auth0 - .createAuth0Client({ - domain: window.AUTH0.domain, - clientId: window.AUTH0.client_id, - useRefreshTokens: true, - cacheLocation: 'localstorage', - authorizationParams: { - audience: window.AUTH0.audience, - redirect_uri: window.AUTH0.redirect_uri, - }, - }); - - return client; -} - -export async function check_login() { - return await get_client().then(async client => { - const isAuthenticated = await client.isAuthenticated(); - if (isAuthenticated) { - console.log('user is already logged in, refreshing state'); - const userProfile = await client.getUser(); - const token = await client.getTokenSilently(); - return { isAuthenticated, userProfile, token }; - } - return null; - }); -} - -export async function auth0_login() { - await get_client().then(client => client.loginWithRedirect()); -} - -export async function auth0_logout() { - await get_client().then(client => client.logout()); -} - -export async function handle_login_callback() { - return await get_client() - .then(async client => { - await client.handleRedirectCallback(); - - const isAuthenticated = await client.isAuthenticated(); - const userProfile = await client.getUser(); - const token = await client.getTokenSilently(); - return { isAuthenticated, userProfile, token }; - }) - .catch(err => { - console.error('handle_login_callback: ', err); - throw err; - }); -} \ No newline at end of file diff --git a/apps/web/public/favicon.png b/apps/web/public/favicon.png deleted file mode 100644 index 11f38b911..000000000 Binary files a/apps/web/public/favicon.png and /dev/null differ diff --git a/apps/web/public/favicon.svg b/apps/web/public/favicon.svg deleted file mode 100644 index af82b1ba7..000000000 --- a/apps/web/public/favicon.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/apps/web/public/gapi.js b/apps/web/public/gapi.js deleted file mode 100644 index 2ddee176b..000000000 --- a/apps/web/public/gapi.js +++ /dev/null @@ -1,63 +0,0 @@ -let tokenClient; -let accessToken = null; -let CLIENT_ID = null; -let API_KEY = null; - -export function init_gapi(client_id, api_key) { - gapi.load('picker'); - CLIENT_ID = client_id; - API_KEY = api_key; - tokenClient = google.accounts.oauth2.initTokenClient({ - client_id: CLIENT_ID, - scope: 'email https://www.googleapis.com/auth/drive.readonly', - callback: '', // defined later - }); -} - -function pickerCallback(data) { - let file_id = null; - if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) { - let doc = data[google.picker.Response.DOCUMENTS][0]; - file_id = doc[google.picker.Document.ID]; - } - return file_id; -} - -export function create_picker(callback) { - const showPicker = () => { - let view = new google.picker.DocsView() - .setIncludeFolders(true) - .setSelectFolderEnabled(true); - - const picker = new google.picker.PickerBuilder() - .addView(view) - .setOAuthToken(accessToken) - .setDeveloperKey(API_KEY) - .setCallback((data) => { - let result = pickerCallback(data); - if (result) { - callback(accessToken, result) - }; - }) - .build(); - picker.setVisible(true); - } - - // Request an access token. - tokenClient.callback = async (response) => { - if (response.error !== undefined) { - throw (response); - } - accessToken = response.access_token; - showPicker(); - }; - - if (accessToken === null) { - // Prompt the user to select a Google Account and ask for consent to share their data - // when establishing a new session. - tokenClient.requestAccessToken({prompt: 'consent'}); - } else { - // Skip display of account chooser and consent dialog for an existing session. - tokenClient.requestAccessToken({prompt: ''}); - } -} \ No newline at end of file diff --git a/apps/web/public/icons/logo@2x.png b/apps/web/public/icons/logo@2x.png deleted file mode 100644 index d21d0694b..000000000 Binary files a/apps/web/public/icons/logo@2x.png and /dev/null differ diff --git a/apps/web/public/utils.js b/apps/web/public/utils.js deleted file mode 100644 index 3bdd1c79a..000000000 --- a/apps/web/public/utils.js +++ /dev/null @@ -1,10 +0,0 @@ - -export function download_file(url, filename) { - const link = document.createElement('a'); - link.href = url; - link.download = filename; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); -} \ No newline at end of file diff --git a/apps/web/src-css/main.css b/apps/web/src-css/main.css deleted file mode 100644 index 07a041e6e..000000000 --- a/apps/web/src-css/main.css +++ /dev/null @@ -1,69 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -input:checked ~ .dot { - transform: translateX(100%); - background-color: #48bb78; -} - -* { - scrollbar-width: thin; - scrollbar-color: #404040 #171717; -} - -*::-webkit-scrollbar { - width: 10px; -} - -*::-webkit-scrollbar-track { - background: #171717; -} - -*::-webkit-scrollbar-thumb { - background: #404040; - border-radius: 100vh; - border: 2px solid #171717; -} - -*::-webkit-scrollbar-thumb:hover { - background: #164e63; -} - -.light-mode * { - scrollbar-width: thin; - scrollbar-color: #404040 white; -} - -.light-mode *::-webkit-scrollbar-track { - background: white; -} - -.light-mode *::-webkit-scrollbar-thumb { - background: lightgray; - border-radius: 100vh; - border: 2px solid #171717; -} - -.light-mode *::-webkit-scrollbar-thumb:hover { - background: darkgray; -} - -mark { - color: rgb(255 255 255); - background-color: rgb(14 116 144 / var(--tw-bg-opacity)); - padding-left: 0.125rem; - padding-right: 0.125rem; -} - -:root .light-mode { - --spy-primary-background: #fafafa; - --spy-light: #e4e5f1; - --spy-mid: #d2d3db; - --spy-dark: #9394a5; - --spy-darker: #484b6a; -} - -:root .dark-mode { - --spy-primary-background: #383838; -} \ No newline at end of file diff --git a/apps/web/src/client.rs b/apps/web/src/client.rs deleted file mode 100644 index 5f4d2aa0b..000000000 --- a/apps/web/src/client.rs +++ /dev/null @@ -1,605 +0,0 @@ -use std::str::Utf8Error; -use std::time::Duration; - -use dotenv_codegen::dotenv; -use futures::io::BufReader; -use futures::{select, AsyncBufReadExt, FutureExt, StreamExt, TryStreamExt}; -use gloo::file::{Blob, ObjectUrl}; -use gloo::timers::future::sleep; -use reqwest::Client; -use serde::{Deserialize, Serialize}; -use shared::request::{AskClippyRequest, ClippyContext}; -use shared::response::{ChatUpdate, SearchResult}; -use thiserror::Error; -use yew::platform::pinned::mpsc::UnboundedReceiver; - -use crate::components::file_upload::FileDetails; -use crate::pages::search::{HistoryItem, HistorySource, WorkerCmd}; -use crate::schema::{ - EmbedConfiguration, GetLensSourceRequest, GetLensSourceResponse, LensSourceQueryFilter, -}; -use reqwest::multipart::Part; - -#[allow(clippy::enum_variant_names)] -#[derive(Error, Debug)] -pub enum ClientError { - #[error("HTTP request error: {0}")] - HttpError(#[from] reqwest::Error), - #[error("RequestError: {0}")] - RequestError(#[from] serde_json::Error), - #[error("Received malformed data: {0}")] - StreamError(#[from] Utf8Error), -} - -pub type ChatUpdateCallback = dyn Fn(ChatUpdate); - -pub struct SpyglassClient { - client: Client, - lens: String, - endpoint: String, - auth: Option, - session_uuid: String, - public_api: bool, -} - -impl SpyglassClient { - pub fn new(lens: String, session_uuid: String, auth: Option, public_api: bool) -> Self { - let client = Client::new(); - - #[cfg(debug_assertions)] - let endpoint = dotenv!("SPYGLASS_BACKEND_DEV"); - #[cfg(not(debug_assertions))] - let endpoint = dotenv!("SPYGLASS_BACKEND_PROD"); - - Self { - client, - lens, - endpoint: endpoint.to_string(), - auth, - session_uuid, - public_api, - } - } - - pub async fn followup( - &mut self, - followup: &str, - history: &[HistoryItem], - doc_context: &[SearchResult], - chat_uuid: &Option, - callback: &ChatUpdateCallback, - channel: UnboundedReceiver, - ) -> Result<(), ClientError> { - let mut context = history - .iter() - .filter(|x| x.source != HistorySource::System) - .map(|x| ClippyContext::History(x.source.to_string(), x.value.clone())) - .collect::>(); - - // Add urls to context - for result in doc_context.iter() { - context.push(ClippyContext::DocId(result.doc_id.clone())); - } - - let body = AskClippyRequest { - query: followup.to_string(), - lens: Some(vec![self.lens.clone()]), - context, - request_uuid: chat_uuid.clone(), - }; - - self.handle_request(&body, callback, channel).await - } - - pub async fn search( - &mut self, - query: &str, - callback: &ChatUpdateCallback, - channel: UnboundedReceiver, - ) -> Result<(), ClientError> { - let body = AskClippyRequest { - query: query.to_string(), - lens: Some(vec![self.lens.clone()]), - context: Vec::new(), - request_uuid: None, - }; - - self.handle_request(&body, callback, channel).await - } - - async fn handle_request( - &mut self, - body: &AskClippyRequest, - callback: &ChatUpdateCallback, - mut channel: UnboundedReceiver, - ) -> Result<(), ClientError> { - let url = if self.public_api { - format!("{}/api/v1/chat", self.endpoint) - } else { - format!("{}/chat", self.endpoint) - }; - - let mut request = self.client.post(url).body(serde_json::to_string(&body)?); - - if let Some(auth_token) = &self.auth { - request = request.bearer_auth(auth_token); - } - request = request.header("spyglass-session", self.session_uuid.clone()); - - let resp = request.send().await?; - - let res = resp - .bytes_stream() - .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) - .into_async_read(); - - let mut reader = BufReader::new(res); - let mut running_buffer = String::new(); - loop { - let mut line = String::new(); - let mut read_line = reader.read_line(&mut line).fuse(); - running_buffer.push_str(&line); - - select! { - res = read_line => { - if res.is_err() { - break; - } - - let line = running_buffer.trim_end_matches(|c| c == '\r' || c == '\n'); - let line = line.strip_prefix("data:").unwrap_or(line); - if line.is_empty() { - running_buffer.clear(); - continue; - } - - let update = serde_json::from_str::(line)?; - callback(update.clone()); - match update { - ChatUpdate::Error(_) | ChatUpdate::EndOfText => { - break; - } - _ => () - } - - running_buffer.clear(); - // give ui thread a chance to do something - sleep(Duration::from_millis(50)).await; - } - _ = channel.next() => { - // aborting response generation - break; - } - } - } - - Ok(()) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct Lens { - pub id: i64, - pub name: String, - pub display_name: String, - pub example_questions: Vec, - pub example_docs: Vec, - pub is_public: bool, - pub image: Option, - pub description: Option, - pub embedded_configuration: Option, -} - -/// Chat history for a single chat session -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct ChatHistoryEntry { - pub qna: Vec, - pub lenses: Vec, - pub session_id: String, - pub last_updated_at: String, -} - -/// Individual question and answer for a Chat -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] -pub struct QuestionAndAnswer { - pub question: String, - pub response: String, - pub successful: bool, - pub created_at: String, - pub documents: Vec, - pub document_details: Option>, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct UserData { - pub lenses: Vec, - pub history: Vec, -} - -#[allow(clippy::enum_variant_names)] -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PreferredModel { - WhisperSmall, - WhisperMedium, - WhisperLarge, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub enum LensAddDocType { - Audio, - /// Token is used to download the document from GDrive. - GDrive { - token: String, - }, - RssFeed { - preferred_model: PreferredModel, - }, - /// Normal, web accessible URL. - WebUrl { - include_all_suburls: bool, - }, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct LensAddDocument { - pub doc_type: LensAddDocType, - pub url: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub enum LensDocType { - Audio, - GDrive, - Web, - Upload, -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] -pub struct LensSource { - pub display_name: String, - pub doc_type: LensDocType, - pub url: String, - pub status: String, - pub doc_uuid: String, -} - -#[derive(Deserialize)] -pub struct SourceValidationResponse { - pub url: String, - pub url_count: u64, - pub has_sitemap: Option, - pub is_valid: bool, - pub validation_msg: Option, -} - -#[derive(Error, Debug)] -pub enum ApiError { - #[error("You need to sign in.")] - Unauthorized, - #[error("Unable to make request: {0}")] - RequestError(#[from] reqwest::Error), - #[error("Api Error: {0}")] - ClientError(ApiErrorMessage), - #[error("Unable to make request: {0}")] - Other(String), -} - -#[derive(Clone, Deserialize, Debug)] -pub struct ApiErrorMessage { - pub code: u16, - pub message: String, -} - -impl std::fmt::Display for ApiErrorMessage { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_fmt(format_args!("({}) {}", self.code, self.message)) - } -} - -pub struct ApiClient { - client: reqwest::Client, - endpoint: String, - token: Option, - public_api: bool, -} - -impl ApiClient { - pub fn new(token: Option, public_api: bool) -> Self { - #[cfg(debug_assertions)] - let endpoint: String = dotenv!("SPYGLASS_BACKEND_DEV").into(); - #[cfg(not(debug_assertions))] - let endpoint: String = dotenv!("SPYGLASS_BACKEND_PROD").into(); - - let client = reqwest::Client::new(); - - Self { - client, - endpoint, - token, - public_api, - } - } - - pub async fn lens_create(&self) -> Result { - let mut request = self.client.post(format!("{}/user/lenses", self.endpoint)); - if let Some(auth_token) = &self.token { - request = request.bearer_auth(auth_token); - } - - Ok(request.send().await?.json::().await?) - } - - /// Creates a local in memory object url that represent a downloaded file. - pub async fn download_file(&self, url: &str) -> Result { - let mut request = self - .client - .get(format!("{}/user/lenses{}", self.endpoint, url)); - - if let Some(auth_token) = &self.token { - request = request.bearer_auth(auth_token); - } - - let response = request.send().await; - match response { - Ok(rsp) => { - let bytes = rsp.bytes().await.unwrap(); - let byte_vec = bytes.to_vec(); - let blob = Blob::new(byte_vec.as_slice()); - let url = ObjectUrl::from(blob); - Ok(url) - } - Err(error) => { - log::error!("Error requesting download {:?}", error); - Err(ApiError::Unauthorized) - } - } - } - - /// Deletes the specified lens. This will delete the lens and all associated - /// stored information - pub async fn lens_delete(&self, lens: &str) -> Result { - let mut request = self - .client - .delete(format!("{}/user/lenses/{}", self.endpoint, lens)); - if let Some(auth_token) = &self.token { - request = request.bearer_auth(auth_token); - } - - Ok(request.send().await?.json::().await?) - } - - pub async fn lens_retrieve(&self, id: &str) -> Result { - let url = if self.public_api { - format!("{}/api/v1/lenses/{}", self.endpoint, id) - } else { - format!("{}/user/lenses/{}", self.endpoint, id) - }; - let mut request = self.client.get(url); - if let Some(auth_token) = &self.token { - request = request.bearer_auth(auth_token); - } - - Ok(request - .send() - .await? - .error_for_status()? - .json::() - .await?) - } - - pub async fn lens_retrieve_sources( - &self, - id: &str, - page: usize, - filter: LensSourceQueryFilter, - ) -> Result { - let req = GetLensSourceRequest { page, filter }; - - match &self.token { - Some(token) => Ok(self - .client - .get(format!("{}/user/lenses/{}/sources", self.endpoint, id)) - .query(&req) - .bearer_auth(token) - .send() - .await? - .error_for_status()? - .json::() - .await?), - None => Err(ApiError::Unauthorized), - } - } - - pub async fn lens_add_source( - &self, - lens: &str, - request: &LensAddDocument, - ) -> Result<(), ApiError> { - match &self.token { - Some(token) => { - let resp = self - .client - .post(format!("{}/user/lenses/{}/source", self.endpoint, lens)) - .bearer_auth(token) - .json(request) - .send() - .await?; - - match resp.error_for_status_ref() { - Ok(_) => Ok(()), - Err(err) => match resp.json::().await { - Ok(msg) => Err(ApiError::ClientError(msg)), - Err(_) => Err(ApiError::RequestError(err)), - }, - } - } - None => Ok(()), - } - } - - /// Uploads a document source for the specified lens. - pub async fn upload_source_document( - &self, - lens: &str, - file_info: Box, - ) -> Result<(), ApiError> { - match &self.token { - Some(token) => { - let data = file_info.data; - let name = file_info.name; - let file_type = file_info.file_type; - let mut part = Part::bytes(data); - part = part.file_name(name.clone()); - part = part.mime_str(&file_type)?; - - let form = reqwest::multipart::Form::new().part(name.clone(), part); - - let resp = self - .client - .post(format!("{}/user/lenses/{}/upload", self.endpoint, lens)) - .bearer_auth(token) - .multipart(form) - .send() - .await?; - - match resp.error_for_status_ref() { - Ok(_) => Ok(()), - Err(err) => match resp.json::().await { - Ok(msg) => Err(ApiError::ClientError(msg)), - Err(_) => Err(ApiError::RequestError(err)), - }, - } - } - None => Ok(()), - } - } - - /// Deletes the specified lens source from the specified lens - pub async fn delete_lens_source(&self, lens: &str, source_uuid: &str) -> Result<(), ApiError> { - match &self.token { - Some(token) => { - let resp = self - .client - .delete(format!( - "{}/user/lenses/{}/source/{}", - self.endpoint, lens, source_uuid - )) - .bearer_auth(token) - .send() - .await?; - - match resp.error_for_status_ref() { - Ok(_) => Ok(()), - Err(err) => match resp.json::().await { - Ok(msg) => Err(ApiError::ClientError(msg)), - Err(_) => Err(ApiError::RequestError(err)), - }, - } - } - None => Err(ApiError::Unauthorized), - } - } - - pub async fn validate_lens_source( - &self, - lens: &str, - request: &LensAddDocument, - ) -> Result { - match &self.token { - Some(token) => { - let resp = self - .client - .post(format!( - "{}/user/lenses/{}/validate/source", - self.endpoint, lens - )) - .bearer_auth(token) - .json(request) - .send() - .await?; - - match resp.error_for_status_ref() { - Ok(_) => match resp.json::().await { - Ok(response) => Ok(response), - Err(msg) => Err(ApiError::Other(msg.to_string())), - }, - Err(err) => match resp.json::().await { - Ok(msg) => Err(ApiError::ClientError(msg)), - Err(_) => Err(ApiError::RequestError(err)), - }, - } - } - None => Err(ApiError::Unauthorized), - } - } - - pub async fn lens_update(&self, lens: &str, display_name: &str) -> Result<(), ApiError> { - match &self.token { - Some(token) => { - match self - .client - .patch(format!("{}/user/lenses/{}", self.endpoint, lens)) - .bearer_auth(token) - .json(&serde_json::json!({ "display_name": display_name })) - .send() - .await? - .error_for_status() - { - Ok(_) => Ok(()), - Err(err) => Err(ApiError::RequestError(err)), - } - } - None => Ok(()), - } - } - - pub async fn get_user_data(&self) -> Result { - match &self.token { - Some(token) => { - let request = self - .client - .get(format!("{}/user/lenses", self.endpoint)) - .bearer_auth(token) - .send() - .await? - .error_for_status()? - .json::>() - .await; - - let lenses = match request { - Ok(lenses) => lenses, - Err(err) => { - log::error!("Unable to get lenses: {}", err.to_string()); - Vec::new() - } - }; - - let history_response = self - .client - .get(format!("{}/user/chat/history", self.endpoint)) - .bearer_auth(token) - .send() - .await? - .error_for_status()? - .json::>() - .await; - let history = match history_response { - Ok(history_val) => history_val, - Err(err) => { - log::error!("Unable to access chat history: {}", err.to_string()); - Vec::new() - } - }; - - Ok(UserData { lenses, history }) - } - None => { - log::error!("User is not logged in"); - Ok(UserData { - lenses: Vec::new(), - history: Vec::new(), - }) - } - } - } -} diff --git a/apps/web/src/components/chat_bubble.rs b/apps/web/src/components/chat_bubble.rs deleted file mode 100644 index 0568decd1..000000000 --- a/apps/web/src/components/chat_bubble.rs +++ /dev/null @@ -1,57 +0,0 @@ -use yew::prelude::*; -use yew::virtual_dom::VNode; - -#[derive(Properties, PartialEq)] -pub struct ChatBubbleProps { - pub text: String, - pub background: Option, - pub icon: Option, - #[prop_or_default] - pub classes: Classes, - pub align: ChatAlign, -} - -#[derive(PartialEq)] -pub enum ChatAlign { - Right, - Left, -} - -#[function_component(ChatBubble)] -pub fn nav_bar_component(props: &ChatBubbleProps) -> Html { - let bg_classes = match &props.background { - Some(color) => classes!(color, "text-gray-900"), - None => match &props.align { - ChatAlign::Left => classes!("bg-blue-100", "text-blue-900"), - ChatAlign::Right => classes!("bg-gray-200", "text-gray-900"), - }, - }; - - let style_classes = classes!(bg_classes, "ml-2", "rounded-lg", "p-2"); - match &props.align { - ChatAlign::Left => { - html! { -
-
- User Avatar -
-
-

{props.text.clone()}

-
-
- } - } - ChatAlign::Right => { - html! { -
-
-

{props.text.clone()}

-
-
- Product Image -
-
- } - } - } -} diff --git a/apps/web/src/components/file_upload.rs b/apps/web/src/components/file_upload.rs deleted file mode 100644 index 0475d71fe..000000000 --- a/apps/web/src/components/file_upload.rs +++ /dev/null @@ -1,377 +0,0 @@ -use std::collections::HashMap; - -use gloo::file::callbacks::FileReader; -use gloo::file::File; -use ui_components::btn::{Btn, BtnSize, BtnType}; -use ui_components::icons::{ - BadgeCheckIcon, DocumentPlus, FileExtIcon, RefreshIcon, TrashIcon, XCircle, -}; -use web_sys::{DragEvent, Event, FileList, HtmlInputElement}; -use yew::html::TargetCast; -use yew::platform::spawn_local; -use yew::{classes, html, Callback, Classes, Component, Context, ContextHandle, Html, Properties}; - -use crate::AuthStatus; - -// Maximum number of bytes that can be uploaded 10 MB -const UPLOAD_SIZE_LIMIT: usize = 10_000_000; - -/// Details about the file that is being uploaded, including the content -#[derive(Clone)] -pub struct FileDetails { - pub name: String, - pub file_type: String, - pub data: Vec, - // Indication if the file has been uploaded - pub uploaded: bool, - // Error with the file that will prevent it from being uploaded - pub error: Option, -} - -pub enum Msg { - // When the file is loaded from disk to memory - Loaded(String, String, Vec), - // The files provided by the user - Files(Vec), - // The start of a drag into the drop region - DragStart, - // The end of a drag into the region - DragEnd, - // Deletes a file at the specified index and indicates if it is - // due to successful upload or not - DeleteFile(usize, bool), - // Sends the upload request to the server - UploadFiles, - // Updates the auth status context - UpdateContext(AuthStatus), -} - -pub struct FileUpload { - processing: bool, - readers: HashMap, - files: Vec, - drag_started: bool, - auth_status: AuthStatus, - _context_listener: ContextHandle, -} - -#[derive(Properties, PartialEq)] -pub struct FileUploadProps { - // Lens we are uploading the data for - pub lens_identifier: String, - // Text to show in the upload drop box - #[prop_or(Some(String::from("Drop your files here or click to select")))] - pub upload_text: Option, - // Height of the upload drop box - #[prop_or("h-64".into())] - pub height: String, - // Width of the upload drop box - #[prop_or("w-full".into())] - pub width: String, - // Classes for the main upload drop area - #[prop_or_default] - pub classes: Classes, - // Callback when a file is uploaded. If multiple files are uploaded - // this callback will emit a value for each file that is uploaded - // when the upload is finished - #[prop_or_default] - pub on_upload: Callback>, -} - -impl Component for FileUpload { - type Message = Msg; - type Properties = FileUploadProps; - - fn create(ctx: &Context) -> Self { - // Connect to context for auth details - let (auth_status, context_listener) = ctx - .link() - .context(ctx.link().callback(Msg::UpdateContext)) - .expect("No Message Context Provided"); - - Self { - readers: HashMap::default(), - files: Vec::default(), - auth_status, - processing: false, - drag_started: false, - _context_listener: context_listener, - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - let props = ctx.props(); - - match msg { - Msg::Loaded(file_name, file_type, data) => { - let error = if data.len() > UPLOAD_SIZE_LIMIT { - Some("File to large, maximum size 10 MB".to_string()) - } else { - None - }; - self.files.push(FileDetails { - data, - file_type, - name: file_name.clone(), - uploaded: false, - error, - }); - - self.readers.remove(&file_name); - if self.readers.is_empty() { - self.processing = false; - } - self.drag_started = false; - - true - } - Msg::Files(files) => { - self.processing = true; - for file in files.into_iter() { - let file_name = file.name(); - let file_type = file.raw_mime_type(); - - let task = { - let link = ctx.link().clone(); - let file_name = file_name.clone(); - - gloo::file::callbacks::read_as_bytes(&file, move |res| { - link.send_message(Msg::Loaded( - file_name, - file_type, - res.expect("failed to read file"), - )) - }) - }; - self.readers.insert(file_name, task); - } - true - } - Msg::DragStart => { - log::error!("Drag start event"); - self.drag_started = true; - true - } - Msg::DragEnd => { - log::error!("Drag end event"); - self.drag_started = false; - true - } - Msg::DeleteFile(index, uploaded) => { - if uploaded { - if let Some(file) = self.files.get_mut(index) { - file.uploaded = true; - } - - if !self.files.iter().any(|file| !file.uploaded) { - self.files.clear(); - self.processing = false; - } - } else { - self.files.remove(index); - } - - true - } - Msg::UploadFiles => { - self.processing = true; - - for (index, file) in self.files.iter().enumerate() { - let client = self.auth_status.get_client(); - let file = Box::new(file.clone()); - let lens = props.lens_identifier.clone(); - let upload_callback = props.on_upload.clone(); - let link = ctx.link().clone(); - spawn_local(async move { - if let Err(error) = client.upload_source_document(&lens, file.clone()).await - { - log::error!("Got error uploading document {:?}", error); - } - upload_callback.emit(file); - link.send_message(Msg::DeleteFile(index, true)) - }); - } - - true - } - Msg::UpdateContext(auth_status) => { - self.auth_status = auth_status; - true - } - } - } - - fn view(&self, ctx: &Context) -> Html { - let props = ctx.props(); - let classes = classes!( - "flex", - "justify-center", - "items-center", - "flex-col", - "flex-grow", - "relative", - "hover:cursor-pointer", - "hover:border-slate-400", - "hover:stroke-slate-400", - "hover:text-slate-400", - "border-dashed", - "border-2", - "m-4", - props.classes.clone(), - &props.width, - &props.height, - ); - - let classes = if self.drag_started { - classes!( - classes, - "cursor-pointer", - "border-slate-400", - "stroke-slate-400", - "text-slate-400" - ) - } else { - classes!(classes, "border-white/30", "text-white/30",) - }; - - let upload_text = props.upload_text.clone(); - let has_error = self.files.iter().any(|file| file.error.is_some()); - let is_processing = self.processing; - let upload_documents = ctx.link().callback(move |_| Msg::UploadFiles); - html! { -
-

{"Upload your files"}

- - -
- { for self.files.iter().enumerate().map(|(i, file)| Self::view_file(file, i, ctx)) } -
-
- {if !self.files.is_empty() && has_error { - html! { - - {"Upload"} - - } - } else if !self.files.is_empty() { - html! { - - {"Upload"} - - } - } else { - html! {} - }} -
-
- } - } -} - -impl FileUpload { - fn view_file(file: &FileDetails, index: usize, ctx: &Context) -> Html { - let link = ctx.link().clone(); - let on_delete = Callback::from(move |_| { - link.send_message(Msg::DeleteFile(index, false)); - }); - let ext = file.name.split('.').last().unwrap_or("").to_owned(); - let classes = classes!("w-6", "h-6", "ml-4"); - - let icon = if file.error.is_some() { - html! { } - } else if file.uploaded { - html! { } - } else { - html! { } - }; - - html! { -
- {icon} -
- { if let Some(error) = &file.error { - html! {

{ format!("{} - {}", file.name, error) }

} - } else { - html! {

{ format!("{}", file.name) }

} - }} -
-
- - - -
-
- } - } - - fn upload_files(files: Option) -> Msg { - let mut result = Vec::new(); - - if let Some(files) = files { - let files = js_sys::try_iter(&files) - .unwrap() - .unwrap() - .map(|v| web_sys::File::from(v.unwrap())) - .map(File::from); - result.extend(files); - } - Msg::Files(result) - } -} diff --git a/apps/web/src/components/mod.rs b/apps/web/src/components/mod.rs deleted file mode 100644 index 130e93733..000000000 --- a/apps/web/src/components/mod.rs +++ /dev/null @@ -1,139 +0,0 @@ -use ui_components::{ - btn::{Btn, BtnSize, BtnType}, - icons, -}; -use yew::{platform::spawn_local, prelude::*}; -use yew_router::prelude::use_navigator; - -use crate::{client::Lens, AuthStatus, Route}; - -pub mod chat_bubble; -pub mod file_upload; -pub mod nav; - -#[derive(Properties, PartialEq)] -pub struct LensListProps { - pub lenses: Option>, - #[prop_or_default] - pub on_select: Callback, - #[prop_or_default] - pub on_edit: Callback, - #[prop_or_default] - pub on_delete: Callback, - #[prop_or_default] - pub class: Classes, -} - -#[function_component(LensList)] -pub fn lens_list(props: &LensListProps) -> Html { - let navigator = use_navigator().unwrap(); - let is_deleting = use_state_eq(|| false); - let auth_status = use_context::().expect("Ctxt not set up"); - let default_classes = classes!( - "hover:bg-cyan-600", - "cursor-pointer", - "flex", - "flex-grow", - "flex-row", - "items-center", - "py-1.5", - "px-2", - "rounded", - "overflow-hidden", - "whitespace-nowrap", - "text-ellipsis", - props.class.clone(), - ); - - let mut html = Vec::new(); - let lenses = props.lenses.clone(); - for lens in lenses.unwrap_or_default() { - let classes = classes!(default_classes.clone(),); - - let onclick = { - let navi = navigator.clone(); - let lens = lens.clone(); - let on_select = props.on_select.clone(); - - Callback::from(move |_| { - on_select.emit(lens.clone()); - navi.push(&Route::Search { - lens: lens.name.clone(), - }) - }) - }; - - let on_edit = { - let navi = navigator.clone(); - let lens = lens.clone(); - let on_edit = props.on_edit.clone(); - - Callback::from(move |e: MouseEvent| { - e.stop_immediate_propagation(); - on_edit.emit(lens.clone()); - navi.push(&Route::Edit { - lens: lens.name.clone(), - }) - }) - }; - - let on_delete = { - let status = auth_status.clone(); - let lens = lens.clone(); - let is_deleting = is_deleting.clone(); - let on_delete_callback = props.on_delete.clone(); - Callback::from(move |e: MouseEvent| { - e.stop_immediate_propagation(); - let client = status.get_client(); - let lens = lens.clone(); - let is_deleting = is_deleting.clone(); - let on_delete_callback = on_delete_callback.clone(); - spawn_local(async move { - is_deleting.set(true); - let _ = client.lens_delete(&lens.name).await; - is_deleting.set(false); - on_delete_callback.emit(lens); - }) - }) - }; - - let icon = if lens.is_public { - html! { } - } else { - html! { } - }; - - let edit_icon = if lens.is_public { - html! {} - } else { - html! { - <> - - - {"Edit"} - - - {if *is_deleting { - html! {} - } else { - html! { } - }} - {"Delete"} - - - } - }; - - html.push(html! { -
  • - - {icon} -
    {lens.display_name.clone()}
    -
    - {edit_icon} -
  • - }); - } - - html! {
      {html}
    } -} diff --git a/apps/web/src/components/nav.rs b/apps/web/src/components/nav.rs deleted file mode 100644 index 140d3f684..000000000 --- a/apps/web/src/components/nav.rs +++ /dev/null @@ -1,148 +0,0 @@ -use ui_components::icons; -use yew::prelude::*; -use yew_router::prelude::use_navigator; - -use crate::{AuthStatus, Route}; - -#[derive(Properties, PartialEq)] -pub struct NavBarProps { - pub current_lens: Option, - pub session_uuid: String, -} - -#[function_component(NavBar)] -pub fn nav_bar_component(_props: &NavBarProps) -> Html { - let auth_status = use_context::().expect("Ctxt not set up"); - let toggle_nav = use_state(|| false); - let navigator = use_navigator().unwrap(); - - #[cfg(debug_assertions)] - let debug_vars = html! { - <> -
    - {"SPYGLASS_BACKEND: "} - {dotenv!("SPYGLASS_BACKEND_DEV")} -
    - - }; - - #[cfg(not(debug_assertions))] - let debug_vars = html! {}; - - let toggle_nav_cb = { - let toggle_nav_state = toggle_nav.clone(); - Callback::from(move |_| { - let new_state = !(*toggle_nav_state); - toggle_nav_state.set(new_state); - }) - }; - - let mut history_buttons: Vec = Vec::new(); - if auth_status.is_authenticated { - if let Some(user_data) = &auth_status.user_data { - for history in &user_data.history { - if history.lenses.len() == 1 && !history.qna.is_empty() { - let title = history.qna.get(0).unwrap().question.clone(); - let lens = history.lenses.get(0).unwrap().clone(); - let session_id = history.session_id.clone(); - - let nav = navigator.clone(); - let session = session_id.clone(); - let onclick = Callback::from(move |_| { - nav.push(&Route::SearchSession { - lens: lens.clone(), - chat_session: session.clone(), - }) - }); - history_buttons.push(html! { - - }); - } - } - } - } - - html! { - <> -
    - - { if *toggle_nav { - html! { -
    - - - {"Discover"} - - {if auth_status.is_authenticated { - html! { - - - {"Home"} - - } - } else { - html! {} - }} -
    - } - } else { html! {} }} -
    - - - } -} diff --git a/apps/web/src/main.rs b/apps/web/src/main.rs deleted file mode 100644 index ee69d9373..000000000 --- a/apps/web/src/main.rs +++ /dev/null @@ -1,352 +0,0 @@ -#[macro_use] -extern crate dotenv_codegen; - -use client::{Lens, UserData}; -use gloo::utils::{history, window}; -use serde::{Deserialize, Serialize}; -use wasm_bindgen::{prelude::*, JsValue}; -use wasm_bindgen_futures::spawn_local; -use yew::prelude::*; -use yew_router::prelude::*; - -mod client; -mod components; -mod metrics; -mod pages; -mod schema; -mod utils; -use components::nav::NavBar; -use pages::{ - dashboard::Dashboard, discover::DiscoverPage, landing::LandingPage, - lens_editor::CreateLensPage, AppPage, -}; - -use crate::{ - client::ApiClient, - pages::{embedded::EmbeddedPage, search::SearchPage}, - utils::decode_string, -}; - -#[derive(Clone, Serialize, Deserialize, PartialEq)] -pub struct Auth0User { - pub name: String, - pub email: String, - pub picture: String, - pub sub: String, -} - -#[derive(Clone, Default, Serialize, Deserialize, PartialEq)] -pub struct AuthStatus { - #[serde(rename(deserialize = "isAuthenticated"))] - pub is_authenticated: bool, - #[serde(rename(deserialize = "userProfile"))] - pub user_profile: Option, - pub token: Option, - // Only used internally - #[serde(skip)] - pub user_data: Option, -} - -impl AuthStatus { - pub fn get_client(&self) -> ApiClient { - ApiClient::new(self.token.clone(), false) - } -} - -#[wasm_bindgen(module = "/public/auth.js")] -extern "C" { - #[wasm_bindgen] - pub fn init_env(domain: &str, client_id: &str, redirect_uri: &str, audience: &str); - - #[wasm_bindgen(catch)] - pub async fn check_login() -> Result; - - #[wasm_bindgen(catch)] - pub async fn auth0_login() -> Result<(), JsValue>; - - #[wasm_bindgen(catch)] - pub async fn auth0_logout() -> Result<(), JsValue>; - - #[wasm_bindgen(catch)] - pub async fn handle_login_callback() -> Result; -} - -#[wasm_bindgen(module = "/public/utils.js")] -extern "C" { - #[wasm_bindgen] - pub fn download_file(url: &str, name: &str); -} - -#[derive(Clone, Routable, PartialEq)] -pub enum EmbeddedRoute { - #[at("/lens/:lens/embedded")] - EmbeddedSearch { lens: String }, -} - -#[derive(Clone, Routable, PartialEq)] -pub enum Route { - #[at("/")] - Start, - #[at("/discover")] - Discover, - #[at("/edit/:lens")] - Edit { lens: String }, - #[at("/lens/:lens")] - Search { lens: String }, - #[at("/lens/:lens/c/:chat_session")] - SearchSession { lens: String, chat_session: String }, - #[not_found] - #[at("/404")] - NotFound, -} - -pub enum Msg { - AuthenticateUser, - CheckAuth, - LoadUserData, - SetSelectedLens(Lens), - LensDeleted(Lens), - UpdateAuth(AuthStatus), - UpdateUserData(UserData), -} - -pub struct App { - auth_status: AuthStatus, - current_lens: Option, - session_uuid: String, -} - -impl Component for App { - type Message = Msg; - type Properties = (); - - fn create(ctx: &Context) -> Self { - // Initialize JS env vars - #[cfg(debug_assertions)] - init_env( - dotenv!("DEV_AUTH0_DOMAIN"), - dotenv!("DEV_AUTH0_CLIENT_ID"), - dotenv!("DEV_AUTH0_REDIRECT_URI"), - dotenv!("DEV_AUTH0_AUDIENCE"), - ); - - #[cfg(not(debug_assertions))] - init_env( - dotenv!("AUTH0_DOMAIN"), - dotenv!("AUTH0_CLIENT_ID"), - dotenv!("AUTH0_REDIRECT_URI"), - dotenv!("AUTH0_AUDIENCE"), - ); - - // Check if user is logged in - if !is_embedded() { - ctx.link().send_message(Msg::CheckAuth); - } - - Self { - auth_status: AuthStatus { - is_authenticated: false, - user_profile: None, - token: None, - user_data: None, - }, - current_lens: None, - session_uuid: uuid::Uuid::new_v4().hyphenated().to_string(), - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - let link = ctx.link(); - - match msg { - Msg::AuthenticateUser => { - let link = link.clone(); - spawn_local(async move { - if let Ok(details) = handle_login_callback().await { - let _ = history().replace_state_with_url( - &JsValue::NULL, - "Spyglass Search", - Some("/"), - ); - match serde_wasm_bindgen::from_value::(details) { - Ok(status) => link.send_message(Msg::UpdateAuth(status)), - Err(err) => { - log::error!("Unable to parse user profile: {}", err.to_string()) - } - } - } - }); - false - } - Msg::CheckAuth => { - let link = link.clone(); - spawn_local(async move { - if let Ok(details) = check_login().await { - // Not logged in, load lenses - if details.is_null() { - link.send_message(Msg::LoadUserData); - } else { - // Logged in! - match serde_wasm_bindgen::from_value::(details) { - Ok(status) => link.send_message(Msg::UpdateAuth(status)), - Err(err) => { - log::error!( - "Unable to parse user profile: {}", - err.to_string() - ); - link.send_message(Msg::LoadUserData); - } - } - } - } - }); - false - } - Msg::LoadUserData => { - let link = link.clone(); - let auth_status = self.auth_status.clone(); - spawn_local(async move { - let api = auth_status.get_client(); - if auth_status.is_authenticated { - log::info!("grabbing logged in user's data"); - if let Ok(user_data) = api.get_user_data().await { - link.send_message(Msg::UpdateUserData(user_data)); - } - } - }); - false - } - Msg::SetSelectedLens(lens) => { - self.current_lens = Some(lens.name); - true - } - Msg::LensDeleted(_lens) => { - link.send_message(Msg::LoadUserData); - true - } - Msg::UpdateAuth(auth) => { - self.auth_status = auth; - link.send_message(Msg::LoadUserData); - true - } - Msg::UpdateUserData(user_data) => { - self.auth_status.user_data = Some(user_data); - true - } - } - } - - fn view(&self, ctx: &Context) -> Html { - let search = window().location().search().unwrap_or_default(); - let link = ctx.link(); - let embedded = is_embedded(); - - // Handle auth callbacks - if search.contains("state=") { - link.send_message(Msg::AuthenticateUser); - } - - let handle_on_create_lens = { - let link = link.clone(); - Callback::from(move |lens| { - link.send_message_batch(vec![Msg::LoadUserData, Msg::SetSelectedLens(lens)]) - }) - }; - - let switch_embedded = { - let uuid = self.session_uuid.clone(); - move |routes: EmbeddedRoute| match &routes { - EmbeddedRoute::EmbeddedSearch { lens } => { - let decoded_lens = decode_string(lens); - - html! { } - } - } - }; - - let switch = { - let link = link.clone(); - let uuid = self.session_uuid.clone(); - let is_authenticated = self.auth_status.is_authenticated; - move |routes: Route| match &routes { - Route::Discover => html! { }, - Route::Start => { - if is_authenticated { - html! { - - - - } - } else { - html! { } - } - } - Route::Edit { lens } => html! { - - - - }, - Route::Search { lens } => { - let decoded_lens = decode_string(lens); - - html! { } - } - Route::SearchSession { lens, chat_session } => { - let decoded_lens = decode_string(lens); - let decoded_chat = decode_string(chat_session); - - html! { } - } - Route::NotFound => html! {
    {"Not Found!"}
    }, - } - }; - - if embedded { - log::error!("rendering embedded"); - html! { - context={self.auth_status.clone()}> - -
    - render={switch_embedded} /> -
    -
    -
    > - } - } else { - html! { - context={self.auth_status.clone()}> - -
    - - render={switch} /> -
    -
    -
    > - } - } - } -} - -// Helper method used to identify if the page is an embedded link or not. The -// url is checked to see if the page should be treated as embedded -fn is_embedded() -> bool { - window() - .location() - .pathname() - .unwrap_or_default() - .ends_with("embedded") -} - -fn main() { - let _ = console_log::init_with_level(log::Level::Debug); - yew::Renderer::::new().render(); -} diff --git a/apps/web/src/metrics.rs b/apps/web/src/metrics.rs deleted file mode 100644 index d66921013..000000000 --- a/apps/web/src/metrics.rs +++ /dev/null @@ -1,82 +0,0 @@ -use reqwest::header; -use serde::Serialize; -use serde_json::Value; -use std::collections::HashMap; - -use strum_macros::{AsRefStr, Display}; - -#[allow(dead_code)] -const ENDPOINT: &str = "https://api.mixpanel.com/track"; -const PROJECT_TOKEN: &str = "fd3c1af155204ebe46ef88dbc7c9e469"; - -#[allow(dead_code)] -#[derive(Clone)] -pub struct Metrics { - client: reqwest::Client, - disabled: bool, -} - -#[allow(dead_code)] -#[derive(AsRefStr, Display)] -pub enum WebClientEvent { - #[strum(serialize = "login")] - Login, - #[strum(serialize = "logout")] - Logout, -} - -#[derive(Serialize)] -struct EventProps { - event: String, - properties: HashMap, -} - -impl EventProps { - pub fn new(uid: &str, event: &str) -> Self { - let mut properties: HashMap = HashMap::new(); - properties.insert("token".into(), PROJECT_TOKEN.into()); - properties.insert("time".into(), chrono::Utc::now().timestamp().into()); - properties.insert("distinct_id".into(), uid.into()); - properties.insert( - "$insert_id".into(), - uuid::Uuid::new_v4().as_hyphenated().to_string().into(), - ); - - EventProps { - event: event.to_string(), - properties, - } - } -} - -#[allow(dead_code)] -impl Metrics { - pub fn new(disabled: bool) -> Self { - let mut headers = header::HeaderMap::new(); - headers.insert("accept", header::HeaderValue::from_static("text/plain")); - headers.insert( - "content-type", - header::HeaderValue::from_static("application/json"), - ); - - let client = reqwest::ClientBuilder::new() - .default_headers(headers) - .build() - .expect("Unable to create HTTP client"); - - Self { client, disabled } - } - - pub async fn track(&self, event: WebClientEvent, uuid: &str) { - // nothing to do if telemetry is disabled. - if self.disabled { - return; - } - - #[allow(unused_variables)] - let data = EventProps::new(uuid, event.as_ref()); - - #[cfg(not(debug_assertions))] - let _ = self.client.post(ENDPOINT).json(&vec![data]).send().await; - } -} diff --git a/apps/web/src/pages/chat.rs b/apps/web/src/pages/chat.rs deleted file mode 100644 index ecd082144..000000000 --- a/apps/web/src/pages/chat.rs +++ /dev/null @@ -1,657 +0,0 @@ -use crate::{ - client::{ApiClient, ApiError, Lens, SpyglassClient}, - components::chat_bubble::{self, ChatBubble}, - pages::search::{HistorySource, WorkerCmd}, - schema::Theme, - utils::validate_hex_color, - AuthStatus, -}; -use futures::lock::Mutex; -use shared::response::SearchResult; -use shared::{ - keyboard::KeyCode, - response::{ChatErrorType, ChatUpdate}, -}; -use std::str::FromStr; -use std::sync::Arc; -use ui_components::{ - btn::{Btn, BtnType}, - icons::{RefreshIcon, SearchIcon}, -}; -use wasm_bindgen_futures::spawn_local; -use web_sys::HtmlInputElement; -use yew::platform::pinned::mpsc; -use yew::{html::Scope, platform::pinned::mpsc::UnboundedSender, prelude::*}; -use yew_router::prelude::*; - -use super::search::HistoryItem; - -// make sure we only have one connection per client -type Client = Arc>; - -#[allow(dead_code)] -pub enum Msg { - SetChatUuid(String), - ContextAdded(String), - HandleFollowup(String), - HandleKeyboardEvent(KeyboardEvent), - HandleSearch, - Reload, - ReloadSavedSession(bool), - SetError(String), - SetFinished, - SetLensData(Lens), - SetQuery(String), - SetSearchResults(Vec), - SetStatus(String), - StopSearch, - ToggleContext, - TokenReceived(String), - UpdateContext(AuthStatus), -} - -#[derive(Properties, PartialEq)] -pub struct ChatPageProps { - pub lens: String, - pub session_uuid: String, - pub chat_session: Option, - pub lens_data: Option, -} - -pub struct ChatPage { - client: Client, - lens_identifier: String, - lens_data: Option, - auth_status: AuthStatus, - current_query: Option, - history: Vec, - in_progress: bool, - results: Vec, - search_input_ref: NodeRef, - status_msg: Option, - tokens: Option, - context: Option, - show_context: bool, - chat_uuid: Option, - session_uuid: String, - historical_chat: bool, - _worker_cmd: Option>, - _context_listener: ContextHandle, -} - -impl Component for ChatPage { - type Message = Msg; - type Properties = ChatPageProps; - - fn create(ctx: &yew::Context) -> Self { - let props = ctx.props(); - - let (auth_status, context_listener) = ctx - .link() - .context(ctx.link().callback(Msg::UpdateContext)) - .expect("No Message Context Provided"); - - if props.chat_session.is_some() { - ctx.link().send_message(Msg::ReloadSavedSession(true)); - } else if props.lens_data.is_none() { - ctx.link().send_message(Msg::Reload); - } - - Self { - client: Arc::new(Mutex::new(SpyglassClient::new( - props.lens.clone(), - props.session_uuid.clone(), - auth_status.token.clone(), - true, - ))), - auth_status, - context: None, - current_query: None, - history: Vec::new(), - in_progress: false, - lens_data: props.lens_data.clone(), - lens_identifier: props.lens.clone(), - results: Vec::new(), - search_input_ref: Default::default(), - show_context: false, - status_msg: None, - tokens: None, - chat_uuid: props.chat_session.clone(), - session_uuid: props.session_uuid.clone(), - historical_chat: props.chat_session.is_some(), - _context_listener: context_listener, - _worker_cmd: None, - } - } - - fn changed(&mut self, ctx: &Context, _old_props: &Self::Properties) -> bool { - if self.in_progress { - ctx.link().send_message(Msg::StopSearch); - } - - let new_lens = ctx.props().lens.clone(); - let new_chat_session = ctx.props().chat_session.clone(); - self.historical_chat = new_chat_session.is_some(); - - let lens_changed = self.lens_identifier != new_lens; - let chat_session_changed = self.chat_uuid != new_chat_session; - let chat_session_set = new_chat_session.is_some(); - - if lens_changed { - self.lens_identifier = new_lens; - if chat_session_set && chat_session_changed { - self.chat_uuid = new_chat_session; - ctx.link().send_message(Msg::ReloadSavedSession(true)); - } else { - ctx.link().send_message(Msg::Reload); - } - true - } else if chat_session_changed { - if chat_session_set { - self.chat_uuid = new_chat_session; - ctx.link().send_message(Msg::ReloadSavedSession(false)); - } else { - ctx.link().send_message(Msg::Reload); - } - - true - } else { - false - } - } - - fn update(&mut self, ctx: &yew::Context, msg: Self::Message) -> bool { - let link = ctx.link(); - match msg { - Msg::SetChatUuid(uuid) => { - self.chat_uuid = Some(uuid); - false - } - Msg::ContextAdded(context) => { - self.context = Some(context); - false - } - Msg::HandleFollowup(question) => { - log::info!("handling followup: {}", question); - // Push existing question & answer into history - if let Some(value) = &self.current_query { - self.history.push(HistoryItem { - source: HistorySource::User, - value: value.to_owned(), - }); - } - - // Push existing answer into history - if let Some(value) = &self.tokens { - self.history.push(HistoryItem { - source: HistorySource::Clippy, - value: value.to_owned(), - }); - } - - // Push user's question into history - self.history.push(HistoryItem { - source: HistorySource::User, - value: question.clone(), - }); - self.context = None; - let mut cur_history = self.history.clone(); - // Add context to the beginning - if let Some(context) = &self.context { - cur_history.insert( - 0, - HistoryItem { - source: HistorySource::User, - value: context.to_owned(), - }, - ); - } - - self.tokens = None; - self.status_msg = None; - self.context = None; - self.in_progress = true; - - let link = link.clone(); - - let cur_doc_context = self.results.clone(); - let chat_uuid = self.chat_uuid.clone(); - let client = self.client.clone(); - let (tx, rx) = mpsc::unbounded::(); - self._worker_cmd = Some(tx); - spawn_local(async move { - let mut client = client.lock().await; - if let Err(err) = client - .followup( - &question, - &cur_history, - &cur_doc_context, - &chat_uuid, - &{ - let link = link.clone(); - move |update| process_update(update, &link) - }, - rx, - ) - .await - { - log::error!("{}", err.to_string()); - link.send_message(Msg::SetError(err.to_string())); - } - }); - - true - } - Msg::HandleKeyboardEvent(event) => { - let key = event.key(); - if let Ok(code) = KeyCode::from_str(&key.to_uppercase()) { - if code == KeyCode::Enter { - log::info!("key-code: {code}"); - link.send_message(Msg::HandleSearch); - } - } - false - } - Msg::HandleSearch => { - if let Some(search_input) = self.search_input_ref.cast::() { - let query = search_input.value(); - if self.current_query.is_some() { - link.send_message(Msg::HandleFollowup(query)) - } else { - link.send_message(Msg::SetQuery(query)); - } - search_input.set_value(""); - } - false - } - Msg::ReloadSavedSession(full_reload) => { - if self.chat_uuid.is_some() { - let chat_uuid = self.chat_uuid.clone().unwrap(); - if full_reload { - self.reload(link); - } else { - self.reset_search(); - } - - self.chat_uuid = Some(chat_uuid.clone()); - if let Some(data) = &self.auth_status.user_data { - if let Some(history) = data - .history - .iter() - .find(|history| history.session_id == chat_uuid) - { - let mut first_question = None; - for qna in &history.qna { - if first_question.is_none() { - first_question = Some(qna.question.clone()); - } - self.history.push(HistoryItem { - source: HistorySource::User, - value: qna.question.clone(), - }); - self.history.push(HistoryItem { - source: HistorySource::Clippy, - value: qna.response.clone(), - }); - - if let Some(doc_details) = &qna.document_details { - link.send_message(Msg::SetSearchResults(doc_details.clone())) - } - } - self.current_query = first_question; - } - } - } else { - self.reload(link); - } - true - } - Msg::Reload => { - self.reload(link); - true - } - Msg::SetError(err) => { - self.in_progress = false; - self.status_msg = Some(err); - true - } - Msg::SetFinished => { - self.in_progress = false; - self.status_msg = None; - true - } - Msg::SetLensData(data) => { - self.lens_data = Some(data); - true - } - Msg::SetSearchResults(results) => { - self.results = results; - true - } - Msg::SetStatus(msg) => { - self.status_msg = Some(msg); - true - } - Msg::SetQuery(query) => { - self.in_progress = true; - self.tokens = None; - self.results = Vec::new(); - self.current_query = Some(query.clone()); - - log::info!("handling search! {}", query); - self.status_msg = Some(format!("searching: {query}")); - - let link = link.clone(); - let client = self.client.clone(); - - let (tx, rx) = mpsc::unbounded::(); - self._worker_cmd = Some(tx); - spawn_local(async move { - let mut client = client.lock().await; - if let Err(err) = client - .search( - &query, - &{ - let link = link.clone(); - move |update| process_update(update, &link) - }, - rx, - ) - .await - { - log::error!("{}", err.to_string()); - link.send_message(Msg::SetError(err.to_string())); - } else { - log::info!("finished response"); - } - }); - - true - } - Msg::StopSearch => { - if let Some(tx) = &self._worker_cmd { - self.in_progress = false; - let _ = tx.send_now(WorkerCmd::Stop); - tx.close_now(); - self._worker_cmd = None; - } - true - } - Msg::ToggleContext => { - self.show_context = !self.show_context; - true - } - Msg::TokenReceived(token) => { - if let Some(tokens) = self.tokens.as_mut() { - tokens.push_str(&token); - } else { - self.tokens = Some(token.to_owned()); - } - true - } - Msg::UpdateContext(auth) => { - self.auth_status = auth; - if self.chat_uuid.is_some() { - link.send_message(Msg::ReloadSavedSession(true)) - } else { - link.send_message(Msg::Reload); - } - false - } - } - } - - fn view(&self, ctx: &yew::Context) -> yew::Html { - let link = ctx.link(); - if let Some(lens) = self.lens_data.clone() { - html! { -
    - {self.render_search(link, &lens)} -
    - } - } else { - html! {} - } - } -} - -fn process_update(update: ChatUpdate, link: &Scope) { - match update { - ChatUpdate::ChatStart(uuid) => { - log::info!("ChatUpdate::ChatStart"); - link.send_message(Msg::SetChatUuid(uuid)) - } - ChatUpdate::SearchingDocuments => { - log::info!("ChatUpdate::SearchingDocuments"); - link.send_message(Msg::SetStatus("Searching...".into())) - } - ChatUpdate::DocumentContextAdded(docs) => { - log::info!("ChatUpdate::DocumentContextAdded"); - link.send_message(Msg::SetSearchResults(docs)) - } - ChatUpdate::GeneratingContext => { - log::info!("ChatUpdate::SearchingDocuments"); - link.send_message(Msg::SetStatus("Analyzing documents...".into())) - } - ChatUpdate::ContextGenerated(context) => { - log::info!("ChatUpdate::ContextGenerated {}", context); - link.send_message(Msg::ContextAdded(context)); - } - ChatUpdate::LoadingModel | ChatUpdate::LoadingPrompt => { - link.send_message(Msg::SetStatus("Generating answer...".into())) - } - ChatUpdate::Token(token) => link.send_message(Msg::TokenReceived(token)), - ChatUpdate::EndOfText => { - link.send_message(Msg::SetFinished); - } - ChatUpdate::Error(err) => { - log::error!("ChatUpdate::Error: {err:?}"); - let msg = match err { - ChatErrorType::ContextLengthExceeded(msg) => msg, - ChatErrorType::APIKeyMissing => "No API key".into(), - ChatErrorType::UnknownError(msg) => msg, - }; - link.send_message(Msg::SetError(msg)); - } - } -} - -impl ChatPage { - fn reset_search(&mut self) { - self.context = None; - self.current_query = None; - self.history.clear(); - self.in_progress = false; - self.results.clear(); - self.status_msg = None; - self.tokens = None; - self.chat_uuid = None; - } - - fn render_search(&self, link: &Scope, lens: &Lens) -> Html { - let placeholder = format!("Ask anything related to {}", lens.display_name); - - let mut chats = Vec::new(); - let mut header_color = String::from("#454545"); - let bot_bubble_color = lens - .embedded_configuration - .as_ref() - .map(|cfg| cfg.bot_bubble_color.clone()) - .unwrap_or_default(); - let user_bubble_color = lens - .embedded_configuration - .as_ref() - .map(|cfg| cfg.user_bubble_color.clone()) - .unwrap_or_default(); - let mut theme = "dark-mode"; - let mut header_title = lens.display_name.clone(); - let add_initial: bool = lens - .embedded_configuration - .as_ref() - .map(|cfg| cfg.initial_chat.is_empty()) - .unwrap_or(true); - - if add_initial { - chats.push(html! { - - }); - } - - if let Some(embedding_config) = &lens.embedded_configuration { - // Add initial chat messages - for initial in &embedding_config.initial_chat { - chats.push(html! { - - }); - } - - if let Some(color) = &embedding_config.header_color { - if validate_hex_color(color).is_ok() { - header_color = format!("#{}", color); - } - } - - if let Some(title) = &embedding_config.header_title { - header_title = title.clone(); - } - - theme = match &embedding_config.theme { - Theme::LightMode => "light-mode", - Theme::DarkMode => "dark-mode", - } - } - - log::error!("history {:?}", self.history.len()); - - chats.extend(self - .history - .iter() - .filter_map(|history| match history.source { - HistorySource::Clippy => Some(html! { - - }), - HistorySource::User => Some(html! { - - }), - _ => None, - }) - .collect::>()); - - // TODO configure justify and background color - let justify = classes!("justify-center", "flex", "items-center", "mb-4", "p-4"); - - let chat_display = classes!(theme, "h-full"); - // TODO configurable product icon, bot image, user image, etc - html! { -
    -
    -
    -
    -

    {header_title}

    - // {"Online"}

    -
    -
    -
    -
    - {chats} - { if self.history.is_empty() { - if let Some(query) = &self.current_query { - html!{ } - } else { - html! {} - } - } else { - html! {} - - }} - { if let Some(tokens) = &self.tokens { - html!{ } - } else if let Some(msg) = &self.status_msg { - html!{ } - } else { - html! {} - }} -
    -
    -
    -
    - - {if self.in_progress { - html! { - - - {"Stop"} - - } - } else { - - html! { - - - - - } - }} -
    -
    - -
    -
    - } - } - - // Fully reloads and resets the search context. This is used when the lens has changed. - fn reload(&mut self, link: &Scope) { - self.reset_search(); - self.client = Arc::new(Mutex::new(SpyglassClient::new( - self.lens_identifier.clone(), - self.session_uuid.clone(), - self.auth_status.token.clone(), - true, - ))); - - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - spawn_local(async move { - let api = ApiClient::new(None, true); - match api.lens_retrieve(&identifier).await { - Ok(lens) => link.send_message(Msg::SetLensData(lens)), - Err(ApiError::ClientError(msg)) => { - // Unauthorized - if msg.code == 400 { - let navi = link.navigator().expect("No navigator"); - navi.push(&crate::Route::Start); - } - log::error!("error retrieving lens: {msg}"); - } - Err(err) => log::error!("error retrieving lens: {}", err), - } - }); - } -} diff --git a/apps/web/src/pages/dashboard.rs b/apps/web/src/pages/dashboard.rs deleted file mode 100644 index d51946509..000000000 --- a/apps/web/src/pages/dashboard.rs +++ /dev/null @@ -1,111 +0,0 @@ -use ui_components::btn::{Btn, BtnSize, BtnType}; -use ui_components::icons; -use yew::{platform::spawn_local, prelude::*}; -use yew_router::prelude::use_navigator; - -use crate::components::LensList; -use crate::{client::Lens, AuthStatus, Route}; - -#[derive(Properties, PartialEq)] -pub struct DashboardProps { - pub session_uuid: String, - #[prop_or_default] - pub on_create_lens: Callback, - #[prop_or_default] - pub on_select_lens: Callback, - #[prop_or_default] - pub on_edit_lens: Callback, - #[prop_or_default] - pub on_delete_lens: Callback, -} - -#[function_component(Dashboard)] -pub fn landing_page(props: &DashboardProps) -> Html { - let navigator = use_navigator().expect("Navigator not available"); - let auth_status = use_context::().expect("ctx not setup"); - - let user_data = auth_status.user_data.clone(); - - let create_lens_cb = { - let auth_status_handle = auth_status; - let on_create = props.on_create_lens.clone(); - Callback::from(move |_: MouseEvent| { - let navigator = navigator.clone(); - let auth_status_handle: AuthStatus = auth_status_handle.clone(); - let on_create = on_create.clone(); - spawn_local(async move { - // create a new lens - let api = auth_status_handle.get_client(); - match api.lens_create().await { - Ok(new_lens) => { - on_create.emit(new_lens.clone()); - navigator.push(&Route::Edit { - lens: new_lens.name, - }) - } - Err(err) => log::error!("error creating lens: {err}"), - } - }); - }) - }; - - if let Some(user_data) = user_data { - html! { -
    -
    -
    - {"My Lenses"} -
    - - - {"Create New"} - -
    - -
    - } - } else { - html! {} - } -} - -#[derive(Properties, PartialEq)] -struct PublicExampleProps { - href: String, - name: String, - description: String, - sources: Vec, -} - -#[function_component(PublicExample)] -fn pub_example(props: &PublicExampleProps) -> Html { - let sources = props - .sources - .iter() - .map(|source| { - html! { - {source} - } - }) - .collect::(); - - html! { - -
    {props.name.clone()}
    -
    {props.description.clone()}
    -
    - {"source:"} - {sources} -
    -
    - } -} diff --git a/apps/web/src/pages/discover.rs b/apps/web/src/pages/discover.rs deleted file mode 100644 index 05b13c78e..000000000 --- a/apps/web/src/pages/discover.rs +++ /dev/null @@ -1,174 +0,0 @@ -use ui_components::btn::{Btn, BtnSize, BtnType}; -use ui_components::icons; -use yew::prelude::*; - -use crate::pages::landing::PublicExample; - -#[derive(Properties, PartialEq)] -pub struct DiscoverPageProps; - -#[function_component(DiscoverPage)] -pub fn discover_page(_: &DiscoverPageProps) -> Html { - html! { -
    -
    -

    - {"Try it out!"} -

    -
    - {"Search, ask questions, and explore our featured communities."} -
    -
    -
    {"Want to add your favorite community?"}
    - - - {"Request on Twitter"} - - - - {"Request on Mastodon"} - -
    -
    - -
    -

    - {"Documentation"} -

    -
    - - - - - - - - - - - - - - - - - - -
    -
    - -
    -

    - {"Podcasts"} -

    -
    - - - - - - -
    -
    - -
    -

    - {"Just for Fun! 🍷 🐉"} -

    -
    - - - -
    -
    -
    - } -} diff --git a/apps/web/src/pages/embedded.rs b/apps/web/src/pages/embedded.rs deleted file mode 100644 index 3134b64ad..000000000 --- a/apps/web/src/pages/embedded.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::{ - client::{ApiClient, ApiError, Lens}, - pages::{chat::ChatPage, search::SearchPage}, - schema::EmbeddedPromptStyle, -}; - -use wasm_bindgen_futures::spawn_local; -use yew::{html::Scope, prelude::*}; -use yew_router::prelude::*; - -pub enum Msg { - Reload, - SetLensData(Box), -} - -#[derive(Properties, PartialEq)] -pub struct EmbeddedPageProps { - pub lens: String, - pub session_uuid: String, -} - -/// The embedded page is used to toggle between the different types -/// of embedded pages based on the lens configuration. To -/// speed up load time the lens configuration is passed into the -/// search page. This allows the search page to skip the need for -/// an additional http request to render -pub struct EmbeddedPage { - lens_identifier: String, - lens_data: Option, - session_uuid: String, -} - -impl Component for EmbeddedPage { - type Message = Msg; - type Properties = EmbeddedPageProps; - - fn create(ctx: &yew::Context) -> Self { - let props = ctx.props(); - - ctx.link().send_message(Msg::Reload); - Self { - lens_data: None, - lens_identifier: props.lens.clone(), - session_uuid: props.session_uuid.clone(), - } - } - - fn changed(&mut self, ctx: &Context, _old_props: &Self::Properties) -> bool { - let new_lens = ctx.props().lens.clone(); - let lens_changed = self.lens_identifier != new_lens; - - if lens_changed { - ctx.link().send_message(Msg::Reload); - true - } else { - false - } - } - - fn update(&mut self, ctx: &yew::Context, msg: Self::Message) -> bool { - let link = ctx.link(); - match msg { - Msg::Reload => { - self.reload(link); - true - } - Msg::SetLensData(data) => { - self.lens_data = Some(*data); - true - } - } - } - - fn view(&self, _ctx: &yew::Context) -> yew::Html { - if let Some(lens) = &self.lens_data { - let prompt_style = lens - .embedded_configuration - .as_ref() - .map(|cfg| cfg.prompt_style.clone()) - .unwrap_or(EmbeddedPromptStyle::Research); - match prompt_style { - EmbeddedPromptStyle::Research => { - html! { - - } - } - EmbeddedPromptStyle::Chat => { - html! { - - } - } - } - } else { - html! {} - } - } -} - -impl EmbeddedPage { - // Reload the lens configuration - fn reload(&mut self, link: &Scope) { - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - spawn_local(async move { - let api = ApiClient::new(None, true); - match api.lens_retrieve(&identifier).await { - Ok(lens) => link.send_message(Msg::SetLensData(Box::new(lens))), - Err(ApiError::ClientError(msg)) => { - log::error!("Got error! {:?}", msg); - // Unauthorized - if msg.code == 400 { - let navi = link.navigator().expect("No navigator"); - navi.push(&crate::Route::Start); - } - log::error!("error retrieving lens: {msg}"); - } - Err(err) => log::error!("error retrieving lens: {}", err), - } - }); - } -} diff --git a/apps/web/src/pages/landing.rs b/apps/web/src/pages/landing.rs deleted file mode 100644 index 7a4834ecb..000000000 --- a/apps/web/src/pages/landing.rs +++ /dev/null @@ -1,150 +0,0 @@ -use yew::prelude::*; -use yew_hooks::use_interval; - -#[derive(Properties, PartialEq)] -pub struct LandingPageProps { - pub session_uuid: String, -} - -const WORDS: [&str; 6] = [ - "community", - "podcast", - "developers", - "listeners", - "users", - "fandom", -]; - -#[function_component(LandingPage)] -pub fn landing_page(_props: &LandingPageProps) -> Html { - let word_swap = use_state_eq(|| "community"); - let word_swap_idx = use_state_eq(|| 0); - { - let word_swap = word_swap.clone(); - use_interval( - move || { - let mut idx = *word_swap_idx + 1; - if idx >= WORDS.len() { - idx = 0; - } - - word_swap.set(WORDS[idx]); - word_swap_idx.set(idx); - }, - 2_000, - ); - } - - html! { -
    -
    -

    -
    {"Conversational search"}
    -
    - {"for your "} - {*word_swap} - {"."} -
    -

    -
    - {"AI-powered "} - {"search"} - {" and "} - {"chat."} - {" Across all your content"} -
    -
    -
    - -
    -
    -
    -

    - {"Try it out!"} -

    -
    - {"Search, ask questions, and explore our featured communities."} -
    -
    -
    - - - - - - - -
    -
    -
    -
    {"Made with ☕️ in SF/SD"}
    -
    -
    - } -} - -#[derive(Properties, PartialEq)] -pub struct PublicExampleProps { - pub href: String, - pub name: String, - pub description: String, - pub sources: Vec, -} - -#[function_component(PublicExample)] -pub fn pub_example(props: &PublicExampleProps) -> Html { - let sources = props - .sources - .iter() - .map(|source| { - html! { - {source} - } - }) - .collect::(); - - html! { - -
    {props.name.clone()}
    -
    {props.description.clone()}
    -
    - {"source:"} - {sources} -
    -
    - } -} diff --git a/apps/web/src/pages/lens_editor/add_source.rs b/apps/web/src/pages/lens_editor/add_source.rs deleted file mode 100644 index cc0b8b698..000000000 --- a/apps/web/src/pages/lens_editor/add_source.rs +++ /dev/null @@ -1,412 +0,0 @@ -use strum::IntoEnumIterator; -use strum_macros::{Display, EnumIter}; -use ui_components::btn::{Btn, BtnSize, BtnType}; -use ui_components::icons; -use wasm_bindgen::{prelude::*, JsValue}; -use web_sys::HtmlInputElement; -use yew::{html::Scope, platform::spawn_local, prelude::*}; - -use crate::components::file_upload::FileUpload; -use crate::{ - client::{ApiError, LensAddDocType, LensAddDocument}, - AuthStatus, -}; - -#[wasm_bindgen(module = "/public/gapi.js")] -extern "C" { - #[wasm_bindgen] - pub fn init_gapi(client_id: &str, api_key: &str); - - #[wasm_bindgen(catch)] - pub async fn create_picker(cb: &Closure) -> Result<(), JsValue>; -} - -#[derive(Clone, EnumIter, Display, PartialEq, Eq)] -pub enum AddSourceTabs { - Website, - Podcast, - GDrive, - File, -} - -pub struct AddSourceComponent { - adding_in_progress: bool, - auth_status: AuthStatus, - selected_tab: AddSourceTabs, - _context_listener: ContextHandle, - _feed_input_ref: NodeRef, - _url_input_ref: NodeRef, - _url_crawl_ref: NodeRef, -} - -pub enum Msg { - AddUrl, - AddFeed, - ChangeToTab(AddSourceTabs), - EmitError(String), - EmitUpdate, - FilePicked { token: String, url: String }, - OpenCloudFilePicker, - UpdateContext(AuthStatus), -} - -#[derive(Properties, PartialEq)] -pub struct AddSourceComponentProps { - pub lens_identifier: String, - #[prop_or_default] - pub on_error: Callback, - #[prop_or_default] - pub on_update: Callback<()>, -} - -impl Component for AddSourceComponent { - type Message = Msg; - type Properties = AddSourceComponentProps; - - fn create(ctx: &Context) -> Self { - // initialize gapi - init_gapi(dotenv!("GOOGLE_CLIENT_ID"), dotenv!("GOOGLE_API_KEY")); - // Connect to context for auth details - let (auth_status, context_listener) = ctx - .link() - .context(ctx.link().callback(Msg::UpdateContext)) - .expect("No Message Context Provided"); - - Self { - adding_in_progress: false, - auth_status, - selected_tab: AddSourceTabs::Website, - _context_listener: context_listener, - _feed_input_ref: NodeRef::default(), - _url_input_ref: NodeRef::default(), - _url_crawl_ref: NodeRef::default(), - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - let link = ctx.link(); - let props = ctx.props(); - - match msg { - Msg::AddFeed => { - if let Some(feed_input) = self._feed_input_ref.cast::() { - let url = feed_input.value(); - let url = match url::Url::parse(&url) { - Ok(url) => url, - Err(_) => { - link.send_message(Msg::EmitError("Invalid URL".into())); - return false; - } - }; - - let source = LensAddDocument { - url: url.to_string(), - doc_type: LensAddDocType::RssFeed { - preferred_model: crate::client::PreferredModel::WhisperSmall, - }, - }; - - self.adding_in_progress = true; - self.add_source(&props.lens_identifier, source, link, false); - } - true - } - Msg::AddUrl => { - if let (Some(url_input), Some(crawl_checkbox)) = ( - self._url_input_ref.cast::(), - self._url_crawl_ref.cast::(), - ) { - let url = url_input.value(); - let is_crawl = crawl_checkbox.checked(); - - let url = match url::Url::parse(&url) { - Ok(url) => url, - Err(_) => { - link.send_message(Msg::EmitError("Invalid URL".into())); - return false; - } - }; - - let new_source = LensAddDocument { - url: url.to_string(), - doc_type: LensAddDocType::WebUrl { - include_all_suburls: is_crawl, - }, - }; - - let link = link.clone(); - self.adding_in_progress = true; - self.add_source(&props.lens_identifier, new_source, &link, true); - } - - true - } - Msg::ChangeToTab(new_tab) => { - self.selected_tab = new_tab; - true - } - Msg::EmitError(msg) => { - self.adding_in_progress = false; - props.on_error.emit(msg); - true - } - Msg::EmitUpdate => { - self.adding_in_progress = false; - // Reset form values - if let Some(input) = self._url_input_ref.cast::() { - input.set_value(""); - } - if let Some(input) = self._url_crawl_ref.cast::() { - input.set_checked(false); - } - - if let Some(input) = self._feed_input_ref.cast::() { - input.set_value(""); - } - - props.on_update.emit(()); - true - } - Msg::FilePicked { token, url } => { - let new_source = LensAddDocument { - url, - doc_type: LensAddDocType::GDrive { token }, - }; - - let link = link.clone(); - self.adding_in_progress = true; - self.add_source(&props.lens_identifier, new_source, &link, false); - true - } - Msg::OpenCloudFilePicker => { - let link = link.clone(); - spawn_local(async move { - let cb = Closure::wrap(Box::new(move |token: JsValue, payload: JsValue| { - if let (Ok(token), Ok(url)) = ( - serde_wasm_bindgen::from_value::(token), - serde_wasm_bindgen::from_value::(payload), - ) { - link.send_message(Msg::FilePicked { token, url }); - } - }) as Box); - - if let Err(err) = create_picker(&cb).await { - log::error!("create_picker error: {:?}", err); - } - cb.forget(); - }); - false - } - Msg::UpdateContext(auth_status) => { - self.auth_status = auth_status; - true - } - } - } - - fn view(&self, ctx: &Context) -> Html { - let link = ctx.link(); - let props = ctx.props(); - - let tab_styles = classes!( - "border-b-2", - "px-4", - "pb-2", - "-mb-[2px]", - "cursor-pointer", - "hover:text-cyan-500", - "hover:border-cyan-500" - ); - let tabs = AddSourceTabs::iter() - .map(|tab| { - let mut styles = tab_styles.clone(); - if self.selected_tab == tab { - styles.extend(vec!["text-cyan-500", "border-cyan-500"]); - } else { - styles.extend(vec!["text-white", "border-neutral-700"]); - } - - let action = { - let new_tab = tab.clone(); - link.callback(move |_| Msg::ChangeToTab(new_tab.clone())) - }; - - html! {
  • {tab}
  • } - }) - .collect::(); - - html! { -
    -
    -
      - {tabs} -
    -
    - {match self.selected_tab { - AddSourceTabs::Website => self.view_website_tab(link), - AddSourceTabs::Podcast => self.view_podcast_tab(link), - AddSourceTabs::GDrive => self.view_gdrive_tab(link), - AddSourceTabs::File => html! { - - } - }} -
    -
    -
    - } - } -} - -impl AddSourceComponent { - fn view_website_tab(&self, link: &Scope) -> Html { - html! { -
    -
    - {"Add a single page or all pages from a website"} -
    -
    - -
    - -
    - - {if self.adding_in_progress { - html! { - - } - } else { - html! {
    {"Fetch"}
    } - }} -
    -
    -
    - } - } - - fn view_podcast_tab(&self, link: &Scope) -> Html { - html! { -
    -
    - {"Add episodes from a podcast feed"} -
    -
    - - - {if self.adding_in_progress { - html! { - - } - } else { - html! {
    {"Add Podcast"}
    } - }} -
    -
    -
    - } - } - - fn view_gdrive_tab(&self, link: &Scope) -> Html { - html! { -
    - - {if self.adding_in_progress { - html! { - - } - } else { - html! {
    {"Select file from Google Drive"}
    } - }} -
    -
    - } - } - - fn add_source( - &self, - lens: &str, - source: LensAddDocument, - link: &Scope, - validate: bool, - ) { - let auth_status = self.auth_status.clone(); - let link: Scope = link.clone(); - let lens = lens.to_string(); - spawn_local(async move { - let api = auth_status.get_client(); - - let is_valid = if validate { - match api.validate_lens_source(&lens, &source).await { - Ok(response) => { - if response.is_valid { - true - } else { - let error_msg = response - .validation_msg - .unwrap_or("Unknown error adding URL".to_string()); - link.send_message(Msg::EmitError(error_msg)); - false - } - } - Err(error) => { - link.send_message(Msg::EmitError(error.to_string())); - false - } - } - } else { - true - }; - - if is_valid { - match api.lens_add_source(&lens, &source).await { - Ok(_) => link.send_message(Msg::EmitUpdate), - Err(ApiError::ClientError(msg)) => { - link.send_message(Msg::EmitError(msg.message)) - } - Err(err) => link.send_message(Msg::EmitError(err.to_string())), - } - } - }); - } -} diff --git a/apps/web/src/pages/lens_editor/mod.rs b/apps/web/src/pages/lens_editor/mod.rs deleted file mode 100644 index 8c9e17e66..000000000 --- a/apps/web/src/pages/lens_editor/mod.rs +++ /dev/null @@ -1,670 +0,0 @@ -use gloo::timers::callback::{Interval, Timeout}; -use strum::IntoEnumIterator; -use ui_components::{ - btn::{Btn, BtnSize, BtnType}, - icons, - results::Paginator, -}; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; -use wasm_bindgen_futures::spawn_local; -use web_sys::HtmlInputElement; -use yew::prelude::*; -use yew_router::scope_ext::RouterScopeExt; - -use crate::{ - client::{ApiError, Lens, LensDocType, LensSource}, - download_file, - schema::{GetLensSourceResponse, LensSourceQueryFilter}, - AuthStatus, -}; - -mod add_source; -use add_source::AddSourceComponent; - -const QUERY_DEBOUNCE_MS: u32 = 1_000; -const REFRESH_INTERVAL_MS: u32 = 5_000; - -const DOWNLOAD_PREFIX: &str = "https://search.spyglass.fyi/lens"; - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(js_name = "clearTimeout")] - fn clear_timeout(handle: JsValue); -} - -#[derive(Clone, PartialEq)] -pub struct LensSourcePaginator { - page: usize, - num_items: usize, - num_pages: usize, -} - -pub struct CreateLensPage { - pub error_msg: Option, - pub lens_identifier: String, - pub lens_data: Option, - - pub source_filter: LensSourceQueryFilter, - pub lens_sources: Option>, - pub lens_source_paginator: Option, - - pub is_loading_lens_sources: bool, - pub is_saving_name: bool, - - pub auth_status: AuthStatus, - pub add_url_error: Option, - - pub _refresh_interval: Option, - pub _context_listener: ContextHandle, - pub _query_debounce: Option, - pub _name_input_ref: NodeRef, -} - -#[derive(Properties, PartialEq)] -pub struct CreateLensProps { - pub lens: String, -} - -pub enum Msg { - ClearError, - DeleteLensSource(LensSource), - Reload, - ReloadCurrentSources, - ReloadSources { - page: usize, - filter: LensSourceQueryFilter, - }, - Save { - display_name: String, - }, - SaveDone, - SetError(String), - SetFilter(LensSourceQueryFilter), - SetLensData(Lens), - SetLensSources(GetLensSourceResponse), - UpdateContext(AuthStatus), - UpdateDisplayName, -} - -impl Component for CreateLensPage { - type Message = Msg; - type Properties = CreateLensProps; - - fn create(ctx: &Context) -> Self { - let (auth_status, context_listener) = ctx - .link() - .context(ctx.link().callback(Msg::UpdateContext)) - .expect("No Message Context Provided"); - - ctx.link().send_message_batch(vec![ - Msg::Reload, - Msg::ReloadSources { - page: 0, - filter: LensSourceQueryFilter::default(), - }, - ]); - - Self { - error_msg: None, - lens_identifier: ctx.props().lens.clone(), - lens_data: None, - lens_sources: None, - lens_source_paginator: None, - source_filter: LensSourceQueryFilter::default(), - is_saving_name: false, - is_loading_lens_sources: false, - auth_status, - add_url_error: None, - _refresh_interval: None, - _context_listener: context_listener, - _query_debounce: None, - _name_input_ref: NodeRef::default(), - } - } - - fn changed(&mut self, ctx: &Context, _old_props: &Self::Properties) -> bool { - let new_lens = ctx.props().lens.clone(); - if self.lens_identifier != new_lens { - self.lens_identifier = new_lens; - - let reload_msg = if let Some(paginator) = &self.lens_source_paginator { - Msg::ReloadSources { - page: paginator.page, - filter: self.source_filter, - } - } else { - Msg::ReloadSources { - page: 0, - filter: LensSourceQueryFilter::All, - } - }; - - ctx.link().send_message_batch(vec![Msg::Reload, reload_msg]); - true - } else { - false - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - let link = ctx.link(); - match msg { - Msg::ClearError => { - self.error_msg = None; - true - } - Msg::DeleteLensSource(source) => { - // Add to lens - let auth_status = self.auth_status.clone(); - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - let page = self - .lens_source_paginator - .as_ref() - .map(|x| x.page) - .unwrap_or(0); - let filter = self.source_filter; - spawn_local(async move { - let api = auth_status.get_client(); - match api.delete_lens_source(&identifier, &source.doc_uuid).await { - Ok(_) => link.send_message(Msg::ReloadSources { page, filter }), - Err(err) => { - log::error!("Error deleting source: {err}"); - link.send_message(Msg::SetError(err.to_string())); - } - } - }); - false - } - Msg::Reload => { - let auth_status = self.auth_status.clone(); - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - spawn_local(async move { - let api = auth_status.get_client(); - match api.lens_retrieve(&identifier).await { - Ok(lens) => link.send_message_batch(vec![ - Msg::SetLensData(lens), - Msg::ReloadCurrentSources, - ]), - Err(ApiError::ClientError(msg)) => { - // Unauthorized - if msg.code == 400 { - let navi = link.navigator().expect("No navigator"); - navi.push(&crate::Route::Start); - } - - log::error!("error retrieving lens: {msg}"); - } - Err(err) => log::error!("error retrieving lens: {err}"), - } - }); - - false - } - Msg::ReloadCurrentSources => { - if let Some(paginator) = &self.lens_source_paginator { - link.send_message(Msg::ReloadSources { - page: paginator.page, - filter: self.source_filter, - }); - } - false - } - Msg::ReloadSources { page, filter } => { - let auth_status = self.auth_status.clone(); - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - self.is_loading_lens_sources = true; - spawn_local(async move { - let api: crate::client::ApiClient = auth_status.get_client(); - match api.lens_retrieve_sources(&identifier, page, filter).await { - Ok(lens) => link.send_message(Msg::SetLensSources(lens)), - Err(ApiError::ClientError(msg)) => { - // Unauthorized - if msg.code == 400 { - let navi = link.navigator().expect("No navigator"); - navi.push(&crate::Route::Start); - } - - log::error!("error retrieving lens: {msg}"); - } - Err(err) => log::error!("error retrieving lens: {err}"), - } - }); - - true - } - Msg::Save { display_name } => { - if let Some(lens_data) = &mut self.lens_data { - let auth_status = self.auth_status.clone(); - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - self.is_saving_name = true; - lens_data.display_name = display_name.clone(); - spawn_local(async move { - let api = auth_status.get_client(); - if api.lens_update(&identifier, &display_name).await.is_ok() { - link.send_message(Msg::SaveDone); - } else { - link.send_message(Msg::Reload); - } - }); - } - true - } - Msg::SaveDone => { - self.is_saving_name = false; - true - } - Msg::SetError(err) => { - self.error_msg = Some(err); - true - } - Msg::SetFilter(filter) => { - self.source_filter = filter; - if let Some(paginator) = &self.lens_source_paginator { - link.send_message(Msg::ReloadSources { - page: paginator.page, - filter: self.source_filter, - }); - } - true - } - Msg::SetLensData(lens_data) => { - self.lens_data = Some(lens_data); - true - } - Msg::SetLensSources(sources) => { - self.is_loading_lens_sources = false; - self.lens_source_paginator = Some(LensSourcePaginator { - page: sources.page, - num_items: sources.num_items, - num_pages: sources.num_pages, - }); - - let has_processing = sources.results.iter().any(|x| x.status == "Processing"); - - if has_processing && self._refresh_interval.is_none() { - let link = link.clone(); - let interval = Interval::new(REFRESH_INTERVAL_MS, move || { - link.send_message(Msg::ReloadCurrentSources); - }); - - self._refresh_interval = Some(interval); - } else if !has_processing { - self._refresh_interval = None; - } - - self.lens_sources = Some(sources.results); - true - } - Msg::UpdateContext(auth_status) => { - self.auth_status = auth_status; - let page = self - .lens_source_paginator - .as_ref() - .map(|x| x.page) - .unwrap_or(0); - link.send_message_batch(vec![ - Msg::Reload, - Msg::ReloadSources { - page, - filter: self.source_filter, - }, - ]); - true - } - Msg::UpdateDisplayName => { - if let Some(timeout_id) = &self._query_debounce { - clear_timeout(timeout_id.clone()); - self._query_debounce = None; - } - - { - if let Some(node) = self._name_input_ref.cast::() { - let display_name = node.value(); - let link = link.clone(); - let handle = Timeout::new(QUERY_DEBOUNCE_MS, move || { - link.send_message(Msg::Save { display_name }) - }); - - let id = handle.forget(); - self._query_debounce = Some(id); - } - } - - false - } - } - } - - fn view(&self, ctx: &Context) -> Html { - let link = ctx.link(); - html! { -
    - {if let Some(msg) = &self.error_msg { - html! { - - } - } else { html! {} }} -
    - {if let Some(lens_data) = self.lens_data.as_ref() { - html! { -
    - - {if self.is_saving_name { - html! { - - } - } else { - html! {} - }} -
    - } - } else { - html! { -

    {"Loading..."}

    - } - }} -
    -
    - -
    -
    - {if let Some(paginator) = self.lens_source_paginator.clone() { - let filter = self.source_filter; - html! { - - } - } else { html! {} }} -
    -
    - } - } -} - -#[derive(Properties, PartialEq)] -struct LensSourceComponentProps { - source: LensSource, - on_delete: Callback, -} - -#[function_component(LensSourceComponent)] -fn lens_source_comp(props: &LensSourceComponentProps) -> Html { - let source = props.source.clone(); - let callback = props.on_delete.clone(); - let is_deleting = use_state_eq(|| false); - let auth_status = use_context::().expect("Ctxt not set up"); - let ext = props - .source - .display_name - .split('.') - .last() - .unwrap_or("") - .to_string(); - let doc_type_icon = match source.doc_type { - LensDocType::Audio => html! { - - }, - LensDocType::GDrive => html! { }, - LensDocType::Web => html! { }, - LensDocType::Upload => { - html! { } - } - }; - - let status_icon = match source.status.as_ref() { - "Deployed" => html! { }, - // todo: show error message in tooltip? - "Failed" | "Unknown" => html! { }, - _ => html! { }, - }; - - let on_delete: Callback = { - let source = source.clone(); - let is_deleting = is_deleting.clone(); - Callback::from(move |_e: MouseEvent| { - is_deleting.set(true); - callback.emit(source.clone()); - }) - }; - - let cell_styles = classes!( - "border-b", - "p-2", - "border-neutral-100", - "dark:border-neutral-700", - "text-neutral-500", - "dark:text-neutral-400", - ); - - let url_link = if source.url.starts_with(DOWNLOAD_PREFIX) { - let url = source - .url - .get(DOWNLOAD_PREFIX.len()..) - .unwrap_or("") - .to_string(); - let name = source.display_name.clone(); - let download: Callback = Callback::from(move |evt: MouseEvent| { - evt.prevent_default(); - let client = auth_status.get_client(); - let url = url.clone(); - let name = name.clone(); - spawn_local(async move { - let response = client.download_file(&url).await; - match response { - Ok(url) => { - download_file(&url, &name); - } - Err(err) => { - log::error!("Error requesting file download {:?}", err); - } - } - }); - }); - - html! { - - {source.display_name.clone()} - - } - } else { - html! { - - {source.display_name.clone()} - - } - }; - - html! { - - -
    {doc_type_icon}
    - - - {url_link} -
    {source.url.clone()}
    - - {status_icon} - - - {if *is_deleting { - html! {} - } else { - html! { - - } - }} - - - - } -} - -#[derive(Properties, PartialEq)] -pub struct SourceTableProps { - sources: Vec, - paginator: LensSourcePaginator, - selected_filter: LensSourceQueryFilter, - is_loading: bool, - #[prop_or_default] - on_delete: Callback, - #[prop_or_default] - on_refresh: Callback, - #[prop_or_default] - on_select_page: Callback, - #[prop_or_default] - on_select_filter: Callback, -} - -#[function_component(SourceTable)] -pub fn source_table(props: &SourceTableProps) -> Html { - let source_html = if props.sources.is_empty() { - html! { - - - {"Try a different filter or adding a source."} - - - } - } else { - props.sources - .iter() - .map(|x| html! { }) - .collect::() - }; - - let header_styles = classes!( - "border-b", - "dark:border-neutral-600", - "font-medium", - "p-2", - "text-neutral-400", - "dark:text-neutral-200", - "text-left" - ); - - let filters = LensSourceQueryFilter::iter() - .map(|x| { - let btn_type = if x == props.selected_filter { - BtnType::Primary - } else { - BtnType::Default - }; - - let on_select = props.on_select_filter.clone(); - let cb = Callback::from(move |_| on_select.emit(x)); - html! { - - {x.to_string()} - - } - }) - .collect::(); - - html! { -
    -
    -
    {format!("Data Sources ({})", props.paginator.num_items)}
    -
    - {"Filter:"} - {filters} -
    - - - {"Refresh"} - -
    - {if props.is_loading { - html! { -
    - -
    - } - } else { - html! { - <> - - - - - - - - - - {source_html} -
    {"Document"}
    - {if props.paginator.num_pages > 1 { - html! { -
    - -
    - } - } else { - html! {} - }} - - } - }} -
    - } -} diff --git a/apps/web/src/pages/mod.rs b/apps/web/src/pages/mod.rs deleted file mode 100644 index 560902153..000000000 --- a/apps/web/src/pages/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -use yew::prelude::*; - -pub mod chat; -pub mod dashboard; -pub mod discover; -pub mod embedded; -pub mod landing; -pub mod lens_editor; -pub mod search; - -#[derive(Properties, PartialEq)] -pub struct AppPageProps { - #[prop_or_default] - pub children: Children, -} - -#[function_component] -pub fn AppPage(props: &AppPageProps) -> Html { - html! { -
    - {props.children.clone()} -
    - } -} diff --git a/apps/web/src/pages/search.rs b/apps/web/src/pages/search.rs deleted file mode 100644 index 2ce99713c..000000000 --- a/apps/web/src/pages/search.rs +++ /dev/null @@ -1,901 +0,0 @@ -use crate::{ - client::{ApiClient, ApiError, Lens, SpyglassClient}, - AuthStatus, Route, -}; -use futures::lock::Mutex; -use shared::response::SearchResult; -use shared::{ - keyboard::KeyCode, - response::{ChatErrorType, ChatUpdate}, -}; -use std::str::FromStr; -use std::sync::Arc; -use strum_macros::Display; -use ui_components::{ - btn::{Btn, BtnSize, BtnType}, - icons::{RefreshIcon, SearchIcon}, - results::{ResultPaginator, WebSearchResultItem}, -}; -use wasm_bindgen_futures::spawn_local; -use web_sys::HtmlInputElement; -use yew::platform::pinned::mpsc; -use yew::{html::Scope, platform::pinned::mpsc::UnboundedSender, prelude::*}; -use yew_router::prelude::*; - -// make sure we only have one connection per client -type Client = Arc>; - -#[derive(Clone, PartialEq, Eq, Display)] -pub enum HistorySource { - #[strum(serialize = "assistant")] - Clippy, - #[strum(serialize = "user")] - User, - #[strum(serialize = "system")] - System, -} - -#[derive(Clone, PartialEq, Eq)] -pub struct HistoryItem { - /// who "wrote" this response - pub source: HistorySource, - pub value: String, -} - -#[allow(dead_code)] -pub enum Msg { - Focus, - SetChatUuid(String), - ContextAdded(String), - HandleFollowup(String), - HandleKeyboardEvent(KeyboardEvent), - HandleSearch, - Reload, - ReloadSavedSession(bool), - SetError(String), - SetFinished, - SetLensData(Lens), - SetQuery(String), - SetSearchResults(Vec), - SetStatus(String), - StopSearch, - ToggleContext, - TokenReceived(String), - UpdateContext(AuthStatus), -} - -#[derive(Properties, PartialEq)] -pub struct SearchPageProps { - pub lens: String, - pub session_uuid: String, - pub chat_session: Option, - pub embedded: bool, - pub lens_data: Option, -} - -#[derive(Clone, Debug)] -pub enum WorkerCmd { - Stop, -} - -pub struct SearchPage { - client: Client, - lens_identifier: String, - lens_data: Option, - auth_status: AuthStatus, - current_query: Option, - history: Vec, - in_progress: bool, - results: Vec, - search_input_ref: NodeRef, - search_wrapper_ref: NodeRef, - status_msg: Option, - tokens: Option, - context: Option, - show_context: bool, - chat_uuid: Option, - session_uuid: String, - historical_chat: bool, - embedded: bool, - _worker_cmd: Option>, - _context_listener: ContextHandle, -} - -impl Component for SearchPage { - type Message = Msg; - type Properties = SearchPageProps; - - fn create(ctx: &yew::Context) -> Self { - let props = ctx.props(); - - let (auth_status, context_listener) = ctx - .link() - .context(ctx.link().callback(Msg::UpdateContext)) - .expect("No Message Context Provided"); - - if props.chat_session.is_some() { - ctx.link().send_message(Msg::ReloadSavedSession(true)); - } else if props.lens_data.is_none() { - ctx.link().send_message(Msg::Reload); - } - - { - let link = ctx.link().clone(); - let timeout = - gloo::timers::callback::Timeout::new(1_000, move || link.send_message(Msg::Focus)); - timeout.forget(); - } - - Self { - client: Arc::new(Mutex::new(SpyglassClient::new( - props.lens.clone(), - props.session_uuid.clone(), - auth_status.token.clone(), - props.embedded, - ))), - embedded: props.embedded, - auth_status, - context: None, - current_query: None, - history: Vec::new(), - in_progress: false, - lens_data: props.lens_data.clone(), - lens_identifier: props.lens.clone(), - results: Vec::new(), - search_input_ref: Default::default(), - search_wrapper_ref: Default::default(), - show_context: false, - status_msg: None, - tokens: None, - chat_uuid: props.chat_session.clone(), - session_uuid: props.session_uuid.clone(), - historical_chat: props.chat_session.is_some(), - _context_listener: context_listener, - _worker_cmd: None, - } - } - - fn changed(&mut self, ctx: &Context, _old_props: &Self::Properties) -> bool { - if self.in_progress { - ctx.link().send_message(Msg::StopSearch); - } - - let new_lens = ctx.props().lens.clone(); - let new_chat_session = ctx.props().chat_session.clone(); - self.historical_chat = new_chat_session.is_some(); - - let lens_changed = self.lens_identifier != new_lens; - let chat_session_changed = self.chat_uuid != new_chat_session; - let chat_session_set = new_chat_session.is_some(); - - if lens_changed { - self.lens_identifier = new_lens; - if chat_session_set && chat_session_changed { - self.chat_uuid = new_chat_session; - ctx.link().send_message(Msg::ReloadSavedSession(true)); - } else { - ctx.link().send_message(Msg::Reload); - } - true - } else if chat_session_changed { - if chat_session_set { - self.chat_uuid = new_chat_session; - ctx.link().send_message(Msg::ReloadSavedSession(false)); - } else { - ctx.link().send_message(Msg::Reload); - } - - true - } else { - false - } - } - - fn update(&mut self, ctx: &yew::Context, msg: Self::Message) -> bool { - let link = ctx.link(); - match msg { - Msg::Focus => { - if let Some(search_input) = self.search_input_ref.cast::() { - let _ = search_input.focus(); - } - true - } - Msg::SetChatUuid(uuid) => { - self.chat_uuid = Some(uuid); - false - } - Msg::ContextAdded(context) => { - self.context = Some(context); - false - } - Msg::HandleFollowup(question) => { - log::info!("handling followup: {}", question); - // Push existing question & answer into history - if let Some(value) = &self.current_query { - self.history.push(HistoryItem { - source: HistorySource::User, - value: value.to_owned(), - }); - } - - // Push existing answer into history - if let Some(value) = &self.tokens { - self.history.push(HistoryItem { - source: HistorySource::Clippy, - value: value.to_owned(), - }); - } - - // Push user's question into history - self.history.push(HistoryItem { - source: HistorySource::User, - value: question.clone(), - }); - self.context = None; - let mut cur_history = self.history.clone(); - // Add context to the beginning - if let Some(context) = &self.context { - cur_history.insert( - 0, - HistoryItem { - source: HistorySource::User, - value: context.to_owned(), - }, - ); - } - - self.tokens = None; - self.status_msg = None; - self.context = None; - self.in_progress = true; - - let link = link.clone(); - - let cur_doc_context = self.results.clone(); - let chat_uuid = self.chat_uuid.clone(); - let client = self.client.clone(); - let (tx, rx) = mpsc::unbounded::(); - self._worker_cmd = Some(tx); - spawn_local(async move { - let mut client = client.lock().await; - if let Err(err) = client - .followup( - &question, - &cur_history, - &cur_doc_context, - &chat_uuid, - &{ - let link = link.clone(); - move |update| process_update(update, &link) - }, - rx, - ) - .await - { - log::error!("{}", err.to_string()); - link.send_message(Msg::SetError(err.to_string())); - } - }); - - true - } - Msg::HandleKeyboardEvent(event) => { - let key = event.key(); - if let Ok(code) = KeyCode::from_str(&key.to_uppercase()) { - if code == KeyCode::Enter { - log::info!("key-code: {code}"); - link.send_message(Msg::HandleSearch); - } - } - false - } - Msg::HandleSearch => { - if let Some(search_input) = self.search_input_ref.cast::() { - self.reset_search(); - let query = search_input.value(); - link.send_message(Msg::SetQuery(query)); - search_input.set_value(""); - } - false - } - Msg::ReloadSavedSession(full_reload) => { - if self.chat_uuid.is_some() { - let chat_uuid = self.chat_uuid.clone().unwrap(); - if full_reload { - self.reload(link); - } else { - self.reset_search(); - } - - self.chat_uuid = Some(chat_uuid.clone()); - if let Some(data) = &self.auth_status.user_data { - if let Some(history) = data - .history - .iter() - .find(|history| history.session_id == chat_uuid) - { - let mut first_question = None; - for qna in &history.qna { - if first_question.is_none() { - first_question = Some(qna.question.clone()); - } - self.history.push(HistoryItem { - source: HistorySource::User, - value: qna.question.clone(), - }); - self.history.push(HistoryItem { - source: HistorySource::Clippy, - value: qna.response.clone(), - }); - - if let Some(doc_details) = &qna.document_details { - link.send_message(Msg::SetSearchResults(doc_details.clone())) - } - } - self.current_query = first_question; - } - } - } else { - self.reload(link); - } - true - } - Msg::Reload => { - self.reload(link); - true - } - Msg::SetError(err) => { - self.in_progress = false; - self.status_msg = Some(err); - true - } - Msg::SetFinished => { - self.in_progress = false; - self.status_msg = None; - true - } - Msg::SetLensData(data) => { - self.lens_data = Some(data); - true - } - Msg::SetSearchResults(results) => { - self.results = results; - true - } - Msg::SetStatus(msg) => { - self.status_msg = Some(msg); - true - } - Msg::SetQuery(query) => { - self.in_progress = true; - self.tokens = None; - self.results = Vec::new(); - self.current_query = Some(query.clone()); - - log::info!("handling search! {}", query); - self.status_msg = Some(format!("searching: {query}")); - - let link = link.clone(); - let client = self.client.clone(); - - let (tx, rx) = mpsc::unbounded::(); - self._worker_cmd = Some(tx); - spawn_local(async move { - let mut client = client.lock().await; - if let Err(err) = client - .search( - &query, - &{ - let link = link.clone(); - move |update| process_update(update, &link) - }, - rx, - ) - .await - { - log::error!("{}", err.to_string()); - link.send_message(Msg::SetError(err.to_string())); - } else { - log::info!("finished response"); - } - }); - - true - } - Msg::StopSearch => { - if let Some(tx) = &self._worker_cmd { - self.in_progress = false; - let _ = tx.send_now(WorkerCmd::Stop); - tx.close_now(); - self._worker_cmd = None; - } - true - } - Msg::ToggleContext => { - self.show_context = !self.show_context; - true - } - Msg::TokenReceived(token) => { - if let Some(tokens) = self.tokens.as_mut() { - tokens.push_str(&token); - } else { - self.tokens = Some(token.to_owned()); - } - true - } - Msg::UpdateContext(auth) => { - self.auth_status = auth; - if self.chat_uuid.is_some() { - link.send_message(Msg::ReloadSavedSession(true)) - } else { - link.send_message(Msg::Reload); - } - false - } - } - } - - fn view(&self, ctx: &yew::Context) -> yew::Html { - let link = ctx.link(); - if let Some(lens) = self.lens_data.clone() { - html! { - <> - {self.render_search(link, &lens)} - {if !self.auth_status.is_authenticated { - html! { - - } - } else { html! {} }} - - } - } else { - html! {} - } - } -} - -fn process_update(update: ChatUpdate, link: &Scope) { - match update { - ChatUpdate::ChatStart(uuid) => { - log::info!("ChatUpdate::ChatStart"); - link.send_message(Msg::SetChatUuid(uuid)) - } - ChatUpdate::SearchingDocuments => { - log::info!("ChatUpdate::SearchingDocuments"); - link.send_message(Msg::SetStatus("Searching...".into())) - } - ChatUpdate::DocumentContextAdded(docs) => { - log::info!("ChatUpdate::DocumentContextAdded"); - link.send_message(Msg::SetSearchResults(docs)) - } - ChatUpdate::GeneratingContext => { - log::info!("ChatUpdate::SearchingDocuments"); - link.send_message(Msg::SetStatus("Analyzing documents...".into())) - } - ChatUpdate::ContextGenerated(context) => { - log::info!("ChatUpdate::ContextGenerated {}", context); - link.send_message(Msg::ContextAdded(context)); - } - ChatUpdate::LoadingModel | ChatUpdate::LoadingPrompt => { - link.send_message(Msg::SetStatus("Generating answer...".into())) - } - ChatUpdate::Token(token) => link.send_message(Msg::TokenReceived(token)), - ChatUpdate::EndOfText => { - link.send_message(Msg::SetFinished); - } - ChatUpdate::Error(err) => { - log::error!("ChatUpdate::Error: {err:?}"); - let msg = match err { - ChatErrorType::ContextLengthExceeded(msg) => msg, - ChatErrorType::APIKeyMissing => "No API key".into(), - ChatErrorType::UnknownError(msg) => msg, - }; - link.send_message(Msg::SetError(msg)); - } - } -} - -impl SearchPage { - fn reset_search(&mut self) { - self.context = None; - self.current_query = None; - self.history.clear(); - self.in_progress = false; - self.results.clear(); - self.status_msg = None; - self.tokens = None; - self.chat_uuid = None; - } - - fn render_search(&self, link: &Scope, lens: &Lens) -> Html { - let placeholder = format!("Ask anything related to \"{}\"", lens.display_name); - - let results = self - .results - .iter() - .map(|result| { - html! { - - } - }) - .collect::>(); - - let nav_link = link.clone(); - let lens_id = self.lens_identifier.clone(); - let nav_callback = Callback::from(move |_| { - nav_link.navigator().unwrap().push(&Route::Search { - lens: lens_id.clone(), - }) - }); - - html! { -
    -
    - {if let Some(image) = lens.image.clone() { - html! { -
    - -
    - } - } else { html! {} }} -
    -
    {lens.display_name.clone()}
    - {if let Some(desc) = lens.description.clone() { - html! { -
    - {desc} -
    - } - } else { html! {} }} -
    -
    - {if !self.historical_chat { - html! { -
    - -
    - {if self.in_progress { - html! { - - - {"Stop"} - - } - } else { - html! { - - - - - } - }} -
    -
    - } - } - else { - html! { -
    - - {"Start New Search"} - -
    - } - }} - {if self.show_context { - html! { -
    -
    {"Context"}
    -
    {self.context.clone()}
    -
    - } - } else { - html! {} - }} - {if let Some(query) = &self.current_query { - html! {
    {query}
    } - } else { html! {}}} -
    - { if !self.history.is_empty() || self.tokens.is_some() || self.status_msg.is_some() { - html! { - - } - } else if !lens.example_questions.is_empty() { - html! { - - } - } else { - html! {} - }} - -
    - {if !results.is_empty() { - html! { - <> -
    {"Related"}
    - {results} - - } - } else if self.current_query.is_some() { - html! { - <> -
    {"Related"}
    -
    - { - "We didn't find any relevant documents, but we - will try to answer the question to the best of our ability - without any additional context" - } -
    - - } - } else { - html! {} - }} -
    -
    -
    - } - } - - // Fully reloads and resets the search context. This is used when the lens has changed. - fn reload(&mut self, link: &Scope) { - self.reset_search(); - self.client = Arc::new(Mutex::new(SpyglassClient::new( - self.lens_identifier.clone(), - self.session_uuid.clone(), - self.auth_status.token.clone(), - self.embedded, - ))); - - let auth_status = self.auth_status.clone(); - let identifier = self.lens_identifier.clone(); - let link = link.clone(); - let embedded = self.embedded; - spawn_local(async move { - let api = if embedded { - ApiClient::new(None, true) - } else { - auth_status.get_client() - }; - - match api.lens_retrieve(&identifier).await { - Ok(lens) => link.send_message(Msg::SetLensData(lens)), - Err(ApiError::ClientError(msg)) => { - // Unauthorized - if msg.code == 400 { - let navi = link.navigator().expect("No navigator"); - navi.push(&crate::Route::Start); - } - log::error!("error retrieving lens: {msg}"); - } - Err(err) => log::error!("error retrieving lens: {}", err), - } - }); - } -} - -#[derive(Properties, PartialEq)] -struct AnswerSectionProps { - pub history: Vec, - pub tokens: Option, - pub status: Option, - #[prop_or_default] - pub in_progress: bool, - #[prop_or_default] - pub on_followup: Callback, -} - -#[function_component(AnswerSection)] -fn answer_section(props: &AnswerSectionProps) -> Html { - let ask_followup = use_node_ref(); - let ask_followup_handle = ask_followup.clone(); - let on_followup_cb = props.on_followup.clone(); - let on_ask_followup = Callback::from(move |event: SubmitEvent| { - event.prevent_default(); - if let Some(node) = ask_followup_handle.cast::() { - on_followup_cb.emit(node.value()); - node.set_value(""); - } - }); - - html! { -
    -
    {"Answer"}
    -
    -
    - - { if let Some(tokens) = &props.tokens { - html! { } - } else if let Some(msg) = &props.status { - html! { } - } else { - html! {} - }} -
    -
    - - -
    -
    -
    - } -} - -#[derive(Properties, PartialEq)] -struct HistoryLogProps { - pub history: Vec, -} - -#[function_component(HistoryLog)] -fn history_log(props: &HistoryLogProps) -> Html { - let html = props - .history - .iter() - // Skip the initial question, we already show this at the top. - .skip(1) - .map(|item| { - html! { - - } - }) - .collect::(); - html! { <>{html} } -} - -#[derive(Properties, PartialEq)] -struct HistoryLogItemProps { - pub source: HistorySource, - pub tokens: String, - // Is this a item currently generating tokens? - #[prop_or_default] - pub in_progress: bool, -} - -#[function_component(HistoryLogItem)] -fn history_log_item(props: &HistoryLogItemProps) -> Html { - let user_icon = match props.source { - HistorySource::Clippy | HistorySource::System => html! {<>{"🔭"}}, - HistorySource::User => html! {<>{"🧙‍♂️"}}, - }; - - let html = markdown::to_html(&props.tokens.clone()); - let html = html.trim_start_matches("

    ").to_string(); - let html = html.trim_end_matches("

    ").to_string(); - let html = format!("{}", html); - - let item_classes = if props.source == HistorySource::User { - classes!("text-white", "font-bold", "text-lg") - } else { - classes!( - "prose-sm", - "md:prose-base", - "prose", - "prose-invert", - "inline" - ) - }; - - html! { -
    -

    - {Html::from_html_unchecked(AttrValue::from(html))} - { if props.in_progress && props.source != HistorySource::User { - html! {

    } - } else { html! {} }} -

    - { if !props.in_progress && props.source != HistorySource::User { - html! {
    {user_icon}
    } - } else { - html! {} - }} -
    - } -} - -#[derive(Properties, PartialEq)] -pub struct FAQComponentProps { - questions: Vec, - #[prop_or_default] - onclick: Callback, -} - -#[function_component(FAQComponent)] -fn faq_component(props: &FAQComponentProps) -> Html { - let qa_classes = classes!( - "text-cyan-500", - "text-base", - "md:text-lg", - "p-2", - "md:p-4", - "rounded", - "border", - "border-neutral-500", - "underline", - "cursor-pointer", - "hover:bg-neutral-700", - "text-left", - ); - - let onclick = props.onclick.clone(); - let questions = props - .questions - .iter() - .map(|q| { - let onclick = onclick.clone(); - let question = q.clone(); - let callback = Callback::from(move |_| { - onclick.emit(question.clone()); - }); - html! { - - } - }) - .collect::(); - - html! { -
    -
    {"Example Questions"}
    -
    - {"Not sure where to start? Try one of these questions"} -
    -
    - {questions} -
    -
    - } -} diff --git a/apps/web/src/schema.rs b/apps/web/src/schema.rs deleted file mode 100644 index 5132dfd3f..000000000 --- a/apps/web/src/schema.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::client::LensSource; -use serde::{Deserialize, Serialize}; -use strum_macros::{Display, EnumIter}; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub struct EmbedConfiguration { - pub prompt_style: EmbeddedPromptStyle, - pub theme: Theme, - pub header_color: Option, - pub bot_bubble_color: Option, - pub user_bubble_color: Option, - pub header_title: Option, - pub initial_chat: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum EmbeddedPromptStyle { - Research, - Chat, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum Theme { - DarkMode, - LightMode, -} - -#[derive(Clone, Copy, Serialize, PartialEq, EnumIter, Display)] -pub enum LensSourceQueryFilter { - #[strum(serialize = "All")] - All, - #[strum(serialize = "Completed")] - Completed, - #[strum(serialize = "In Progress")] - InProgress, - #[strum(serialize = "Failed")] - Failed, - #[strum(serialize = "Not Started")] - NotStarted, -} - -impl Default for LensSourceQueryFilter { - fn default() -> Self { - Self::All - } -} - -#[derive(Serialize)] -pub struct GetLensSourceRequest { - pub page: usize, - pub filter: LensSourceQueryFilter, -} - -#[derive(Deserialize)] -pub struct GetLensSourceResponse { - pub page: usize, - pub num_items: usize, - pub num_pages: usize, - pub results: Vec, -} diff --git a/apps/web/src/utils.rs b/apps/web/src/utils.rs deleted file mode 100644 index 5fb1640e9..000000000 --- a/apps/web/src/utils.rs +++ /dev/null @@ -1,26 +0,0 @@ -use js_sys::decode_uri_component; - -pub fn decode_string(value: &str) -> String { - if let Ok(Some(decoded)) = decode_uri_component(value).map(|x| x.as_string()) { - decoded - } else { - value.to_owned() - } -} - -pub fn validate_hex_color(hex_color: &str) -> Result<(), String> { - // Check if the hex color is valid. - if hex_color.len() != 3 && hex_color.len() != 6 { - return Err("Invalid hex color length.".to_string()); - } - - // Check if the hex color contains only valid characters. - for c in hex_color.chars() { - if !c.is_ascii_hexdigit() { - return Err("Invalid hex color character.".to_string()); - } - } - - // The hex color is valid. - Ok(()) -} diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js deleted file mode 100644 index 5b63387e7..000000000 --- a/apps/web/tailwind.config.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = { - content: [ - "./src/**/*.{html,js,rs}", - "./*.html", - "../../crates/ui-components/**/*.rs" - ], - theme: { - minWidth: { - "4": "1rem", - "5": "1.25rem" - }, - extend: { - keyframes: { - "fade-in": { - "0%": { - opacity: "0", - transform: "translateY(10px)", - }, - "100%": { - opacity: "1", - transform: "translateY(0)", - }, - }, - wiggle: { - "0%, 100%": { transform: "rotate(-6deg)" }, - "50%": { transform: "rotate(6deg)" }, - } - }, - animation: { - "fade-in": "fade-in 0.5s ease-out", - "pulse-fast": "pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite", - "wiggle-short": "wiggle 1s ease-in-out 10", - "wiggle": "wiggle 1s ease-in-out infinite", - } - }, - fontSize: { - // 10px - xs: "0.625rem", - // 12px - sm: "0.75rem", - // 14px - base: "0.875rem", - // 16px - lg: "1rem", - xl: "1.125rem", - "2xl": "1.25rem", - "3xl": "1.5rem", - "4xl": "1.875rem", - "5xl": "2rem", - "6xl": "3rem", - } - }, - plugins: [ - require("@tailwindcss/forms")({ strategy: "class" }), - require("@tailwindcss/typography") - ], -} diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index fc89762de..401a0c9fd 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -19,11 +19,13 @@ serde_json = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } spyglass-lens = "0.1.7" +ts-rs = "10.0" uuid = { workspace = true } url = "2.2" # Dependencies for metrics chrono = { workspace = true, optional = true } reqwest = { workspace = true, optional = true } + [features] metrics = ["dep:chrono", "dep:reqwest"] \ No newline at end of file diff --git a/crates/shared/src/config.rs b/crates/shared/src/config.rs index e9c92a4ad..54a112570 100644 --- a/crates/shared/src/config.rs +++ b/crates/shared/src/config.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; use std::path::PathBuf; +use ts_rs::TS; use uuid::Uuid; pub use spyglass_lens::{ @@ -62,7 +63,8 @@ impl Limit { } // Enum of actions the user can take when a document is selected -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff, TS)] +#[ts(export)] pub enum UserAction { OpenApplication(String, String), OpenUrl(String), diff --git a/crates/shared/src/config/user_actions.rs b/crates/shared/src/config/user_actions.rs index c4cffadce..23a3949a8 100644 --- a/crates/shared/src/config/user_actions.rs +++ b/crates/shared/src/config/user_actions.rs @@ -1,6 +1,7 @@ use diff::Diff; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use ts_rs::TS; use crate::accelerator; use crate::keyboard::{KeyCode, ModifiersState}; @@ -11,7 +12,8 @@ use super::{Tag, UserAction}; // Defines context specific actions. A context specific action // is a list of actions that are only valid when the document selected // matches the defined context. -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff, TS)] +#[ts(export)] pub struct ContextActions { // Defines what context must be matched for the actions to be valid pub context: ContextFilter, @@ -126,7 +128,8 @@ impl ContextActions { // Filter definition used to define what documents should match // against the context. -#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Diff)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Diff, TS)] +#[ts(export)] pub struct ContextFilter { // Includes documents that match any of the defined tags pub has_tag: Option>, @@ -143,7 +146,8 @@ pub struct ContextFilter { } // The definition for an action -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff, TS)] +#[ts(export)] pub struct UserActionDefinition { pub label: String, pub status_msg: Option, @@ -165,7 +169,8 @@ impl UserActionDefinition { // The user action settings configuration provides the ability // for the user to define custom behavior for a document. -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Diff, TS)] +#[ts(export)] pub struct UserActionSettings { pub actions: Vec, pub context_actions: Vec, diff --git a/crates/shared/src/event.rs b/crates/shared/src/event.rs index 9367223b7..1516932a1 100644 --- a/crates/shared/src/event.rs +++ b/crates/shared/src/event.rs @@ -1,12 +1,14 @@ use serde::{Deserialize, Serialize}; use strum_macros::{AsRefStr, Display}; +use ts_rs::TS; #[derive(Clone, Debug, Deserialize)] pub struct ListenPayload { pub payload: T, } -#[derive(AsRefStr, Display)] +#[derive(AsRefStr, Display, TS)] +#[ts(export)] pub enum ClientEvent { ClearSearch, FocusWindow, @@ -23,61 +25,68 @@ pub enum ClientEvent { UpdateLensFinished, } -#[derive(AsRefStr, Display)] +#[derive(AsRefStr, Display, Deserialize, Serialize, TS)] +#[ts(export)] pub enum ClientInvoke { - #[strum(serialize = "authorize_connection")] + #[serde(rename = "authorize_connection")] AuthorizeConnection, - #[strum(serialize = "choose_folder")] + #[serde(rename = "choose_folder")] ChooseFolder, - #[strum(serialize = "default_indices")] + #[serde(rename = "default_indices")] DefaultIndices, - #[strum(serialize = "escape")] + #[serde(rename = "escape")] Escape, - #[strum(serialize = "open_plugins_folder")] + #[serde(rename = "open_plugins_folder")] EditPluginSettings, - #[strum(serialize = "get_library_stats")] + #[serde(rename = "get_library_stats")] GetLibraryStats, - #[strum(serialize = "get_shortcut")] + #[serde(rename = "get_shortcut")] GetShortcut, - #[strum(serialize = "plugin:tauri-plugin-startup|get_startup_progress")] + #[serde(rename = "plugin:tauri-plugin-startup|get_startup_progress")] GetStartupProgressText, - #[strum(serialize = "plugin:lens-updater|install_lens")] + #[serde(rename = "plugin:lens-updater|install_lens")] InstallLens, - #[strum(serialize = "list_connections")] + #[serde(rename = "list_connections")] ListConnections, - #[strum(serialize = "plugin:lens-updater|list_installed_lenses")] + #[serde(rename = "plugin:lens-updater|list_installed_lenses")] ListInstalledLenses, - #[strum(serialize = "plugin:lens-updater|list_installable_lenses")] + #[serde(rename = "plugin:lens-updater|list_installable_lenses")] ListInstallableLenses, - #[strum(serialize = "list_plugins")] + #[serde(rename = "list_plugins")] ListPlugins, - #[strum(serialize = "load_user_settings")] + #[serde(rename = "load_user_settings")] LoadUserSettings, - #[strum(serialize = "load_action_settings")] + #[serde(rename = "load_action_settings")] LoadUserActions, - #[strum(serialize = "resync_connection")] + #[serde(rename = "resize_window")] + ResizeWindow, + #[serde(rename = "resync_connection")] ResyncConnection, - #[strum(serialize = "revoke_connection")] + #[serde(rename = "revoke_connection")] RevokeConnection, - #[strum(serialize = "plugin:lens-updater|run_lens_updater")] + #[serde(rename = "plugin:lens-updater|run_lens_updater")] RunLensUpdater, - #[strum(serialize = "open_folder_path")] + #[serde(rename = "search_docs")] + SearchDocuments, + #[serde(rename = "search_lenses")] + SearchLenses, + #[serde(rename = "open_folder_path")] OpenFolder, - #[strum(serialize = "open_lens_folder")] + #[serde(rename = "open_lens_folder")] OpenLensFolder, - #[strum(serialize = "open_result")] + #[serde(rename = "open_result")] OpenResult, - #[strum(serialize = "copy_to_clipboard")] + #[serde(rename = "copy_to_clipboard")] CopyToClipboard, - #[strum(serialize = "open_settings_folder")] + #[serde(rename = "open_settings_folder")] OpenSettingsFolder, - #[strum(serialize = "plugin:lens-updater|uninstall_lens")] + #[serde(rename = "plugin:lens-updater|uninstall_lens")] UninstallLens, - #[strum(serialize = "update_and_restart")] + #[serde(rename = "update_and_restart")] UpdateAndRestart, - #[strum(serialize = "wizard_finished")] + #[serde(rename = "wizard_finished")] WizardFinished, - #[strum(serialize = "navigate")] + #[serde(rename = "navigate")] Navigate, } @@ -97,7 +106,8 @@ pub struct InstallLensParams { pub name: String, } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, TS)] +#[ts(export)] pub struct OpenResultParams { pub url: String, pub application: Option, diff --git a/crates/shared/src/response.rs b/crates/shared/src/response.rs index d6aeeb4e4..29124eae7 100644 --- a/crates/shared/src/response.rs +++ b/crates/shared/src/response.rs @@ -2,6 +2,7 @@ use crate::url_to_file_path; use num_format::{Buffer, Locale}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use ts_rs::TS; use url::Url; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -57,7 +58,8 @@ impl InstallableLens { } } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)] +#[ts(export)] pub enum InstallStatus { NotInstalled, Finished { num_docs: u32 }, @@ -82,7 +84,8 @@ impl InstallStatus { } } -#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, TS)] +#[ts(export)] pub enum LensType { #[default] Lens, @@ -91,7 +94,8 @@ pub enum LensType { Internal, } -#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq, TS)] +#[ts(export)] pub struct LensResult { /// Author of this lens pub author: String, @@ -122,14 +126,16 @@ pub struct PluginResult { pub is_enabled: bool, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] pub struct SearchMeta { pub query: String, pub num_docs: u32, pub wall_time_ms: u32, } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TS)] +#[ts(export)] pub struct SearchResult { /// Document ID pub doc_id: String, @@ -226,7 +232,8 @@ impl From for SearchResultTemplate { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize, TS)] +#[ts(export)] pub struct SearchResults { pub results: Vec, pub meta: SearchMeta,