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 + React
+
+
setCount((count) => count + 1)}>
+ count is {count}
+
+
+ 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 (
+
+ ENTER
+ to open.
+
+ );
+}
+
+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 (
+
+ );
+}
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 (
+
+ );
+}
+
+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 (
+
+ );
+}
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 (
+ <>
+
+
+ {"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! {
-
-
-
-
-
-
- }
- }
- ChatAlign::Right => {
- html! {
-
-
-
-
-
-
- }
- }
- }
-}
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"}
-
-
- {if self.processing {
- html! {
-
- }
- } else {
- html! {
-
- }
- }}
-
- {if upload_text.is_some() {
- html! {
{upload_text.unwrap()}
}
- } else {
- html! {}
- }}
-
-
-
-
-
- { 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! { }
-}
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! {
- <>
-
-
-
- {"Menu"}
-
-
-
- { if *toggle_nav {
- html! {
-
- }
- } else { html! {} }}
-
-
-
-
- {if auth_status.is_authenticated {
- if let Some(profile) = auth_status.user_profile {
- html! {
-
-
-
-
{profile.name}
-
-
- }
- } else {
- html! {}
- }
- } else {
- html! {}
- }}
-
-
-
-
-
- {"My Q&As"}
-
- {history_buttons}
-
-
-
- {"build: "}
- {dotenv!("GIT_HASH")}
-
- {debug_vars}
-
-
- >
- }
-}
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"}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {"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"}
-
-
-
- VIDEO
-
-
-
-
- {"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! {
-
-
-
-
- {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"}
-
-
-
-
-
-
- {"Add all pages"}
-
-
-
- {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}
-
- {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! {
- {q.clone()}
- }
- })
- .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,