9 Commits

Author SHA1 Message Date
5f90d663cf Add docker for web
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 23:12:01 +02:00
ea61ba9ed7 Add web 2022-07-18 22:57:33 +02:00
86cc2ea889 add cors
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 14:04:13 +02:00
5aecf1ef26 allow telegram on failure
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 13:53:47 +02:00
085fc3b179 set localhost to public
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 13:42:20 +02:00
66358bdd05 set localhost to public
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2022-07-18 13:40:17 +02:00
2608b10efa Without env
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 13:33:27 +02:00
92ce57dc60 With auto_tag
All checks were successful
continuous-integration/drone/push Build is passing
2022-07-18 13:31:50 +02:00
05745f51ad 07-17-remove_ticker (#2)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: https://git.front.kjuulh.io/kjuulh/scel/pulls/2
2022-07-18 13:17:02 +02:00
38 changed files with 2488 additions and 102 deletions

4
.dockerignore Normal file
View File

@@ -0,0 +1,4 @@
target/
.git/
.env
data/

29
.drone.yml Normal file
View File

@@ -0,0 +1,29 @@
kind: pipeline
name: default
type: docker
steps:
- name: server
image: plugins/docker
environment:
DOCKER_BUILDKIT: 1
settings:
username: kasperhermansen
password:
from_secret:
docker_secret
repo: kasperhermansen/scel
tags: latest
context: .
dockerfile: Dockerfile
cache_from: kasperhermansen/scel:latest
- name: send telegram notification
image: appleboy/drone-telegram
settings:
token:
from_secret: telegram_token
to: 2129601481
format: markdown
when:
status: [failure]

1
.gitignore vendored
View File

@@ -1 +1,2 @@
target/ target/
.env

652
Cargo.lock generated
View File

@@ -36,6 +36,18 @@ version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]] [[package]]
name = "ascii_utils" name = "ascii_utils"
version = "0.9.3" version = "0.9.3"
@@ -59,10 +71,12 @@ dependencies = [
"futures-util", "futures-util",
"http", "http",
"indexmap", "indexmap",
"log",
"mime", "mime",
"multer", "multer",
"num-traits", "num-traits",
"once_cell", "once_cell",
"opentelemetry",
"pin-project-lite", "pin-project-lite",
"regex", "regex",
"serde", "serde",
@@ -70,6 +84,8 @@ dependencies = [
"static_assertions", "static_assertions",
"tempfile", "tempfile",
"thiserror", "thiserror",
"tracing",
"tracing-futures",
] ]
[[package]] [[package]]
@@ -130,6 +146,36 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "async-lock"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
dependencies = [
"event-listener",
]
[[package]]
name = "async-session"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07da4ce523b4e2ebaaf330746761df23a465b951a83d84bbce4233dabedae630"
dependencies = [
"anyhow",
"async-lock",
"async-trait",
"base64",
"bincode",
"blake3",
"chrono",
"hmac",
"log",
"rand",
"serde",
"serde_json",
"sha2 0.9.9",
]
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.3" version = "0.3.3"
@@ -217,18 +263,70 @@ dependencies = [
"mime", "mime",
] ]
[[package]]
name = "axum-extra"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "277c75e6c814b061ae4947d02335d9659db9771b9950cca670002ae986372f44"
dependencies = [
"axum",
"bytes",
"futures-util",
"http",
"mime",
"pin-project-lite",
"tokio",
"tower",
"tower-http",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake3"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3"
dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if 0.1.10",
"constant_time_eq",
"crypto-mac 0.8.0",
"digest 0.9.0",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.2" version = "0.10.2"
@@ -238,6 +336,12 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "bumpalo"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@@ -253,12 +357,43 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"winapi",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.2" version = "0.2.2"
@@ -268,6 +403,26 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "crossbeam-channel"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
dependencies = [
"cfg-if 1.0.0",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
dependencies = [
"cfg-if 1.0.0",
"once_cell",
]
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.5" version = "0.1.5"
@@ -278,6 +433,26 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "crypto-mac"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array",
"subtle",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.14.1" version = "0.14.1"
@@ -313,25 +488,46 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.3" version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [ dependencies = [
"block-buffer", "block-buffer 0.10.2",
"crypto-common", "crypto-common",
] ]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.31" version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]] [[package]]
name = "fast_chemail" name = "fast_chemail"
version = "0.9.6" version = "0.9.6"
@@ -471,9 +667,30 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"js-sys",
"libc", "libc",
"wasi", "wasi",
"wasm-bindgen",
]
[[package]]
name = "h2"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
] ]
[[package]] [[package]]
@@ -516,6 +733,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac 0.11.1",
"digest 0.9.0",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.8" version = "0.2.8"
@@ -566,6 +793,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2",
"http", "http",
"http-body", "http-body",
"httparse", "httparse",
@@ -579,6 +807,19 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper-rustls"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
dependencies = [
"http",
"hyper",
"rustls",
"tokio",
"tokio-rustls",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@@ -613,15 +854,30 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]]
name = "ipnet"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
[[package]]
name = "js-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -650,7 +906,7 @@ version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
] ]
[[package]] [[package]]
@@ -686,6 +942,16 @@ version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mime_guess"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
dependencies = [
"mime",
"unicase",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.4" version = "0.8.4"
@@ -712,10 +978,20 @@ dependencies = [
"log", "log",
"memchr", "memchr",
"mime", "mime",
"spin", "spin 0.9.4",
"version_check", "version_check",
] ]
[[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]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.15" version = "0.2.15"
@@ -735,12 +1011,57 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "oauth2"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d62c436394991641b970a92e23e8eeb4eb9bca74af4f5badc53bcd568daadbd"
dependencies = [
"base64",
"chrono",
"getrandom",
"http",
"rand",
"reqwest",
"serde",
"serde_json",
"serde_path_to_error",
"sha2 0.10.2",
"thiserror",
"url",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.13.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "opentelemetry"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8"
dependencies = [
"async-trait",
"crossbeam-channel",
"futures-channel",
"futures-executor",
"futures-util",
"js-sys",
"lazy_static",
"percent-encoding",
"pin-project",
"rand",
"thiserror",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@@ -757,7 +1078,7 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"libc", "libc",
"redox_syscall", "redox_syscall",
"smallvec", "smallvec",
@@ -919,6 +1240,81 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "reqwest"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-rustls",
"ipnet",
"js-sys",
"lazy_static",
"log",
"mime",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-rustls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
"winreg",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin 0.5.2",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rustls"
version = "0.20.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9"
dependencies = [
"base64",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.10" version = "1.0.10"
@@ -930,6 +1326,7 @@ name = "scel"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"dotenv",
"scel_api", "scel_api",
"scel_core", "scel_core",
"tokio", "tokio",
@@ -944,8 +1341,14 @@ dependencies = [
"anyhow", "anyhow",
"async-graphql", "async-graphql",
"async-graphql-axum", "async-graphql-axum",
"async-session",
"axum", "axum",
"axum-extra",
"futures", "futures",
"hyper",
"oauth2",
"reqwest",
"scel_core",
"serde", "serde",
"serde_json", "serde_json",
"tokio", "tokio",
@@ -957,6 +1360,17 @@ dependencies = [
[[package]] [[package]]
name = "scel_core" name = "scel_core"
version = "0.1.0" version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"futures",
"lazy_static",
"regex",
"thiserror",
"tokio",
"tracing",
"uuid",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@@ -964,6 +1378,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.139" version = "1.0.139"
@@ -995,6 +1419,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_path_to_error"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7868ad3b8196a8a0aea99a8220b124278ee5320a55e4fde97794b6f85b1a377"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@@ -1013,9 +1446,33 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"digest", "digest 0.10.3",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.9.0",
"opaque-debug",
]
[[package]]
name = "sha2"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.3",
] ]
[[package]] [[package]]
@@ -1058,6 +1515,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.4" version = "0.9.4"
@@ -1076,6 +1539,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.98" version = "1.0.98"
@@ -1099,7 +1568,7 @@ version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"fastrand", "fastrand",
"libc", "libc",
"redox_syscall", "redox_syscall",
@@ -1183,6 +1652,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls",
"tokio",
"webpki",
]
[[package]] [[package]]
name = "tokio-tungstenite" name = "tokio-tungstenite"
version = "0.17.2" version = "0.17.2"
@@ -1207,6 +1687,7 @@ dependencies = [
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
@@ -1247,10 +1728,17 @@ dependencies = [
"http", "http",
"http-body", "http-body",
"http-range-header", "http-range-header",
"httpdate",
"mime",
"mime_guess",
"percent-encoding",
"pin-project-lite", "pin-project-lite",
"tokio",
"tokio-util",
"tower", "tower",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing",
] ]
[[package]] [[package]]
@@ -1271,7 +1759,7 @@ version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
dependencies = [ dependencies = [
"cfg-if", "cfg-if 1.0.0",
"log", "log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
@@ -1299,6 +1787,18 @@ dependencies = [
"valuable", "valuable",
] ]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"futures",
"futures-task",
"pin-project",
"tracing",
]
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.3" version = "0.1.3"
@@ -1365,6 +1865,15 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c"
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.8" version = "0.3.8"
@@ -1386,6 +1895,12 @@ dependencies = [
"tinyvec", "tinyvec",
] ]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "url" name = "url"
version = "2.2.2" version = "2.2.2"
@@ -1396,6 +1911,7 @@ dependencies = [
"idna", "idna",
"matches", "matches",
"percent-encoding", "percent-encoding",
"serde",
] ]
[[package]] [[package]]
@@ -1404,6 +1920,16 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [
"getrandom",
"rand",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"
@@ -1432,6 +1958,101 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
[[package]]
name = "web-sys"
version = "0.3.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
dependencies = [
"webpki",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -1496,3 +2117,12 @@ name = "windows_x86_64_msvc"
version = "0.36.1" version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]

31
Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
FROM node:16-alpine as web_builder
WORKDIR /usr/src/scel/web
COPY src/web/ .
RUN --mount=type=cache,target=/usr/src/scel/web/dist yarn
RUN --mount=type=cache,target=/usr/src/scel/web/dist yarn build
FROM rust:1.60 as builder
WORKDIR /usr/src/scel
COPY . .
RUN --mount=type=cache,target=/usr/src/scel/target cargo build --release
RUN --mount=type=cache,target=/usr/src/scel/target cargo install --path src/cmd/scel
FROM debian:bullseye-slim
# Install YTD
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \
apt-get update && apt-get install -y python3 python3-pip
RUN python3 -m pip install -U yt-dlp
# Copy binary
COPY --from=builder /usr/local/cargo/bin/scel /usr/local/bin/scel
COPY --from=web_builder /usr/src/scel/web/dist /src/web/dist
CMD ["scel"]

View File

@@ -10,6 +10,7 @@ tokio = { version = "1.0", features = ["full"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
anyhow = { version = "1.0.58" } anyhow = { version = "1.0.58" }
dotenv = { version = "*" }
scel_api = { path = "../../lib/scel_api" } scel_api = { path = "../../lib/scel_api" }
scel_core = { path = "../../lib/scel_core" } scel_core = { path = "../../lib/scel_core" }

View File

@@ -1,15 +1,28 @@
use tracing::{info, Level}; use std::sync::Arc;
use tracing_subscriber::FmtSubscriber;
use dotenv::dotenv;
use scel_core::App;
use tracing::info;
use tracing_subscriber::{EnvFilter, FmtSubscriber};
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
dotenv().ok();
let subscriber = FmtSubscriber::builder() let subscriber = FmtSubscriber::builder()
.with_max_level(Level::INFO) .with_env_filter(
EnvFilter::default()
.add_directive("tower_http=debug".parse().unwrap())
.add_directive("scel_api=info".parse().unwrap())
.add_directive("scel=info".parse().unwrap()),
)
.finish(); .finish();
tracing::subscriber::set_global_default(subscriber)?; tracing::subscriber::set_global_default(subscriber)?;
info!("Starting scel"); info!("Starting scel");
scel_api::Server::new().start().await let app = Arc::new(App::new());
scel_api::Server::new(app.clone()).start().await
} }

View File

@@ -7,9 +7,14 @@ edition = "2021"
[dependencies] [dependencies]
axum = { version = "0.5.6" } axum = { version = "0.5.6" }
axum-extra = { version = "0.3.6", features = ["spa"] }
futures = "0.3.21" futures = "0.3.21"
tower-http = {version = "0.3.3", features = ["cors"]} tower-http = { version = "0.3.3", features = ["cors", "trace"] }
async-graphql = { version = "4.0.0" } async-graphql = { version = "4.0.0", features = [
'tracing',
'opentelemetry',
"log",
] }
async-graphql-axum = { version = "4.0.0" } async-graphql-axum = { version = "4.0.0" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.68" serde_json = "1.0.68"
@@ -17,3 +22,12 @@ tokio = { version = "1.0", features = ["full"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3" } tracing-subscriber = { version = "0.3" }
anyhow = { version = "1.0.58" } anyhow = { version = "1.0.58" }
oauth2 = { version = "*" }
async-session = { version = "*" }
reqwest = { version = "*", default-features = false, features = [
"rustls-tls",
"json",
] }
hyper = { version = "*" }
scel_core = { path = "../scel_core" }

View File

@@ -0,0 +1,99 @@
use std::env;
use async_session::{MemoryStore, Session, SessionStore};
use axum::{
extract::Query,
http::HeaderMap,
response::{IntoResponse, Redirect},
Extension,
};
use oauth2::{
basic::BasicClient, reqwest::async_http_client, AuthUrl, AuthorizationCode, ClientId,
ClientSecret, CsrfToken, RedirectUrl, TokenResponse, TokenUrl,
};
use reqwest::header::SET_COOKIE;
use serde::Deserialize;
use crate::{User, COOKIE_NAME};
pub fn oauth_client() -> BasicClient {
let client_id = env::var("GITEA_CLIENT_ID").expect("Missing GITEA_CLIENT_ID");
let client_secret = env::var("GITEA_CLIENT_SECRET").expect("Missing GITEA_CLIENT_SECRET");
let redirect_url = env::var("GITEA_REDIRECT_URL")
.unwrap_or_else(|_| "http://127.0.0.1:3000/auth/authorized".to_string());
let auth_url =
env::var("GITEA_AUTH_URL").unwrap_or_else(|_| "https://git.front.kjuulh.io".to_string());
let token_url =
env::var("GITEA_TOKEN_URL").unwrap_or_else(|_| "https://git.front.kjuulh.io".to_string());
BasicClient::new(
ClientId::new(client_id),
Some(ClientSecret::new(client_secret)),
AuthUrl::new(auth_url).expect("AuthUrl was invalid"),
Some(TokenUrl::new(token_url).expect("Token url was invalid")),
)
.set_redirect_uri(RedirectUrl::new(redirect_url).expect("RedirectUrl was invalid"))
}
pub async fn gitea(Extension(client): Extension<BasicClient>) -> impl IntoResponse {
let (auth_url, _crsf_token) = client.authorize_url(CsrfToken::new_random).url();
Redirect::to(&auth_url.to_string())
}
#[derive(Debug, Deserialize)]
pub struct AuthRequest {
code: String,
state: String,
}
pub async fn authorized(
Query(query): Query<AuthRequest>,
Extension(store): Extension<MemoryStore>,
Extension(oauth_client): Extension<BasicClient>,
) -> impl IntoResponse {
let token = oauth_client
.exchange_code(AuthorizationCode::new(query.code.clone()))
.request_async(async_http_client)
.await
.expect("failed to get http client");
let client = reqwest::Client::new();
let user_data_json = client
.get(get_gitea_user_data_url())
.bearer_auth(token.access_token().secret())
.send()
.await
.expect("Request did not succeed");
// .text()
// .await
// .unwrap();
let user_data: User = user_data_json
.json::<User>()
.await
.expect("could not parse user");
let mut session = Session::new();
session
.insert("user", &user_data)
.expect("could not insert user data");
let cookie = store
.store_session(session)
.await
.expect("could not insert session")
.expect("session was not valid");
let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie);
let mut headers = HeaderMap::new();
headers.insert(SET_COOKIE, cookie.parse().expect("Cookie is not valid"));
(headers, Redirect::to("/"))
}
fn get_gitea_user_data_url() -> String {
env::var("GITEA_USER_INFO_URL").expect("Missing GITEA_USER_INFO_URL")
}

View File

@@ -0,0 +1,4 @@
pub mod mutation;
pub mod query;
pub mod schema;
pub mod subscription;

View File

@@ -0,0 +1,38 @@
use std::sync::Arc;
use async_graphql::{Context, Object, Result, SimpleObject, ID};
use scel_core::{services::Download, App};
pub struct MutationRoot;
#[derive(SimpleObject)]
struct RequestDownloadResponse {
id: ID,
}
#[Object]
impl MutationRoot {
async fn request_download(
&self,
ctx: &Context<'_>,
download_link: String,
) -> Result<RequestDownloadResponse> {
let app = ctx.data_unchecked::<Arc<App>>();
let download = app
.download_service
.clone()
.add_download(Download {
id: None,
link: download_link,
progress: None,
file_name: None,
})
.await
.unwrap();
Ok(RequestDownloadResponse {
id: download.id.unwrap().into(),
})
}
}

View File

@@ -0,0 +1,32 @@
use std::sync::Arc;
use async_graphql::{Context, Object, Result, SimpleObject, ID};
use scel_core::App;
#[derive(SimpleObject, Clone)]
pub struct Download {
pub id: ID,
pub link: String,
pub progress: Option<u32>,
pub file_name: Option<String>,
}
pub struct QueryRoot;
#[Object]
impl QueryRoot {
async fn get_download(&self, ctx: &Context<'_>, id: ID) -> Result<Option<Download>> {
let app = ctx.data_unchecked::<Arc<App>>();
match app.download_service.get_download(id.to_string()).await {
Ok(Some(d)) => Ok(Some(Download {
id: ID::from(d.id.expect("ID could not be found")),
progress: None,
link: d.link,
file_name: None,
})),
Ok(None) => Ok(None),
Err(e) => Err(e.into()),
}
}
}

View File

@@ -1,5 +1,5 @@
use async_graphql::Schema; use async_graphql::Schema;
use crate::{mutation::MutationRoot, query::QueryRoot, subscription::SubscriptionRoot}; use super::{mutation::MutationRoot, query::QueryRoot, subscription::SubscriptionRoot};
pub type ScelSchema = Schema<QueryRoot, MutationRoot, SubscriptionRoot>; pub type ScelSchema = Schema<QueryRoot, MutationRoot, SubscriptionRoot>;

View File

@@ -0,0 +1,49 @@
use std::sync::Arc;
use async_graphql::{
async_stream::stream, futures_util::Stream, Context, Object, Subscription, ID,
};
use scel_core::App;
use super::query::Download;
pub struct SubscriptionRoot;
struct DownloadChanged {
download: Download,
}
#[Object]
impl DownloadChanged {
async fn download(&self) -> Download {
self.download.clone()
}
}
#[Subscription]
impl SubscriptionRoot {
async fn get_download(&self, ctx: &Context<'_>, id: ID) -> impl Stream<Item = DownloadChanged> {
let app = ctx.data_unchecked::<Arc<App>>();
let mut stream = app
.download_service
.subscribe_download(id.to_string())
.await;
stream! {
while stream.changed().await.is_ok() {
let next_download = (*stream.borrow()).clone();
let id = ID::from(next_download.id.unwrap());
yield DownloadChanged {
download: Download {
id: id,
link: next_download.link,
file_name: next_download.file_name,
progress: next_download.progress,
}
}
}
}
}
}

View File

@@ -1,32 +1,46 @@
mod mutation; mod auth;
mod query; mod graphql;
mod schema;
mod subscription;
use std::net::SocketAddr; use std::{io, net::SocketAddr, sync::Arc};
use async_graphql::{ use async_graphql::{
extensions::{Logger, Tracing},
http::{playground_source, GraphQLPlaygroundConfig}, http::{playground_source, GraphQLPlaygroundConfig},
Request, Response, Schema, Request, Response, Schema,
}; };
use async_graphql_axum::GraphQLSubscription; use async_graphql_axum::GraphQLSubscription;
use async_session::{async_trait, MemoryStore, SessionStore};
use auth::{authorized, gitea};
use axum::{ use axum::{
http::Method, extract::{rejection::TypedHeaderRejectionReason, FromRequest, RequestParts},
response::{Html, IntoResponse}, headers,
routing, Extension, Json, Router, http::{header, Method},
response::{Html, IntoResponse, Redirect},
routing::{self, get_service},
Extension, Json, Router, TypedHeader,
};
use graphql::{
mutation::MutationRoot, query::QueryRoot, schema::ScelSchema, subscription::SubscriptionRoot,
};
use hyper::{client::HttpConnector, Body, StatusCode, Uri};
use scel_core::App;
use serde::{Deserialize, Serialize};
use tower_http::{
cors::CorsLayer,
services::ServeDir,
trace::{DefaultMakeSpan, TraceLayer},
}; };
use mutation::MutationRoot;
use query::QueryRoot;
use schema::ScelSchema;
use subscription::SubscriptionRoot;
use tower_http::cors::CorsLayer;
async fn graphql_playground() -> impl IntoResponse { async fn graphql_playground() -> impl IntoResponse {
Html(playground_source( Html(playground_source(
GraphQLPlaygroundConfig::new("/").subscription_endpoint("/ws"), GraphQLPlaygroundConfig::new("/graphql").subscription_endpoint("/ws"),
)) ))
} }
async fn graphql_handler(schema: Extension<ScelSchema>, req: Json<Request>) -> Json<Response> { async fn graphql_handler(
schema: Extension<ScelSchema>,
req: Json<Request>,
_: User,
) -> Json<Response> {
schema.execute(req.0).await.into() schema.execute(req.0).await.into()
} }
@@ -35,27 +49,53 @@ pub struct Server {
addr: SocketAddr, addr: SocketAddr,
} }
impl Server { type Client = hyper::client::Client<HttpConnector, Body>;
pub fn new() -> Server {
let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot).finish();
let cors = vec!["http://localhost:3000" impl Server {
.parse() pub fn new(app: Arc<App>) -> Server {
.expect("Could not parse url")]; let schema = Schema::build(QueryRoot, MutationRoot, SubscriptionRoot)
.extension(Tracing)
.extension(Logger)
.data(app)
.finish();
let cors = vec![
"http://localhost:3000"
.parse()
.expect("Could not parse url"),
"https://scel.front.kjuulh.io"
.parse()
.expect("Could not parse url"),
];
let app = Router::new() let app = Router::new()
.route("/", routing::get(graphql_playground).post(graphql_handler)) .route(
"/graphql",
routing::get(graphql_playground).post(graphql_handler),
)
.route("/ws", GraphQLSubscription::new(schema.clone())) .route("/ws", GraphQLSubscription::new(schema.clone()))
.route("/auth/gitea", routing::get(gitea))
.route("/auth/authorized", routing::get(authorized))
// .merge(axum_extra::routing::SpaRouter::new(
// "/assets",
// "src/web/dist/assets",
// ))
.fallback(get_service(ServeDir::new("./src/web/dist/")).handle_error(handle_error))
.layer(Extension(schema)) .layer(Extension(schema))
.layer(Extension(MemoryStore::new()))
.layer(Extension(Client::new()))
.layer(Extension(auth::oauth_client()))
.layer( .layer(
CorsLayer::new() CorsLayer::new()
.allow_origin(cors) .allow_origin(cors)
.allow_headers([axum::http::header::CONTENT_TYPE]) .allow_headers([axum::http::header::CONTENT_TYPE])
.allow_methods([Method::GET, Method::POST, Method::OPTIONS]), .allow_methods([Method::GET, Method::POST, Method::OPTIONS]),
); )
let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); .layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::default()));
return Server { app, addr }; let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
Server { app, addr }
} }
pub async fn start(self) -> anyhow::Result<()> { pub async fn start(self) -> anyhow::Result<()> {
@@ -70,3 +110,65 @@ impl Server {
} }
} }
} }
#[derive(Debug, Serialize, Deserialize)]
struct User {
#[serde(alias = "sub")]
id: String,
#[serde(alias = "picture")]
avatar: Option<String>,
#[serde(alias = "email")]
email: String,
#[serde(alias = "preferred_username")]
username: String,
}
struct AuthRedirect;
impl IntoResponse for AuthRedirect {
fn into_response(self) -> axum::response::Response {
Redirect::temporary("/auth/gitea").into_response()
}
}
const COOKIE_NAME: &str = "auth";
#[async_trait]
impl<B> FromRequest<B> for User
where
B: Send,
{
type Rejection = AuthRedirect;
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
let Extension(store) = Extension::<MemoryStore>::from_request(req)
.await
.expect("MemoryStore extension is missing");
let cookies = TypedHeader::<headers::Cookie>::from_request(req)
.await
.map_err(|e| match *e.name() {
header::COOKIE => match e.reason() {
TypedHeaderRejectionReason::Missing => AuthRedirect,
_ => panic!("unexpected error getting Cookie header(s): {}", e),
},
_ => panic!("unexpected error getting cookies: {}", e),
})?;
let session_cookie = cookies.get(COOKIE_NAME).ok_or(AuthRedirect)?;
let session = store
.load_session(session_cookie.to_string())
.await
.expect("could not load session")
.ok_or(AuthRedirect)?;
let user = session.get::<User>("user").ok_or(AuthRedirect)?;
Ok(user)
}
}
async fn handle_error(_err: io::Error) -> impl IntoResponse {
(StatusCode::INTERNAL_SERVER_ERROR, "Something went wrong...")
}

View File

@@ -1,15 +0,0 @@
use async_graphql::{Context, Object, Result, SimpleObject, ID};
pub struct MutationRoot;
#[derive(SimpleObject)]
struct RequestDownloadResponse {
id: ID,
}
#[Object]
impl MutationRoot {
async fn request_download(&self, ctx: &Context<'_>) -> Result<RequestDownloadResponse> {
Err("not implemented 123".into())
}
}

View File

@@ -1,10 +0,0 @@
use async_graphql::Object;
pub struct QueryRoot;
#[Object]
impl QueryRoot {
async fn hello_world(&self) -> &str {
"Hello, world!"
}
}

View File

@@ -1,25 +0,0 @@
use async_graphql::{
async_stream::stream, futures_util::Stream, Context, Object, Subscription, ID,
};
pub struct SubscriptionRoot;
struct DownloadChanged {
id: ID,
}
#[Object]
impl DownloadChanged {
async fn id(&self) -> &ID {
&self.id
}
}
#[Subscription]
impl SubscriptionRoot {
async fn get_download(&self, ctx: &Context<'_>) -> impl Stream<Item = DownloadChanged> {
stream! {
yield DownloadChanged {id: "Some-id".into()}
}
}
}

View File

@@ -6,3 +6,12 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
tokio = { version = "1.0", features = ["full"] }
anyhow = { version = "*" }
async-trait = { version = "0.1.56" }
futures = "0.3.21"
tracing = "0.1"
lazy_static = "1.4.0"
regex = { version = "1.5.5" }
thiserror = "1.0.31"
uuid = {version = "1.1.2", features = ["v4", "fast-rng"]}

View File

@@ -1,12 +1,19 @@
#[cfg(test)] use std::sync::Arc;
mod tests {
#[test] use services::InMemoryDownloadService;
fn it_works() {
let result = 2 + 2; pub mod services;
assert_eq!(result, 4); mod youtube;
}
#[allow(dead_code)]
pub struct App {
pub download_service: Arc<InMemoryDownloadService>,
} }
pub fn something() -> String { impl App {
"".into() pub fn new() -> Self {
Self {
download_service: Arc::new(InMemoryDownloadService::new()),
}
}
} }

View File

@@ -0,0 +1,3 @@
pub trait UsersRepo {
// add code here
}

View File

@@ -0,0 +1,135 @@
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use tokio::sync::{watch, Mutex};
use tracing::error;
use uuid::Uuid;
use crate::youtube::{Arg, YoutubeDL};
#[derive(Clone)]
pub struct Download {
pub id: Option<String>,
pub link: String,
pub progress: Option<u32>,
pub file_name: Option<String>,
}
pub struct InMemoryDownloadService {
downloads: Mutex<
HashMap<
String,
(
Arc<Mutex<Download>>,
Arc<Mutex<tokio::sync::watch::Sender<Download>>>,
tokio::sync::watch::Receiver<Download>,
),
>,
>,
}
impl InMemoryDownloadService {
pub fn new() -> Self {
Self {
downloads: Mutex::new(HashMap::new()),
}
}
pub async fn add_download(self: Arc<Self>, download: Download) -> anyhow::Result<Download> {
let mut downloads = self.downloads.lock().await;
let (tx, rx) = watch::channel(download.clone());
let shared_tx = Arc::new(Mutex::new(tx));
let mut d = download.to_owned();
let id = Uuid::new_v4().to_string();
d.id = Some(id.clone());
downloads.insert(
id.clone(),
(
Arc::new(Mutex::new(d.clone())),
shared_tx,
rx,
),
);
let args = vec![
Arg::new("--progress"),
Arg::new("--newline"),
Arg::new_with_args("--output", "%(title).90s.%(ext)s"),
];
let ytd = YoutubeDL::new(
&PathBuf::from("./data/downloads"),
args,
download.link.as_str(),
)?;
tokio::spawn({
let download_service = self.clone();
async move {
if let Err(e) = ytd
.download(
|percentage| {
let ds = download_service.clone();
let id = id.clone();
async move {
let mut download = ds.get_download(id).await.unwrap().unwrap();
download.progress = Some(percentage);
let _ = ds.update_download(download).await;
}
},
|file_name| {
let ds = download_service.clone();
let id = id.clone();
async move {
let mut download = ds.get_download(id).await.unwrap().unwrap();
download.file_name = Some(file_name);
let _ = ds.update_download(download).await;
}
},
)
.await
{
error!("Download failed: {}", e);
} else {
let download = download_service.get_download(id).await.unwrap().unwrap();
let _ = download_service.update_download(download).await;
}
}
});
Ok(d)
}
pub async fn update_download(self: Arc<Self>, download: Download) -> anyhow::Result<()> {
let mut downloads = self.downloads.lock().await;
if let Some(d) = downloads.get_mut(&download.clone().id.unwrap()) {
let mut d_mut = d.0.lock().await;
*d_mut = download.clone();
let _ = d.1.lock().await.send(download);
}
Ok(())
}
pub async fn get_download(&self, id: String) -> anyhow::Result<Option<Download>> {
let downloads = self.downloads.lock().await;
if let Some(d) = downloads.get(&id) {
let download = d.0.lock().await;
Ok(Some(download.clone()))
} else {
Ok(None)
}
}
pub async fn subscribe_download(&self, id: String) -> tokio::sync::watch::Receiver<Download> {
let downloads = self.downloads.lock().await;
let download = downloads.get(&id).unwrap();
download.2.clone()
}
}

View File

@@ -0,0 +1,256 @@
use std::fmt::{Display, Formatter};
use std::fs::{canonicalize, create_dir_all};
use std::future::Future;
use std::num::ParseIntError;
use std::path::{Path, PathBuf};
use std::process::{Output, Stdio};
use lazy_static::lazy_static;
use regex::Regex;
use thiserror::Error;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::process::Command;
#[derive(Error, Debug)]
pub enum YoutubeDLError {
#[error("failed to execute youtube-dl")]
IOError(#[from] std::io::Error),
#[error("failed to convert path")]
UTF8Error(#[from] std::string::FromUtf8Error),
#[error("youtube-dl exited with: {0}")]
Failure(String),
}
type Result<T> = std::result::Result<T, YoutubeDLError>;
const YOUTUBE_DL_COMMAND: &str = "yt-dlp";
#[derive(Clone, Debug)]
pub struct Arg {
arg: String,
input: Option<String>,
}
impl Arg {
pub fn new(argument: &str) -> Self {
Self {
arg: argument.to_string(),
input: None,
}
}
pub fn new_with_args(argument: &str, input: &str) -> Self {
Self {
arg: argument.to_string(),
input: Option::from(input.to_string()),
}
}
}
impl Display for Arg {
fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
match &self.input {
Some(input) => write!(fmt, "{} {}", self.arg, input),
None => write!(fmt, "{}", self.arg),
}
}
}
#[derive(Clone, Debug)]
pub struct YoutubeDL {
path: PathBuf,
links: Vec<String>,
args: Vec<Arg>,
}
#[derive(Clone, Debug)]
pub struct YoutubeDLResult {
path: PathBuf,
output: String,
}
impl YoutubeDLResult {
fn new(path: &PathBuf) -> Self {
Self {
path: path.clone(),
output: String::new(),
}
}
pub fn output_dir(&self) -> &PathBuf {
&self.path
}
}
impl YoutubeDL {
pub fn new_multiple_links(
dl_path: &PathBuf,
args: Vec<Arg>,
links: Vec<String>,
) -> Result<YoutubeDL> {
let path = Path::new(dl_path);
if !path.exists() {
create_dir_all(&path)?;
}
if !path.is_dir() {
return Err(YoutubeDLError::IOError(std::io::Error::new(
std::io::ErrorKind::Other,
"path is not a directory",
)));
}
let path = canonicalize(dl_path)?;
Ok(YoutubeDL { path, links, args })
}
pub fn new(dl_path: &PathBuf, args: Vec<Arg>, link: &str) -> Result<YoutubeDL> {
YoutubeDL::new_multiple_links(dl_path, args, vec![link.to_string()])
}
pub async fn download<F, FutAvailable, FAvailable, Fut>(
&self,
progress_update_fn: F,
file_name_available: FAvailable,
) -> Result<YoutubeDLResult>
where
F: Fn(u32) -> Fut,
FAvailable: Fn(String) -> FutAvailable,
Fut: Future<Output = ()>,
FutAvailable: Future<Output = ()>,
{
let output = self
.spawn_youtube_dl(progress_update_fn, file_name_available)
.await?;
let mut result = YoutubeDLResult::new(&self.path);
if !output.status.success() {
return Err(YoutubeDLError::Failure(String::from_utf8(output.stderr)?));
}
result.output = String::from_utf8(output.stdout)?;
Ok(result)
}
async fn spawn_youtube_dl<F, FutAvailable, FAvailable, Fut>(
&self,
progress_update_fn: F,
file_name_available: FAvailable,
) -> Result<Output>
where
F: Fn(u32) -> Fut,
FAvailable: Fn(String) -> FutAvailable,
Fut: Future<Output = ()>,
FutAvailable: Future<Output = ()>,
{
let mut cmd = Command::new(YOUTUBE_DL_COMMAND);
cmd.current_dir(&self.path)
.env("LC_ALL", "en_US.UTF-8")
.stdout(Stdio::piped())
.stderr(Stdio::piped());
for arg in self.args.iter() {
match &arg.input {
Some(input) => cmd.arg(&arg.arg).arg(input),
None => cmd.arg(&arg.arg),
};
}
for link in self.links.iter() {
cmd.arg(&link);
}
let mut pr = cmd.spawn()?;
{
let stdout = pr.stdout.as_mut().unwrap();
let stdout_reader = BufReader::new(stdout);
let mut stdout_lines = stdout_reader.lines();
let mut have_gotten_file_name = false;
while let Ok(Some(line)) = stdout_lines.next_line().await {
println!("{}", line.clone());
if !have_gotten_file_name {
if let Some(file_name) = parse_file_name(line.clone()) {
file_name_available(file_name).await;
have_gotten_file_name = true
}
}
if let Some(Ok(percentage)) = parse_line(line) {
progress_update_fn(percentage).await;
}
}
}
Ok(pr.wait_with_output().await?)
}
}
fn parse_line(line: String) -> Option<core::result::Result<u32, ParseIntError>> {
lazy_static! {
static ref RE: Regex = Regex::new(r"\[download\]\s+(\d+)").unwrap();
}
let capture: regex::Captures = RE.captures(line.as_str())?;
if capture.len() != 2 {
return None;
}
let str = &capture[1];
Some(str.to_string().parse::<u32>())
}
fn parse_file_name(line: String) -> Option<String> {
lazy_static! {
static ref RE: Regex = Regex::new(r"^\[download\] Destination: (.+)$").unwrap();
}
let capture: regex::Captures = RE.captures(line.as_str())?;
if capture.len() != 2 {
return None;
}
let str = &capture[1];
Some(str.to_string())
}
#[cfg(test)]
mod tests {
use crate::youtube::{parse_file_name, parse_line};
#[test]
fn test_parse_line() {
let percentage = parse_line(
"[download] 95.4% of ~215.85MiB at 9.61MiB/s ETA 00:01 (frag 144/151)".into(),
);
assert_eq!(percentage, Some(Ok(95)))
}
#[test]
fn test_parse_line_get_nothing() {
let nothing = parse_line("[download] Got server HTTP error: The read operation timed out. Retrying (attempt 1 of 10) ...".into());
assert_eq!(nothing, None)
}
#[test]
fn test_parse_file_name() {
let file_name = parse_file_name(
"[download] Destination: 10 Design Patterns Explained in 10 Minutes.mp4".into(),
);
assert_eq!(
file_name,
Some("10 Design Patterns Explained in 10 Minutes.mp4".into())
);
}
#[test]
fn test_parse_file_name_get_nothing() {
let nothing = parse_file_name("[download] No fit: something".into());
assert_eq!(nothing, None)
}
}

1
src/web/.dockerignore Normal file
View File

@@ -0,0 +1 @@
node_modules/

24
src/web/.gitignore vendored Normal file
View File

@@ -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?

13
src/web/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

22
src/web/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "web",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.0.0",
"typescript": "^4.6.4",
"vite": "^3.0.0"
}
}

1
src/web/public/vite.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

41
src/web/src/App.css Normal file
View File

@@ -0,0 +1,41 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.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;
}

34
src/web/src/App.tsx Normal file
View File

@@ -0,0 +1,34 @@
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<div className="App">
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" className="logo" alt="Vite logo" />
</a>
<a href="https://reactjs.org" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</div>
)
}
export default App

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

70
src/web/src/index.css Normal file
View File

@@ -0,0 +1,70 @@
:root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

10
src/web/src/main.tsx Normal file
View File

@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>
)

1
src/web/src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

21
src/web/tsconfig.json Normal file
View File

@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

7
src/web/vite.config.ts Normal file
View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
})

724
src/web/yarn.lock Normal file
View File

@@ -0,0 +1,724 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@ampproject/remapping@^2.1.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
dependencies:
"@jridgewell/gen-mapping" "^0.1.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@babel/code-frame@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
dependencies:
"@babel/highlight" "^7.18.6"
"@babel/compat-data@^7.18.8":
version "7.18.8"
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
"@babel/core@^7.18.6":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
dependencies:
"@ampproject/remapping" "^2.1.0"
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.18.9"
"@babel/helper-compilation-targets" "^7.18.9"
"@babel/helper-module-transforms" "^7.18.9"
"@babel/helpers" "^7.18.9"
"@babel/parser" "^7.18.9"
"@babel/template" "^7.18.6"
"@babel/traverse" "^7.18.9"
"@babel/types" "^7.18.9"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.1"
semver "^6.3.0"
"@babel/generator@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5"
integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==
dependencies:
"@babel/types" "^7.18.9"
"@jridgewell/gen-mapping" "^0.3.2"
jsesc "^2.5.1"
"@babel/helper-annotate-as-pure@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-compilation-targets@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
dependencies:
"@babel/compat-data" "^7.18.8"
"@babel/helper-validator-option" "^7.18.6"
browserslist "^4.20.2"
semver "^6.3.0"
"@babel/helper-environment-visitor@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
"@babel/helper-function-name@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
dependencies:
"@babel/template" "^7.18.6"
"@babel/types" "^7.18.9"
"@babel/helper-hoist-variables@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-imports@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-transforms@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712"
integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
dependencies:
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-module-imports" "^7.18.6"
"@babel/helper-simple-access" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/helper-validator-identifier" "^7.18.6"
"@babel/template" "^7.18.6"
"@babel/traverse" "^7.18.9"
"@babel/types" "^7.18.9"
"@babel/helper-plugin-utils@^7.18.6":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
"@babel/helper-simple-access@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-split-export-declaration@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-validator-identifier@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
"@babel/helper-validator-option@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
"@babel/helpers@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
dependencies:
"@babel/template" "^7.18.6"
"@babel/traverse" "^7.18.9"
"@babel/types" "^7.18.9"
"@babel/highlight@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
dependencies:
"@babel/helper-validator-identifier" "^7.18.6"
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
"@babel/plugin-syntax-jsx@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-react-jsx-development@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5"
integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==
dependencies:
"@babel/plugin-transform-react-jsx" "^7.18.6"
"@babel/plugin-transform-react-jsx-self@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz#3849401bab7ae8ffa1e3e5687c94a753fc75bda7"
integrity sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-react-jsx-source@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz#06e9ae8a14d2bc19ce6e3c447d842032a50598fc"
integrity sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-transform-react-jsx@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz#2721e96d31df96e3b7ad48ff446995d26bc028ff"
integrity sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.18.6"
"@babel/helper-module-imports" "^7.18.6"
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-syntax-jsx" "^7.18.6"
"@babel/types" "^7.18.6"
"@babel/template@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/parser" "^7.18.6"
"@babel/types" "^7.18.6"
"@babel/traverse@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.18.9"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.18.9"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.18.9"
"@babel/types" "^7.18.9"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.18.6", "@babel/types@^7.18.9":
version "7.18.9"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
dependencies:
"@babel/helper-validator-identifier" "^7.18.6"
to-fast-properties "^2.0.0"
"@jridgewell/gen-mapping@^0.1.0":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==
dependencies:
"@jridgewell/set-array" "^1.0.0"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/gen-mapping@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
dependencies:
"@jridgewell/set-array" "^1.0.1"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
"@jridgewell/resolve-uri@^3.0.3":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.14"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
"@jridgewell/trace-mapping@^0.3.9":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@types/prop-types@*":
version "15.7.5"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==
"@types/react-dom@^18.0.6":
version "18.0.6"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.6.tgz#36652900024842b74607a17786b6662dd1e103a1"
integrity sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.15":
version "18.0.15"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe"
integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
"@vitejs/plugin-react@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-2.0.0.tgz#12decd097773a00620e44b780b1d2c00df101449"
integrity sha512-zHkRR+X4zqEPNBbKV2FvWSxK7Q6crjMBVIAYroSU8Nbb4M3E5x4qOiLoqJBHtXgr27kfednXjkwr3lr8jS6Wrw==
dependencies:
"@babel/core" "^7.18.6"
"@babel/plugin-transform-react-jsx" "^7.18.6"
"@babel/plugin-transform-react-jsx-development" "^7.18.6"
"@babel/plugin-transform-react-jsx-self" "^7.18.6"
"@babel/plugin-transform-react-jsx-source" "^7.18.6"
magic-string "^0.26.2"
react-refresh "^0.14.0"
ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
browserslist@^4.20.2:
version "4.21.2"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.2.tgz#59a400757465535954946a400b841ed37e2b4ecf"
integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==
dependencies:
caniuse-lite "^1.0.30001366"
electron-to-chromium "^1.4.188"
node-releases "^2.0.6"
update-browserslist-db "^1.0.4"
caniuse-lite@^1.0.30001366:
version "1.0.30001367"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz#2b97fe472e8fa29c78c5970615d7cd2ee414108a"
integrity sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==
chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
convert-source-map@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
dependencies:
safe-buffer "~5.1.1"
csstype@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
debug@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
electron-to-chromium@^1.4.188:
version "1.4.192"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.192.tgz#fac050058b3e0713b401a1088cc579e14c2ab165"
integrity sha512-8nCXyIQY9An88NXAp+PuPy5h3/w5ZY7Iu2lag65Q0XREprcat5F8gKhoHsBUnQcFuCRnmevpR8yEBYRU3d2HDw==
esbuild-android-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz#9e4682c36dcf6e7b71b73d2a3723a96e0fdc5054"
integrity sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==
esbuild-android-arm64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz#9861b1f7e57d1dd1f23eeef6198561c5f34b51f6"
integrity sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==
esbuild-darwin-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz#fd30a5ebe28704a3a117126c60f98096c067c8d1"
integrity sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==
esbuild-darwin-arm64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz#c04a3a57dad94a972c66a697a68a25aa25947f41"
integrity sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==
esbuild-freebsd-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz#c404dbd66c98451395b1eef0fa38b73030a7be82"
integrity sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==
esbuild-freebsd-arm64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz#b62cec96138ebc5937240ce3e1b97902963ea74a"
integrity sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==
esbuild-linux-32@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz#495b1cc011b8c64d8bbaf65509c1e7135eb9ddbf"
integrity sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==
esbuild-linux-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz#3f28dd8f986e6ff42f38888ee435a9b1fb916a56"
integrity sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==
esbuild-linux-arm64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz#a52e99ae30246566dc5f33e835aa6ca98ef70e33"
integrity sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==
esbuild-linux-arm@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz#7c33d05a64ec540cf7474834adaa57b3167bbe97"
integrity sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==
esbuild-linux-mips64le@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz#ed062bd844b587be649443831eb84ba304685f25"
integrity sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==
esbuild-linux-ppc64le@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz#c0786fb5bddffd90c10a2078181513cbaf077958"
integrity sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==
esbuild-linux-riscv64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz#579b0e7cc6fce4bfc698e991a52503bb616bec49"
integrity sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==
esbuild-linux-s390x@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz#09eb15c753e249a500b4e28d07c5eef7524a9740"
integrity sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==
esbuild-netbsd-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz#f7337cd2bddb7cc9d100d19156f36c9ca117b58d"
integrity sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==
esbuild-openbsd-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz#1f8bdc49f8a44396e73950a3fb6b39828563631d"
integrity sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==
esbuild-sunos-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz#47d042739365b61aa8ca642adb69534a8eef9f7a"
integrity sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==
esbuild-windows-32@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz#79198c88ec9bde163c18a6b430c34eab098ec21a"
integrity sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==
esbuild-windows-64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz#b36b230d18d1ee54008e08814c4799c7806e8c79"
integrity sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==
esbuild-windows-arm64@0.14.49:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz#d83c03ff6436caf3262347cfa7e16b0a8049fae7"
integrity sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==
esbuild@^0.14.47:
version "0.14.49"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.49.tgz#b82834760eba2ddc17b44f05cfcc0aaca2bae492"
integrity sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==
optionalDependencies:
esbuild-android-64 "0.14.49"
esbuild-android-arm64 "0.14.49"
esbuild-darwin-64 "0.14.49"
esbuild-darwin-arm64 "0.14.49"
esbuild-freebsd-64 "0.14.49"
esbuild-freebsd-arm64 "0.14.49"
esbuild-linux-32 "0.14.49"
esbuild-linux-64 "0.14.49"
esbuild-linux-arm "0.14.49"
esbuild-linux-arm64 "0.14.49"
esbuild-linux-mips64le "0.14.49"
esbuild-linux-ppc64le "0.14.49"
esbuild-linux-riscv64 "0.14.49"
esbuild-linux-s390x "0.14.49"
esbuild-netbsd-64 "0.14.49"
esbuild-openbsd-64 "0.14.49"
esbuild-sunos-64 "0.14.49"
esbuild-windows-32 "0.14.49"
esbuild-windows-64 "0.14.49"
esbuild-windows-arm64 "0.14.49"
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
is-core-module@^2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
dependencies:
has "^1.0.3"
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
json5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
magic-string@^0.26.2:
version "0.26.2"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.2.tgz#5331700e4158cd6befda738bb6b0c7b93c0d4432"
integrity sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==
dependencies:
sourcemap-codec "^1.4.8"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
node-releases@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
path-parse@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
postcss@^8.4.14:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
react-dom@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
react-refresh@^0.14.0:
version "0.14.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
dependencies:
loose-envify "^1.1.0"
resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
dependencies:
is-core-module "^2.9.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
rollup@^2.75.6:
version "2.77.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.0.tgz#749eaa5ac09b6baa52acc076bc46613eddfd53f4"
integrity sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==
optionalDependencies:
fsevents "~2.3.2"
safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
dependencies:
loose-envify "^1.1.0"
semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
sourcemap-codec@^1.4.8:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
supports-color@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
to-fast-properties@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
typescript@^4.6.4:
version "4.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
update-browserslist-db@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
dependencies:
escalade "^3.1.1"
picocolors "^1.0.0"
vite@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.2.tgz#2a7b4642c53ae066cf724e7e581d6c1fd24e2c32"
integrity sha512-TAqydxW/w0U5AoL5AsD9DApTvGb2iNbGs3sN4u2VdT1GFkQVUfgUldt+t08TZgi23uIauh1TUOQJALduo9GXqw==
dependencies:
esbuild "^0.14.47"
postcss "^8.4.14"
resolve "^1.22.1"
rollup "^2.75.6"
optionalDependencies:
fsevents "~2.3.2"