diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..1de1efb --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,30 @@ +name: Rust + +on: + push: + tags: + - '**' + +env: + CARGO_TERM_COLOR: always + PROJECT_NAME: ovenauth + +jobs: + release: + name: Build and Release + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: Release Build + run: cargo build --release + - name: Release binary + uses: softprops/action-gh-release@v1 + with: + files: target/release/${{ env.PROJECT_NAME }} diff --git a/.gitignore b/.gitignore index fedaa2b..13c77c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target .env +docker/nginx/certs/ +docker/ove/Server.id \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c109427..dd5f498 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "actix-codec" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13895df506faee81e423febbae3a33b27fca71831b96bb3d60adf16ebcfea952" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" dependencies = [ "bitflags", "bytes", @@ -16,16 +16,15 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.1", ] [[package]] name = "actix-cors" -version = "0.6.0-beta.7" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969ddf0c2fb9508e4fa8246d3d4a33bfd7de7c51ed3538b600318190c25b4787" +checksum = "414360eed71ba2d5435b185ba43ecbe281dfab5df3898286d6b7be8074372c92" dependencies = [ - "actix-service", "actix-utils", "actix-web", "derive_more", @@ -37,9 +36,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.0.0-beta.16" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6294c508c1413346857838356f53f45dbfd257ea31dca19470d9ce78750a7d37" +checksum = "a5885cb81a0d4d0d322864bea1bb6c2a8144626b4fdc625d4c51eba197e7797a" dependencies = [ "actix-codec", "actix-rt", @@ -48,19 +47,18 @@ dependencies = [ "ahash", "base64", "bitflags", - "brotli2", + "brotli", "bytes", "bytestring", "derive_more", "encoding_rs", "flate2", "futures-core", - "futures-task", "h2", "http", "httparse", "httpdate", - "itoa 0.4.8", + "itoa 1.0.1", "language-tags", "local-channel", "log", @@ -68,16 +66,16 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand", - "sha-1", + "sha-1 0.10.0", "smallvec", "zstd", ] [[package]] name = "actix-identity" -version = "0.4.0-beta.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3ef86791ffa5e29771c3d770c62650766b10acf5b3a7bdb28e8522fc2e200d" +checksum = "171fe3ed055b2dd50c61967911d253d47e76e1d4308acfbf99fc7affe5ec42aa" dependencies = [ "actix-service", "actix-utils", @@ -85,7 +83,7 @@ dependencies = [ "futures-util", "serde", "serde_json", - "time 0.2.27", + "time 0.3.5", ] [[package]] @@ -100,9 +98,9 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.5.0-beta.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd9f117b910fbcce6e9f45092ffd4ff017785a346d09e2d4fd049f4e20384f4" +checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" dependencies = [ "bytestring", "firestorm", @@ -114,31 +112,30 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f" +checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" dependencies = [ - "actix-macros", "futures-core", "tokio", ] [[package]] name = "actix-server" -version = "2.0.0-rc.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c9b22794b8af1c2e02434873ef858f2a7db40dbbf861ce77a04cd81ac6b767" +checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" dependencies = [ "actix-rt", "actix-service", "actix-utils", "futures-core", "futures-util", - "log", "mio 0.8.0", "num_cpus", "socket2", "tokio", + "tracing", ] [[package]] @@ -164,9 +161,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.0.0-beta.15" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4609cf57246040316642d4dc4c03d7f3d4a083a892122829dbd9e6ec8db7cd67" +checksum = "f4e5ebffd51d50df56a3ae0de0e59487340ca456f05dd0b90c0a7a6dd6a74d31" dependencies = [ "actix-codec", "actix-http", @@ -179,18 +176,18 @@ dependencies = [ "actix-web-codegen", "ahash", "bytes", + "bytestring", "cfg-if", "cookie", "derive_more", "encoding_rs", "futures-core", "futures-util", - "itoa 0.4.8", + "itoa 1.0.1", "language-tags", "log", "mime", "once_cell", - "paste", "pin-project-lite", "regex", "serde", @@ -204,9 +201,9 @@ dependencies = [ [[package]] name = "actix-web-codegen" -version = "0.5.0-beta.6" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a90b7f6c2fde9a1fe3df4da758c2c3c9d620dfa3eae4da0b6925dc0a13444a" +checksum = "7525bedf54704abb1d469e88d7e7e9226df73778798a69cea5022d53b2ae91bc" dependencies = [ "actix-router", "proc-macro2", @@ -222,29 +219,30 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" -version = "0.3.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ "generic-array", ] [[package]] name = "aes" -version = "0.6.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "aes-soft", - "aesni", + "cfg-if", "cipher", + "cpufeatures", + "opaque-debug", ] [[package]] name = "aes-gcm" -version = "0.8.0" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", @@ -254,26 +252,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", -] - [[package]] name = "ahash" version = "0.7.6" @@ -294,6 +272,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "anyhow" version = "1.0.51" @@ -308,9 +301,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "atoi" @@ -322,16 +315,21 @@ dependencies = [ ] [[package]] -name = "autocfg" -version = "1.0.1" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] [[package]] -name = "base-x" -version = "0.2.8" +name = "autocfg" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" @@ -347,9 +345,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" -version = "0.5.11" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" dependencies = [ "arrayref", "arrayvec", @@ -366,23 +364,33 @@ dependencies = [ ] [[package]] -name = "brotli-sys" -version = "0.3.2" +name = "block-buffer" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "cc", - "libc", + "generic-array", ] [[package]] -name = "brotli2" -version = "0.3.2" +name = "brotli" +version = "3.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" dependencies = [ - "brotli-sys", - "libc", + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] @@ -443,19 +451,13 @@ dependencies = [ [[package]] name = "cipher" -version = "0.2.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" dependencies = [ "generic-array", ] -[[package]] -name = "const_fn" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -470,19 +472,19 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" dependencies = [ "aes-gcm", "base64", "hkdf", - "hmac 0.10.1", + "hmac 0.12.1", "percent-encoding", "rand", - "sha2", + "sha2 0.10.2", "subtle", - "time 0.2.27", + "time 0.3.5", "version_check", ] @@ -495,12 +497,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crc" version = "2.1.0" @@ -556,13 +552,13 @@ dependencies = [ ] [[package]] -name = "crypto-mac" -version = "0.10.1" +name = "crypto-common" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array", - "subtle", + "typenum", ] [[package]] @@ -577,9 +573,9 @@ dependencies = [ [[package]] name = "ctr" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ "cipher", ] @@ -593,7 +589,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn", ] @@ -606,6 +602,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + [[package]] name = "dirs" version = "3.0.2" @@ -626,12 +633,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dotenv" version = "0.15.0" @@ -656,11 +657,24 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "firestorm" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31586bda1b136406162e381a3185a506cdfc1631708dd40cba2f6628d8634499" +checksum = "4d3d6188b8804df28032815ea256b6955c9625c24da7525f387a7af02fbb8f01" [[package]] name = "flate2" @@ -765,9 +779,9 @@ dependencies = [ [[package]] name = "ghash" -version = "0.3.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug", "polyval", @@ -788,7 +802,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.9", "tracing", ] @@ -836,32 +850,30 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.10.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "digest", - "hmac 0.10.1", + "hmac 0.12.1", ] [[package]] name = "hmac" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.10.1", - "digest", + "crypto-mac", + "digest 0.9.0", ] [[package]] name = "hmac" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "crypto-mac 0.11.1", - "digest", + "digest 0.10.3", ] [[package]] @@ -887,6 +899,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "idna" version = "0.2.3" @@ -1022,8 +1040,8 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.9.0", + "digest 0.9.0", "opaque-debug", ] @@ -1161,12 +1179,15 @@ dependencies = [ "anyhow", "chrono", "dotenv", + "env_logger", + "log", "rand", "rust-argon2", "serde", "serde_json", "sqlx", "url", + "uuid", ] [[package]] @@ -1220,11 +1241,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "polyval" -version = "0.4.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cpuid-bool", + "cfg-if", + "cpufeatures", "opaque-debug", "universal-hash", ] @@ -1235,12 +1257,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.34" @@ -1352,9 +1368,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" dependencies = [ "base64", "blake2b_simd", @@ -1362,22 +1378,13 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver", ] [[package]] @@ -1415,27 +1422,12 @@ dependencies = [ "untrusted", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.132" @@ -1486,18 +1478,23 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] [[package]] -name = "sha1" -version = "0.6.0" +name = "sha-1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] [[package]] name = "sha2" @@ -1505,13 +1502,24 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest", + "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", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1608,8 +1616,8 @@ dependencies = [ "rustls", "serde", "serde_json", - "sha-1", - "sha2", + "sha-1 0.9.8", + "sha2 0.9.8", "smallvec", "sqlformat", "sqlx-rt", @@ -1637,7 +1645,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.9.8", "sqlx-core", "sqlx-rt", "syn", @@ -1656,64 +1664,6 @@ dependencies = [ "tokio-rustls", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stringprep" version = "0.1.2" @@ -1741,6 +1691,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -1772,21 +1731,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi", -] - [[package]] name = "time" version = "0.3.5" @@ -1795,30 +1739,14 @@ checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" dependencies = [ "itoa 0.4.8", "libc", + "time-macros", ] [[package]] name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" [[package]] name = "tinyvec" @@ -1889,22 +1817,49 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "80b9fa4360528139bc96100c160b7ae879f5567f49f1782b0b02035b0358ebf3" dependencies = [ "cfg-if", + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee" dependencies = [ "lazy_static", ] @@ -1976,6 +1931,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6d5d669b51467dcf7b2f1a796ce0f955f05f01cafda6c19d6e95f730df29238" +dependencies = [ + "getrandom", + "rand", +] + [[package]] name = "version_check" version = "0.9.3" @@ -2097,6 +2062,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2105,18 +2079,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zstd" -version = "0.9.0+zstd.1.5.0" +version = "0.10.0+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" +checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" +version = "4.1.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" +checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" dependencies = [ "libc", "zstd-sys", @@ -2124,9 +2098,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" +version = "1.6.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index f051003..d38c58a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,18 +6,21 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.0.0-beta.9" -rust-argon2 = "0.8.3" +actix-web = "4.0.1" +rust-argon2 = "1.0.0" anyhow = "1.0.51" -actix-identity = "0.4.0-beta.2" -actix-cors = "0.6.0-beta.2" +actix-identity = "0.4.0" +actix-cors = "0.6.1" rand = "0.8.4" serde = { version = "1.0.132", features = ["derive"] } serde_json = "1.0.64" dotenv = "0.15" chrono = { version = "0.4.19", features = ["serde"] } url = "2.2.2" +env_logger = "0.9.0" +log = "0.4.14" +uuid = { version = "1.1.1", features = ["v4", "fast-rng"] } [dependencies.sqlx] version = "0.5.9" -features = [ "postgres", "runtime-actix-rustls", "offline", "json" ] +features = ["runtime-actix-rustls", "offline", "json", "postgres" ] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1f5c14c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM rust as builder + +WORKDIR ./ovenauth +COPY ./Cargo.toml ./Cargo.toml +COPY ./migrations ./migrations +COPY ./Cargo.lock ./Cargo.lock +COPY ./sqlx-data.json ./sqlx-data.json +COPY ./src ./src +RUN cargo build --release +RUN rm src/*.rs + +FROM debian:buster-slim +COPY --from=builder /ovenauth/target/release/ovenauth ./ovenauth +CMD ["./ovenauth"] \ No newline at end of file diff --git a/build_image b/build_image new file mode 100755 index 0000000..e72f648 --- /dev/null +++ b/build_image @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +sqlx migrate run +cargo sqlx prepare +docker build -t ovenauth . +docker container stop ovenauth +docker container rm ovenauth +docker-compose -f docker/docker-compose.yml up -d ovenauth \ No newline at end of file diff --git a/create_self_signed_cert b/create_self_signed_cert new file mode 100755 index 0000000..36c26a6 --- /dev/null +++ b/create_self_signed_cert @@ -0,0 +1,4 @@ +#!/bin/bash +mkdir -p ./docker/nginx/certs/ +openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./docker/nginx/certs/nginx-selfsigned.key -out ./docker/nginx/certs/nginx-selfsigned.crt +openssl dhparam -out ./docker/nginx/certs/dhparam.pem 2048 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..87e1617 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,59 @@ +services: + webserver: + image: nginx + container_name: nginx + ports: + - 443:443 + volumes: + - "./nginx/nginx.conf:/etc/nginx/nginx.conf:ro" + - "./nginx/site:/data/www:ro" + - "./nginx/certs:/etc/nginx/certs" + - "/tmp/vods/:/mnt/vods/" + networks: + - fluss + ovenauth: + image: ovenauth + container_name: ovenauth + platform: "linux/amd64" + environment: + DATABASE_URL: "postgres://postgres:1234@postgresql:5432/meme" + HOST: "0.0.0.0" + PORT: "8080" + SECRET_CODE: "meme" + ports: + - 13337:8080 + networks: + - fluss + postgres: + image: "postgres:alpine3.15" + container_name: postgresql + environment: + POSTGRES_PASSWORD: "1234" + POSTGRES_DB: "meme" + PGDATA: "/var/lib/postgresql/data/pgdata" + ports: + - 5432:5432 + networks: + - fluss + ove: + image: "airensoft/ovenmediaengine" + container_name: ove + ports: + - 1935:1935 + - 3333:3333 + - 3478:3478 + - 8080-8081:8080-8081 + - 4000-4005:4000-4005 + - 9999:9999 + - 9000:9000 + - 10006-10010:10006-10010 + - 20080:20080 + networks: + - fluss + volumes: + - "./ove/:/opt/ovenmediaengine/bin/origin_conf" + - "/tmp/vods/:/mnt/vods/" + platform: "linux/amd64" +networks: + fluss: + name: fluss diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf new file mode 100644 index 0000000..0cdb772 --- /dev/null +++ b/docker/nginx/nginx.conf @@ -0,0 +1,119 @@ +worker_processes 5; ## Default: 1 +worker_rlimit_nofile 8192; +error_log /dev/stdout info; + +events { + worker_connections 4096; ## Default: 1024 +} + +http { + include mime.types; + index index.html index.htm index.php; + + default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] $status ' + '"$request" $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + sendfile on; + tcp_nopush on; + server_names_hash_bucket_size 128; # this seems to be required for some vhosts + + server { + listen 443 ssl; + ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt; + ssl_certificate_key /etc/nginx/certs/nginx-selfsigned.key; + + root /data/www; + index index.html; + + location / { + try_files $uri /index.html; + } + + location /private/ { + auth_request /url_param_auth; + } + + location /api/vods/ { + auth_request /header_auth; + alias /mnt/vods/default/app/; + autoindex on; + autoindex_format json; + } + + location /ws/ { + auth_request /url_param_auth; + proxy_pass http://ove:3333/app/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } + + location /thumbs/ { + auth_request /url_param_auth; + proxy_pass http://ove:20080/app/; + proxy_set_header Host $host:20080; + proxy_http_version 1.1; + } + + location /api/viewers/ { + auth_request /url_param_auth; + proxy_pass http://ove:8081/v1/stats/current/vhosts/default/apps/app/streams/; + proxy_set_header authorization "Basic TWVlbXF4ZA=="; + } + + location /api/startRecord { + auth_request /header_auth; + proxy_pass http://ove:8081/v1/vhosts/default/apps/app:startRecord; + proxy_set_header authorization "Basic TWVlbXF4ZA=="; + proxy_set_header Host $host:8081; + proxy_http_version 1.1; + } + + location /api/stopRecord { + auth_request /header_auth; + proxy_pass http://ove:8081/v1/vhosts/default/apps/app:stopRecord; + proxy_set_header authorization "Basic TWVlbXF4ZA=="; + proxy_set_header Host $host:8081; + proxy_http_version 1.1; + } + + location /api/recordStatus { + auth_request /header_auth; + proxy_pass http://ove:8081/v1/vhosts/default/apps/app:records; + proxy_set_header authorization "Basic TWVlbXF4ZA=="; + proxy_set_header Host $host:8081; + proxy_http_version 1.1; + } + + location /api/ { + proxy_pass http://ovenauth:8080/; + proxy_set_header Host $host; + } + + location = /url_param_auth { + set $query ''; + if ($request_uri ~* "[^\?]+\?(.*)$") { + set $query $1; + } + proxy_pass http://ovenauth:8080/submitToken?$query; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header Host $host; # MAGIC + } + + location = /header_auth { + set $query ''; + if ($request_uri ~* "[^\?]+\?(.*)$") { + set $query $1; + } + proxy_pass http://ovenauth:8080/submitHeaderToken?$query; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + proxy_set_header Host $host; # MAGIC + } + } +} \ No newline at end of file diff --git a/docker/ove/Server.id b/docker/ove/Server.id new file mode 100644 index 0000000..dfe8c00 --- /dev/null +++ b/docker/ove/Server.id @@ -0,0 +1 @@ +082a52cd-4bc3-4365-8a7b-e4850bb49efe \ No newline at end of file diff --git a/docker/ove/Server.xml b/docker/ove/Server.xml new file mode 100644 index 0000000..bc74379 --- /dev/null +++ b/docker/ove/Server.xml @@ -0,0 +1,168 @@ + + OvenMediaEngine + + origin + + * + false + + stun.l.google.com:19302 + + + + + + + + 8081 + 1 + + + + + + + ${env:OME_RTMP_PROV_PORT:1935} + 1 + + + + + + + 20080 + + + + + ${env:OME_SIGNALLING_PORT:3333} + 1 + + + + + ${env:OME_TCP_RELAY_ADDRESS:*:3478} + true + 1 + ${env:OME_ICE_CANDIDATES:*:10006/udp} + + + + + + + + + * + + + + Meemqxd + + + + + + + + default + + ovenmediaengine.com + + + http://ovenauth:8080/webhook + 1234 + 3000 + + rtmp + + + + + + + + * + + + + + + + + + app + + live + + + default_stream + ${OriginStreamName} + + + + + + png + 1 + 1280 + 720 + + + + + + + + + 1 + 8 + + 30000 + false + false + false + + + + * + + + + /mnt/vods + /${VirtualHost}/${Application}/${Stream}/${StartTime:YYYYMMDDhhmmss}.ts + /${VirtualHost}/${Application}/${Stream}.xml + + + + + + + \ No newline at end of file diff --git a/frontend/.env.development b/frontend/.env.development new file mode 100644 index 0000000..9c1425e --- /dev/null +++ b/frontend/.env.development @@ -0,0 +1,4 @@ +VITE_BASEURL="localhost:8080" +VITE_PROTOCOL="http://" +VITE_APIPATH="" +VITE_PAGE_TITLE="Flussen statt zucken" \ No newline at end of file diff --git a/frontend/.env.localdocker b/frontend/.env.localdocker new file mode 100644 index 0000000..6019226 --- /dev/null +++ b/frontend/.env.localdocker @@ -0,0 +1,4 @@ +VITE_BASEURL="localhost:443" +VITE_PROTOCOL="https://" +VITE_APIPATH="/api" +VITE_PAGE_TITLE="Test page" \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..e605675 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +docker/nginx/site +docker_host/nginx/site \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..377400a --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,33 @@ +## Usage + +Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`. + +This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template. + +```bash +$ npm install # or pnpm install or yarn install +``` +### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs) + +## Available Scripts + +In the project directory, you can run: + +### `npm dev` or `npm start` + +Runs the app in the development mode.
+Open [http://localhost:3000](http://localhost:3000) to view it in the browser. + +The page will reload if you make edits.
+ +### `npm run build` + +Builds the app for production to the `dist` folder.
+It correctly bundles Solid in production mode and optimizes the build for the best performance. + +The build is minified and the filenames include the hashes.
+Your app is ready to be deployed! + +## Deployment + +You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.) diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..96555ba --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + +
+ + + + + diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..4407b2b --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,3658 @@ +{ + "name": "vite-template-solid", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "vite-template-solid", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@felte/solid": "^0.3.0", + "daisyui": "^1.17.1", + "ovenplayer": "^0.10.17", + "solid-app-router": "^0.3.3", + "solid-js": "^1.3.0", + "solid-services": "^2.0.0" + }, + "devDependencies": { + "@types/ovenplayer": "^0.10.0", + "autoprefixer": "^10.4.0", + "postcss": "^8.4.5", + "tailwindcss": "^3.0.7", + "typescript": "^4.5.4", + "vite": "^2.7.3", + "vite-plugin-solid": "^2.1.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz", + "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", + "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", + "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", + "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", + "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz", + "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-transform-typescript": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", + "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.8", + "@babel/types": "^7.16.8", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", + "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@felte/common": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@felte/common/-/common-0.6.0.tgz", + "integrity": "sha512-dLh+heGTGKQzIeUbLcJMEvDks3YTy99FFdUHg8/fxeIFSprUM/b4olK+tIMBrTE30AV2BFYeQHxB8hFpzUafAQ==" + }, + "node_modules/@felte/core": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@felte/core/-/core-0.3.0.tgz", + "integrity": "sha512-v3rOg8wdchnQoMYJCPLelaJmgyG3doibYFqKmoOj7iQlnI738fczEEjDToJfa9UUbYBRDdgfYHXrEtEK7kYIGg==", + "dependencies": { + "@felte/common": "0.6.0" + }, + "funding": { + "url": "https://www.buymeacoffee.com/pablo.abc" + } + }, + "node_modules/@felte/solid": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@felte/solid/-/solid-0.3.0.tgz", + "integrity": "sha512-ZzVBu+aHRugUhpI3MVIVeS75iHkk66grZbfWUEPvbNIC15BDh6uTYxjwW5KlBbu38FLlgPSr1hGN1klPkK0/dg==", + "dependencies": { + "@felte/core": "0.3.0" + }, + "funding": { + "url": "https://www.buymeacoffee.com/pablo.abc" + }, + "peerDependencies": { + "solid-js": "^1.2.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/ovenplayer": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/ovenplayer/-/ovenplayer-0.10.0.tgz", + "integrity": "sha512-aY81oEMk4H1vfXXCq9Vrmjsd2x3lRLcfc49FtaUesLgFXGH/kq/6Tu+Q7tKOgSsQEfTLK6VSLWy2Rq+y0IOtVA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", + "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", + "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions": { + "version": "0.31.9", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.31.9.tgz", + "integrity": "sha512-PY86Hesr0D3HxzKSsg0jk/oxRsFyw9jW9ejR+CSsBHpOCTilrOUDOXct3LevnG+dU5cKfm6D1V7fs2F3TyBf8A==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "7.16.0", + "@babel/plugin-syntax-jsx": "^7.16.5", + "@babel/types": "^7.16.0", + "html-entities": "2.3.2" + } + }, + "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", + "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/babel-preset-solid": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.3.2.tgz", + "integrity": "sha512-NiWGdkWZ6a/3Sfc6JdkzeNi8HkbVLNhHuKPCBvCkZPMABP6VRBoqq/aYydZlESk6EC1PYRdZAYSItb9Is6tnJQ==", + "dev": true, + "dependencies": { + "babel-plugin-jsx-dom-expressions": "^0.31.9" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001299", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz", + "integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/core-js": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.2.tgz", + "integrity": "sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/daisyui": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-1.22.2.tgz", + "integrity": "sha512-uaG7JC2wOEbcZT6mzODlfUjA0XOsCGcmJTda6qhdlYSaPoJDi9u87sfT64Hh8CNA1eeKpCm9xGt2WAWUcwqzIQ==" + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dev": true, + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.45", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.45.tgz", + "integrity": "sha512-czF9eYVuOmlY/vxyMQz2rGlNSjZpxNQYBe1gmQv7al171qOIhgyO9k7D5AKlgeTCSPKk+LHhj5ZyIdmEub9oNg==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz", + "integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "optionalDependencies": { + "esbuild-android-arm64": "0.13.15", + "esbuild-darwin-64": "0.13.15", + "esbuild-darwin-arm64": "0.13.15", + "esbuild-freebsd-64": "0.13.15", + "esbuild-freebsd-arm64": "0.13.15", + "esbuild-linux-32": "0.13.15", + "esbuild-linux-64": "0.13.15", + "esbuild-linux-arm": "0.13.15", + "esbuild-linux-arm64": "0.13.15", + "esbuild-linux-mips64le": "0.13.15", + "esbuild-linux-ppc64le": "0.13.15", + "esbuild-netbsd-64": "0.13.15", + "esbuild-openbsd-64": "0.13.15", + "esbuild-sunos-64": "0.13.15", + "esbuild-windows-32": "0.13.15", + "esbuild-windows-64": "0.13.15", + "esbuild-windows-arm64": "0.13.15" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz", + "integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/esbuild-darwin-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz", + "integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz", + "integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz", + "integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz", + "integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/esbuild-linux-32": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz", + "integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz", + "integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-arm": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz", + "integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz", + "integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz", + "integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz", + "integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz", + "integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ] + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz", + "integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/esbuild-sunos-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz", + "integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ] + }, + "node_modules/esbuild-windows-32": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz", + "integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/esbuild-windows-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz", + "integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz", + "integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-glob": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz", + "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/html-entities": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", + "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/merge-anything": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-4.0.2.tgz", + "integrity": "sha512-YxLHKgX8jN5xfKIxcwVNzQ2HpS0r9eUSqifgGhVARoZEW31Jwu95OQzX7qlFPBPQdCmNBhCYaqJzOcwAKi2Elg==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1", + "ts-toolbelt": "^9.6.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.1.32", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.32.tgz", + "integrity": "sha512-F8mf7R3iT9bvThBoW4tGXhXFHCctyCiUUPrWF8WaTqa3h96d9QybkSeba43XVOOE3oiLfkVDe4bT8MeGmkrTxw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ovenplayer": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/ovenplayer/-/ovenplayer-0.10.17.tgz", + "integrity": "sha512-um6l01FMseU9/Vb8GwiaTHSn1ko/dndAvT7fZ/IWY9vn3oYPG86/OQBMyJ+ItIE64dxrfCgLvNtjpeFtOqFFjQ==", + "dependencies": { + "core-js": "^3.16.3", + "whatwg-fetch": "^3.6.2" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dev": true, + "dependencies": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", + "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.4", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.6" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", + "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", + "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "2.63.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz", + "integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/solid-app-router": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/solid-app-router/-/solid-app-router-0.3.3.tgz", + "integrity": "sha512-JEn0gi6q8Pq9M2Ml3CLeNzenxuBrOrQg4aQyeIZTNjOAeEil/9YiaAJk+US78sIdVcqflTneN5KZgJMIGJ0rFQ==", + "peerDependencies": { + "solid-js": "^1.3.5" + } + }, + "node_modules/solid-js": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.4.tgz", + "integrity": "sha512-nf/cbRzMuhb5UjbRDNfSJPqHKzUxNb9YgCQwijPUbdA3koQ/hWrz/lj0ter3lvThgxinvGPtXofDGy9bsKrXqA==" + }, + "node_modules/solid-refresh": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.4.0.tgz", + "integrity": "sha512-5XCUz845n/sHPzKK2i2G2EeV61tAmzv6SqzqhXcPaYhrgzVy7nKTQaBpKK8InKrriq9Z2JFF/mguIU00t/73xw==", + "dev": true, + "dependencies": { + "@babel/generator": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "peerDependencies": { + "solid-js": "^1.3.0" + } + }, + "node_modules/solid-services": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/solid-services/-/solid-services-2.0.0.tgz", + "integrity": "sha512-fwC7X77xrJaHn61XWoWnEhIFApeSgt3AVw/zB1f/ek5k4UgXHIUuGo/zeePskABTo51sVnPlmnD+u7DoSnIlXQ==", + "dependencies": { + "solid-js": "^1.3.1" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz", + "integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==", + "dev": true, + "dependencies": { + "arg": "^5.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color-name": "^1.1.4", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.8", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.21.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "autoprefixer": "^10.0.2", + "postcss": "^8.0.9" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/vite": { + "version": "2.7.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.7.12.tgz", + "integrity": "sha512-KvPYToRQWhRfBeVkyhkZ5hASuHQkqZUUdUcE3xyYtq5oYEPIJ0h9LWiWTO6v990glmSac2cEPeYeXzpX5Z6qKQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.13.12", + "postcss": "^8.4.5", + "resolve": "^1.20.0", + "rollup": "^2.59.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": ">=12.2.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "less": "*", + "sass": "*", + "stylus": "*" + }, + "peerDependenciesMeta": { + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + } + } + }, + "node_modules/vite-plugin-solid": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.2.2.tgz", + "integrity": "sha512-9Um49U4L7FwZuB1dNRjY+5fhzIBGeYTJuF8eQxx1PZ8R0dnU1vGAswwDexn1OrfoyFDeS9PCBjLtE9VTkbPqYA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", + "babel-preset-solid": "^1.3.0", + "merge-anything": "^4.0.2", + "solid-js": "^1.3.0", + "solid-refresh": "^0.4.0", + "vite": "^2.7.10" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/compat-data": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz", + "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==", + "dev": true + }, + "@babel/core": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", + "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", + "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/helpers": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "dev": true, + "requires": { + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", + "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "dev": true + }, + "@babel/plugin-syntax-jsx": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", + "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", + "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-typescript": "^7.16.7" + } + }, + "@babel/preset-typescript": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz", + "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-option": "^7.16.7", + "@babel/plugin-transform-typescript": "^7.16.7" + } + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", + "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.8", + "@babel/types": "^7.16.8", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", + "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "@felte/common": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@felte/common/-/common-0.6.0.tgz", + "integrity": "sha512-dLh+heGTGKQzIeUbLcJMEvDks3YTy99FFdUHg8/fxeIFSprUM/b4olK+tIMBrTE30AV2BFYeQHxB8hFpzUafAQ==" + }, + "@felte/core": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@felte/core/-/core-0.3.0.tgz", + "integrity": "sha512-v3rOg8wdchnQoMYJCPLelaJmgyG3doibYFqKmoOj7iQlnI738fczEEjDToJfa9UUbYBRDdgfYHXrEtEK7kYIGg==", + "requires": { + "@felte/common": "0.6.0" + } + }, + "@felte/solid": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@felte/solid/-/solid-0.3.0.tgz", + "integrity": "sha512-ZzVBu+aHRugUhpI3MVIVeS75iHkk66grZbfWUEPvbNIC15BDh6uTYxjwW5KlBbu38FLlgPSr1hGN1klPkK0/dg==", + "requires": { + "@felte/core": "0.3.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/ovenplayer": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/ovenplayer/-/ovenplayer-0.10.0.tgz", + "integrity": "sha512-aY81oEMk4H1vfXXCq9Vrmjsd2x3lRLcfc49FtaUesLgFXGH/kq/6Tu+Q7tKOgSsQEfTLK6VSLWy2Rq+y0IOtVA==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", + "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", + "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", + "dev": true, + "requires": { + "browserslist": "^4.19.1", + "caniuse-lite": "^1.0.30001297", + "fraction.js": "^4.1.2", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "babel-plugin-jsx-dom-expressions": { + "version": "0.31.9", + "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.31.9.tgz", + "integrity": "sha512-PY86Hesr0D3HxzKSsg0jk/oxRsFyw9jW9ejR+CSsBHpOCTilrOUDOXct3LevnG+dU5cKfm6D1V7fs2F3TyBf8A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "7.16.0", + "@babel/plugin-syntax-jsx": "^7.16.5", + "@babel/types": "^7.16.0", + "html-entities": "2.3.2" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", + "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + } + } + }, + "babel-preset-solid": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.3.2.tgz", + "integrity": "sha512-NiWGdkWZ6a/3Sfc6JdkzeNi8HkbVLNhHuKPCBvCkZPMABP6VRBoqq/aYydZlESk6EC1PYRdZAYSItb9Is6tnJQ==", + "dev": true, + "requires": { + "babel-plugin-jsx-dom-expressions": "^0.31.9" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", + "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001286", + "electron-to-chromium": "^1.4.17", + "escalade": "^3.1.1", + "node-releases": "^2.0.1", + "picocolors": "^1.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001299", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001299.tgz", + "integrity": "sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "core-js": { + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.2.tgz", + "integrity": "sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw==" + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "daisyui": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-1.22.2.tgz", + "integrity": "sha512-uaG7JC2wOEbcZT6mzODlfUjA0XOsCGcmJTda6qhdlYSaPoJDi9u87sfT64Hh8CNA1eeKpCm9xGt2WAWUcwqzIQ==" + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dev": true, + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.45", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.45.tgz", + "integrity": "sha512-czF9eYVuOmlY/vxyMQz2rGlNSjZpxNQYBe1gmQv7al171qOIhgyO9k7D5AKlgeTCSPKk+LHhj5ZyIdmEub9oNg==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "esbuild": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz", + "integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==", + "dev": true, + "requires": { + "esbuild-android-arm64": "0.13.15", + "esbuild-darwin-64": "0.13.15", + "esbuild-darwin-arm64": "0.13.15", + "esbuild-freebsd-64": "0.13.15", + "esbuild-freebsd-arm64": "0.13.15", + "esbuild-linux-32": "0.13.15", + "esbuild-linux-64": "0.13.15", + "esbuild-linux-arm": "0.13.15", + "esbuild-linux-arm64": "0.13.15", + "esbuild-linux-mips64le": "0.13.15", + "esbuild-linux-ppc64le": "0.13.15", + "esbuild-netbsd-64": "0.13.15", + "esbuild-openbsd-64": "0.13.15", + "esbuild-sunos-64": "0.13.15", + "esbuild-windows-32": "0.13.15", + "esbuild-windows-64": "0.13.15", + "esbuild-windows-arm64": "0.13.15" + } + }, + "esbuild-android-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz", + "integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz", + "integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz", + "integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz", + "integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz", + "integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz", + "integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz", + "integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz", + "integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz", + "integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz", + "integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz", + "integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz", + "integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz", + "integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz", + "integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz", + "integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz", + "integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.13.15", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz", + "integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "fast-glob": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz", + "integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fraction.js": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz", + "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "html-entities": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", + "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "merge-anything": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-4.0.2.tgz", + "integrity": "sha512-YxLHKgX8jN5xfKIxcwVNzQ2HpS0r9eUSqifgGhVARoZEW31Jwu95OQzX7qlFPBPQdCmNBhCYaqJzOcwAKi2Elg==", + "dev": true, + "requires": { + "is-what": "^3.14.1", + "ts-toolbelt": "^9.6.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.1.32", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.32.tgz", + "integrity": "sha512-F8mf7R3iT9bvThBoW4tGXhXFHCctyCiUUPrWF8WaTqa3h96d9QybkSeba43XVOOE3oiLfkVDe4bT8MeGmkrTxw==", + "dev": true + }, + "node-releases": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", + "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "dev": true + }, + "ovenplayer": { + "version": "0.10.17", + "resolved": "https://registry.npmjs.org/ovenplayer/-/ovenplayer-0.10.17.tgz", + "integrity": "sha512-um6l01FMseU9/Vb8GwiaTHSn1ko/dndAvT7fZ/IWY9vn3oYPG86/OQBMyJ+ItIE64dxrfCgLvNtjpeFtOqFFjQ==", + "requires": { + "core-js": "^3.16.3", + "whatwg-fetch": "^3.6.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "postcss": { + "version": "8.4.5", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", + "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "dev": true, + "requires": { + "nanoid": "^3.1.30", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.1" + } + }, + "postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "dev": true, + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.1.tgz", + "integrity": "sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==", + "dev": true, + "requires": { + "lilconfig": "^2.0.4", + "yaml": "^1.10.2" + } + }, + "postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.6" + } + }, + "postcss-selector-parser": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", + "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "resolve": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", + "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "dev": true, + "requires": { + "is-core-module": "^2.8.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rollup": { + "version": "2.63.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz", + "integrity": "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "solid-app-router": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/solid-app-router/-/solid-app-router-0.3.3.tgz", + "integrity": "sha512-JEn0gi6q8Pq9M2Ml3CLeNzenxuBrOrQg4aQyeIZTNjOAeEil/9YiaAJk+US78sIdVcqflTneN5KZgJMIGJ0rFQ==", + "requires": {} + }, + "solid-js": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.4.4.tgz", + "integrity": "sha512-nf/cbRzMuhb5UjbRDNfSJPqHKzUxNb9YgCQwijPUbdA3koQ/hWrz/lj0ter3lvThgxinvGPtXofDGy9bsKrXqA==" + }, + "solid-refresh": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.4.0.tgz", + "integrity": "sha512-5XCUz845n/sHPzKK2i2G2EeV61tAmzv6SqzqhXcPaYhrgzVy7nKTQaBpKK8InKrriq9Z2JFF/mguIU00t/73xw==", + "dev": true, + "requires": { + "@babel/generator": "^7.16.0", + "@babel/helper-module-imports": "^7.16.0", + "@babel/types": "^7.16.0" + } + }, + "solid-services": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/solid-services/-/solid-services-2.0.0.tgz", + "integrity": "sha512-fwC7X77xrJaHn61XWoWnEhIFApeSgt3AVw/zB1f/ek5k4UgXHIUuGo/zeePskABTo51sVnPlmnD+u7DoSnIlXQ==", + "requires": { + "solid-js": "^1.3.1" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", + "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tailwindcss": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.13.tgz", + "integrity": "sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==", + "dev": true, + "requires": { + "arg": "^5.0.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.2", + "color-name": "^1.1.4", + "cosmiconfig": "^7.0.1", + "detective": "^5.2.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "normalize-path": "^3.0.0", + "object-hash": "^2.2.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.0", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.8", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.21.0" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "dev": true + }, + "typescript": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", + "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "vite": { + "version": "2.7.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.7.12.tgz", + "integrity": "sha512-KvPYToRQWhRfBeVkyhkZ5hASuHQkqZUUdUcE3xyYtq5oYEPIJ0h9LWiWTO6v990glmSac2cEPeYeXzpX5Z6qKQ==", + "dev": true, + "requires": { + "esbuild": "^0.13.12", + "fsevents": "~2.3.2", + "postcss": "^8.4.5", + "resolve": "^1.20.0", + "rollup": "^2.59.0" + } + }, + "vite-plugin-solid": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.2.2.tgz", + "integrity": "sha512-9Um49U4L7FwZuB1dNRjY+5fhzIBGeYTJuF8eQxx1PZ8R0dnU1vGAswwDexn1OrfoyFDeS9PCBjLtE9VTkbPqYA==", + "dev": true, + "requires": { + "@babel/core": "^7.16.7", + "@babel/preset-typescript": "^7.16.7", + "babel-preset-solid": "^1.3.0", + "merge-anything": "^4.0.2", + "solid-js": "^1.3.0", + "solid-refresh": "^0.4.0", + "vite": "^2.7.10" + } + }, + "whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..d5d89b2 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,29 @@ +{ + "name": "vite-template-solid", + "version": "0.0.0", + "description": "", + "scripts": { + "dev": "vite", + "build": "vite build", + "dockerbuild": "vite build --mode localdocker --minify false", + "serve": "vite preview" + }, + "license": "MIT", + "devDependencies": { + "autoprefixer": "^10.4.0", + "postcss": "^8.4.5", + "tailwindcss": "^3.0.7", + "typescript": "^4.5.4", + "vite": "^2.7.3", + "vite-plugin-solid": "^2.1.4", + "@types/ovenplayer": "^0.10.0" + }, + "dependencies": { + "@felte/solid": "^0.3.0", + "daisyui": "^1.17.1", + "ovenplayer": "^0.10.17", + "solid-app-router": "^0.3.3", + "solid-js": "^1.3.0", + "solid-services": "^2.0.0" + } +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 0000000..417a35f --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,1350 @@ +lockfileVersion: 5.3 + +specifiers: + autoprefixer: ^10.4.0 + postcss: ^8.4.5 + solid-js: ^1.2.6 + tailwindcss: ^3.0.7 + typescript: ^4.5.4 + vite: ^2.7.3 + vite-plugin-solid: ^2.1.4 + +dependencies: + solid-js: 1.2.6 + +devDependencies: + autoprefixer: 10.4.0_postcss@8.4.5 + postcss: 8.4.5 + tailwindcss: 3.0.7_16a290f6d0e3717bf6d2667234aebd30 + typescript: 4.5.4 + vite: 2.7.3 + vite-plugin-solid: 2.1.4 + +packages: + + /@babel/code-frame/7.16.0: + resolution: {integrity: sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.16.0 + dev: true + + /@babel/compat-data/7.16.4: + resolution: {integrity: sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core/7.16.0: + resolution: {integrity: sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/generator': 7.16.0 + '@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.0 + '@babel/helper-module-transforms': 7.16.0 + '@babel/helpers': 7.16.3 + '@babel/parser': 7.16.4 + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.3 + '@babel/types': 7.16.0 + convert-source-map: 1.8.0 + debug: 4.3.3 + gensync: 1.0.0-beta.2 + json5: 2.2.0 + semver: 6.3.0 + source-map: 0.5.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator/7.16.0: + resolution: {integrity: sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + jsesc: 2.5.2 + source-map: 0.5.7 + dev: true + + /@babel/helper-annotate-as-pure/7.16.0: + resolution: {integrity: sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-compilation-targets/7.16.3_@babel+core@7.16.0: + resolution: {integrity: sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.16.4 + '@babel/core': 7.16.0 + '@babel/helper-validator-option': 7.14.5 + browserslist: 4.18.1 + semver: 6.3.0 + dev: true + + /@babel/helper-create-class-features-plugin/7.16.0_@babel+core@7.16.0: + resolution: {integrity: sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.16.0 + '@babel/helper-annotate-as-pure': 7.16.0 + '@babel/helper-function-name': 7.16.0 + '@babel/helper-member-expression-to-functions': 7.16.0 + '@babel/helper-optimise-call-expression': 7.16.0 + '@babel/helper-replace-supers': 7.16.0 + '@babel/helper-split-export-declaration': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-function-name/7.16.0: + resolution: {integrity: sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-get-function-arity': 7.16.0 + '@babel/template': 7.16.0 + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-get-function-arity/7.16.0: + resolution: {integrity: sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-hoist-variables/7.16.0: + resolution: {integrity: sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-member-expression-to-functions/7.16.0: + resolution: {integrity: sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-module-imports/7.16.0: + resolution: {integrity: sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-module-transforms/7.16.0: + resolution: {integrity: sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-module-imports': 7.16.0 + '@babel/helper-replace-supers': 7.16.0 + '@babel/helper-simple-access': 7.16.0 + '@babel/helper-split-export-declaration': 7.16.0 + '@babel/helper-validator-identifier': 7.15.7 + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.3 + '@babel/types': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-optimise-call-expression/7.16.0: + resolution: {integrity: sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-plugin-utils/7.14.5: + resolution: {integrity: sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-replace-supers/7.16.0: + resolution: {integrity: sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-member-expression-to-functions': 7.16.0 + '@babel/helper-optimise-call-expression': 7.16.0 + '@babel/traverse': 7.16.3 + '@babel/types': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-simple-access/7.16.0: + resolution: {integrity: sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-split-export-declaration/7.16.0: + resolution: {integrity: sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-validator-identifier/7.15.7: + resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option/7.14.5: + resolution: {integrity: sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers/7.16.3: + resolution: {integrity: sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.3 + '@babel/types': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight/7.16.0: + resolution: {integrity: sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.15.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser/7.16.4: + resolution: {integrity: sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==} + engines: {node: '>=6.0.0'} + hasBin: true + dev: true + + /@babel/plugin-syntax-jsx/7.16.0_@babel+core@7.16.0: + resolution: {integrity: sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.0 + '@babel/helper-plugin-utils': 7.14.5 + dev: true + + /@babel/plugin-syntax-typescript/7.16.0_@babel+core@7.16.0: + resolution: {integrity: sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.0 + '@babel/helper-plugin-utils': 7.14.5 + dev: true + + /@babel/plugin-transform-typescript/7.16.1_@babel+core@7.16.0: + resolution: {integrity: sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.0 + '@babel/helper-create-class-features-plugin': 7.16.0_@babel+core@7.16.0 + '@babel/helper-plugin-utils': 7.14.5 + '@babel/plugin-syntax-typescript': 7.16.0_@babel+core@7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-typescript/7.16.0_@babel+core@7.16.0: + resolution: {integrity: sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.0 + '@babel/helper-plugin-utils': 7.14.5 + '@babel/helper-validator-option': 7.14.5 + '@babel/plugin-transform-typescript': 7.16.1_@babel+core@7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/template/7.16.0: + resolution: {integrity: sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/parser': 7.16.4 + '@babel/types': 7.16.0 + dev: true + + /@babel/traverse/7.16.3: + resolution: {integrity: sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/generator': 7.16.0 + '@babel/helper-function-name': 7.16.0 + '@babel/helper-hoist-variables': 7.16.0 + '@babel/helper-split-export-declaration': 7.16.0 + '@babel/parser': 7.16.4 + '@babel/types': 7.16.0 + debug: 4.3.3 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types/7.16.0: + resolution: {integrity: sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.15.7 + to-fast-properties: 2.0.0 + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + dev: true + + /@types/parse-json/4.0.0: + resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: true + + /acorn-node/1.8.2: + resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + xtend: 4.0.2 + dev: true + + /acorn-walk/7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn/7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /anymatch/3.1.2: + resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.0 + dev: true + + /arg/5.0.1: + resolution: {integrity: sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==} + dev: true + + /autoprefixer/10.4.0_postcss@8.4.5: + resolution: {integrity: sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.18.1 + caniuse-lite: 1.0.30001286 + fraction.js: 4.1.2 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.5 + postcss-value-parser: 4.2.0 + dev: true + + /babel-plugin-jsx-dom-expressions/0.30.9_@babel+core@7.16.0: + resolution: {integrity: sha512-FdfgH5IgB5vUCHGQtj65uZ4uiW42VPN2h2KgRwRkINL9/vHRPw0bsGKL+2CaI/LmLKvot9IXhqjSV/HhD0KDWA==} + dependencies: + '@babel/helper-module-imports': 7.16.0 + '@babel/plugin-syntax-jsx': 7.16.0_@babel+core@7.16.0 + '@babel/types': 7.16.0 + html-entities: 2.3.2 + transitivePeerDependencies: + - '@babel/core' + dev: true + + /babel-preset-solid/1.2.6_@babel+core@7.16.0: + resolution: {integrity: sha512-rFl9Sv/llx5fbE1zfx9QlQMsJz3q/nQZds2xq5Atnayop1NOyK9l/ychF2g3DWXoN9MbAR+ZxZqxzsPnOXAV+A==} + dependencies: + babel-plugin-jsx-dom-expressions: 0.30.9_@babel+core@7.16.0 + transitivePeerDependencies: + - '@babel/core' + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /binary-extensions/2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces/3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist/4.18.1: + resolution: {integrity: sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001286 + electron-to-chromium: 1.4.16 + escalade: 3.1.1 + node-releases: 2.0.1 + picocolors: 1.0.0 + dev: true + + /callsites/3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-css/2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /caniuse-lite/1.0.30001286: + resolution: {integrity: sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==} + dev: true + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chokidar/3.5.2: + resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.2 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name/1.1.3: + resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} + dev: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: true + + /convert-source-map/1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /cosmiconfig/7.0.1: + resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.0 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /cssesc/3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /defined/1.0.0: + resolution: {integrity: sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=} + dev: true + + /detective/5.2.0: + resolution: {integrity: sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==} + engines: {node: '>=0.8.0'} + hasBin: true + dependencies: + acorn-node: 1.8.2 + defined: 1.0.0 + minimist: 1.2.5 + dev: true + + /didyoumean/1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /dlv/1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + + /electron-to-chromium/1.4.16: + resolution: {integrity: sha512-BQb7FgYwnu6haWLU63/CdVW+9xhmHls3RCQUFiV4lvw3wimEHTVcUk2hkuZo76QhR8nnDdfZE7evJIZqijwPdA==} + dev: true + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /esbuild-android-arm64/0.13.15: + resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-64/0.13.15: + resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64/0.13.15: + resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-64/0.13.15: + resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-arm64/0.13.15: + resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-32/0.13.15: + resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-64/0.13.15: + resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm/0.13.15: + resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm64/0.13.15: + resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-mips64le/0.13.15: + resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-ppc64le/0.13.15: + resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.13.15: + resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-openbsd-64/0.13.15: + resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-sunos-64/0.13.15: + resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-32/0.13.15: + resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-64/0.13.15: + resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-arm64/0.13.15: + resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild/0.13.15: + resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==} + hasBin: true + requiresBuild: true + optionalDependencies: + esbuild-android-arm64: 0.13.15 + esbuild-darwin-64: 0.13.15 + esbuild-darwin-arm64: 0.13.15 + esbuild-freebsd-64: 0.13.15 + esbuild-freebsd-arm64: 0.13.15 + esbuild-linux-32: 0.13.15 + esbuild-linux-64: 0.13.15 + esbuild-linux-arm: 0.13.15 + esbuild-linux-arm64: 0.13.15 + esbuild-linux-mips64le: 0.13.15 + esbuild-linux-ppc64le: 0.13.15 + esbuild-netbsd-64: 0.13.15 + esbuild-openbsd-64: 0.13.15 + esbuild-sunos-64: 0.13.15 + esbuild-windows-32: 0.13.15 + esbuild-windows-64: 0.13.15 + esbuild-windows-arm64: 0.13.15 + dev: true + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} + engines: {node: '>=0.8.0'} + dev: true + + /fast-glob/3.2.7: + resolution: {integrity: sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==} + engines: {node: '>=8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.4 + dev: true + + /fastq/1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fill-range/7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /fraction.js/4.1.2: + resolution: {integrity: sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==} + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} + dev: true + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /gensync/1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob/7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /globals/11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /has-flag/3.0.0: + resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} + engines: {node: '>=4'} + dev: true + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /html-entities/2.3.2: + resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==} + dev: true + + /import-cwd/3.0.0: + resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} + engines: {node: '>=8'} + dependencies: + import-from: 3.0.0 + dev: true + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-from/3.0.0: + resolution: {integrity: sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=} + dev: true + + /is-binary-path/2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-core-module/2.8.0: + resolution: {integrity: sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==} + dependencies: + has: 1.0.3 + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} + engines: {node: '>=0.10.0'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-what/3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /jsesc/2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-parse-even-better-errors/2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json5/2.2.0: + resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + + /lilconfig/2.0.4: + resolution: {integrity: sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==} + engines: {node: '>=10'} + dev: true + + /lines-and-columns/1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /merge-anything/4.0.2: + resolution: {integrity: sha512-YxLHKgX8jN5xfKIxcwVNzQ2HpS0r9eUSqifgGhVARoZEW31Jwu95OQzX7qlFPBPQdCmNBhCYaqJzOcwAKi2Elg==} + dependencies: + is-what: 3.14.1 + ts-toolbelt: 9.6.0 + dev: true + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch/4.0.4: + resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.0 + dev: true + + /minimatch/3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist/1.2.5: + resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + dev: true + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /nanoid/3.1.30: + resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /node-releases/2.0.1: + resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} + dev: true + + /normalize-path/3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-range/0.1.2: + resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=} + engines: {node: '>=0.10.0'} + dev: true + + /object-hash/2.2.0: + resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} + engines: {node: '>= 6'} + dev: true + + /once/1.4.0: + resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} + dependencies: + wrappy: 1.0.2 + dev: true + + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json/5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.16.0 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} + engines: {node: '>=0.10.0'} + dev: true + + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch/2.3.0: + resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==} + engines: {node: '>=8.6'} + dev: true + + /postcss-js/3.0.3: + resolution: {integrity: sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==} + engines: {node: '>=10.0'} + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.5 + dev: true + + /postcss-load-config/3.1.0: + resolution: {integrity: sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==} + engines: {node: '>= 10'} + peerDependencies: + ts-node: '>=9.0.0' + peerDependenciesMeta: + ts-node: + optional: true + dependencies: + import-cwd: 3.0.0 + lilconfig: 2.0.4 + yaml: 1.10.2 + dev: true + + /postcss-nested/5.0.6_postcss@8.4.5: + resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.5 + postcss-selector-parser: 6.0.7 + dev: true + + /postcss-selector-parser/6.0.7: + resolution: {integrity: sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-value-parser/4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss/8.4.5: + resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.1.30 + picocolors: 1.0.0 + source-map-js: 1.0.1 + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /readdirp/3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.0 + dev: true + + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from/5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve/1.20.0: + resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} + dependencies: + is-core-module: 2.8.0 + path-parse: 1.0.7 + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.0 + dev: true + + /rollup/2.61.1: + resolution: {integrity: sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==} + engines: {node: '>=10.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /solid-js/1.2.6: + resolution: {integrity: sha512-NvPHJ5Vj5f+ZJWIioickrC55seovSkDtm5NzSpnoUk3z4tATv0STpy5iuGNEn51ZORUcwpZzrMAtOCGziXU1XA==} + + /solid-refresh/0.3.2_solid-js@1.2.6: + resolution: {integrity: sha512-7lg3EjenGoxQvGoZnTD3d480wBxbpAiAsyk0dhoGq6hjcaAQ3vnsBGxvXV0LBTzeQcGmIRz1GeSsw/64YyNr+g==} + peerDependencies: + solid-js: ^1.0.0 + dependencies: + '@babel/generator': 7.16.0 + '@babel/helper-module-imports': 7.16.0 + '@babel/types': 7.16.0 + solid-js: 1.2.6 + dev: true + + /source-map-js/1.0.1: + resolution: {integrity: sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.5.7: + resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=} + engines: {node: '>=0.10.0'} + dev: true + + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /tailwindcss/3.0.7_16a290f6d0e3717bf6d2667234aebd30: + resolution: {integrity: sha512-rZdKNHtC64jcQncLoWOuCzj4lQDTAgLtgK3WmQS88tTdpHh9OwLqULTQxI3tw9AMJsqSpCKlmcjW/8CSnni6zQ==} + engines: {node: '>=12.13.0'} + hasBin: true + peerDependencies: + autoprefixer: ^10.0.2 + postcss: ^8.0.9 + dependencies: + arg: 5.0.1 + autoprefixer: 10.4.0_postcss@8.4.5 + chalk: 4.1.2 + chokidar: 3.5.2 + color-name: 1.1.4 + cosmiconfig: 7.0.1 + detective: 5.2.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.2.7 + glob-parent: 6.0.2 + is-glob: 4.0.3 + normalize-path: 3.0.0 + object-hash: 2.2.0 + postcss: 8.4.5 + postcss-js: 3.0.3 + postcss-load-config: 3.1.0 + postcss-nested: 5.0.6_postcss@8.4.5 + postcss-selector-parser: 6.0.7 + postcss-value-parser: 4.2.0 + quick-lru: 5.1.1 + resolve: 1.20.0 + tmp: 0.2.1 + transitivePeerDependencies: + - ts-node + dev: true + + /tmp/0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + + /to-fast-properties/2.0.0: + resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} + engines: {node: '>=4'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /ts-toolbelt/9.6.0: + resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} + dev: true + + /typescript/4.5.4: + resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /util-deprecate/1.0.2: + resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} + dev: true + + /vite-plugin-solid/2.1.4: + resolution: {integrity: sha512-lhEPlDf4PB+KKu5ExaT3zaENqC8shpJ4H74a2R0qbr1MCiFvhE/AooWvIlclpHzBtDK6MmUKv25qSFoSC1EaXQ==} + dependencies: + '@babel/core': 7.16.0 + '@babel/preset-typescript': 7.16.0_@babel+core@7.16.0 + babel-preset-solid: 1.2.6_@babel+core@7.16.0 + merge-anything: 4.0.2 + solid-js: 1.2.6 + solid-refresh: 0.3.2_solid-js@1.2.6 + vite: 2.7.3 + transitivePeerDependencies: + - less + - sass + - stylus + - supports-color + dev: true + + /vite/2.7.3: + resolution: {integrity: sha512-GAY1P+9fLJOju1SRm8+hykVnEXog+E+KXuqqyMBQDriKCUIKzWnPn142yNNhSdf/ixYGYdUa5ce3A8WaEajzGw==} + engines: {node: '>=12.2.0'} + hasBin: true + peerDependencies: + less: '*' + sass: '*' + stylus: '*' + peerDependenciesMeta: + less: + optional: true + sass: + optional: true + stylus: + optional: true + dependencies: + esbuild: 0.13.15 + postcss: 8.4.5 + resolve: 1.20.0 + rollup: 2.61.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} + dev: true + + /xtend/4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + + /yaml/1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/frontend/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..780e9a2 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,22 @@ +import { useRoutes } from "solid-app-router"; +import { Component } from "solid-js"; +// import Login from "./Login"; +import Navbar from "./Navbar"; +import Footer from "./Footer"; + +import { routes } from "./routes"; + +const App: Component = () => { + + const Router = useRoutes(routes); + return ( +
+ + +
+
+ ); +}; + +export default App; diff --git a/frontend/src/Dashboard.tsx b/frontend/src/Dashboard.tsx new file mode 100644 index 0000000..3153973 --- /dev/null +++ b/frontend/src/Dashboard.tsx @@ -0,0 +1,125 @@ +import {Navigate, useSearchParams} from "solid-app-router"; +import {Component, createMemo, createResource, createSignal, Show, Switch, Match, For} from "solid-js"; +import { useService } from "solid-services"; +import Layout from "./Layout"; +import { AuthService } from "./store/AuthService"; +import Title from "./Title"; +import ViewerAccess from "./components/vieweraccess"; +import Recordings from "./components/recordings"; + + +const Dashboard: Component = () => { + + const authService = useService(AuthService); + const [options, { refetch }] = createResource(() => { + return authService().client.common.options(); + }); + + const [searchParams, setSearchParams] = useSearchParams(); + + const [inputtype, setInputtype] = createSignal('password'); + + const toggletype = () => inputtype() === 'password' ? setInputtype('text') : setInputtype('password'); + + const reset = () => + authService().client.common.reset() + .then(refetch); + + const visibleicon = ( + + + + + ); + + const visibleofficon = ( + + + + + ); + + const icon = createMemo(() => { + return inputtype() === 'password' ? visibleicon : visibleofficon; + }); + + let input: HTMLInputElement; + + const copy = () => { + navigator.clipboard.writeText(input.value); + } + + function setEntry(page: string) { + setSearchParams({subpage: page}) + } + + if (searchParams.subpage == undefined) { + setEntry("token") + } + + return ( + <> + + + + + <Layout> + <div class="rounded-lg shadow bg-base-200 drawer drawer-mobile"> + <input id="my-drawer-2" type="checkbox" class="drawer-toggle"/> + <div class="flex flex-col items-center justify-center drawer-content fix-content-height"> + <label for="my-drawer-2" class="mb-4 btn btn-primary drawer-button lg:hidden">open menu</label> + <Show when={authService().user}> + <Switch fallback={<div>Not Found</div>}> + <Match when={searchParams.subpage === "token"}> + <div class="text-xs text-center"> + <div class="form-control relative flex flex-row"> + <input ref={input} + class="input font-mono box-content input-bordered bordered-r-none rounded-r-none w-[38ex]" + type={inputtype()} readOnly value={options()?.token || 'Create Token'}/> + <button type="button" onclick={toggletype} + class="top-0 rounded-none btn btn-primary">{icon()}</button> + <button type="button" onclick={copy} class="top-0 rounded-none btn btn-primary">Copy</button> + <button type="button" onclick={reset} + class="top-0 rounded-l-none btn btn-primary">{options() ? 'reset' : 'create'}</button> + </div> + </div> + </Match> + <Match when={searchParams.subpage === "access"}> + <ViewerAccess></ViewerAccess> + </Match> + + <Match when={searchParams.subpage === "record"}> + <Show when={authService().token}> + <Recordings token={authService().token}></Recordings> + </Show> + </Match> + </Switch> + </Show> + </div> + <div class="drawer-side"> + <label for="my-drawer-2" class="drawer-overlay"></label> + <ul class="menu p-4 overflow-y-auto w-80 bg-base-100 text-base-content"> + <li> + <a classList={{ active: searchParams.subpage === "token" }} onclick={() => setEntry("token")}> + Stream Token + </a> + </li> + <li> + <a classList={{ active: searchParams.subpage === "access" }} onclick={() => setEntry("access")}> + Access + </a> + </li> + <li> + <a classList={{ active: searchParams.subpage === "record" }} onclick={() => setEntry("record")}> + Record + </a> + </li> + </ul> + </div> + </div> + </Layout> + </> + ); +} + +export default Dashboard; diff --git a/frontend/src/Footer.tsx b/frontend/src/Footer.tsx new file mode 100644 index 0000000..37ff790 --- /dev/null +++ b/frontend/src/Footer.tsx @@ -0,0 +1,47 @@ +import { Component, For } from "solid-js"; +import { theme, setTheme } from "./utils/theme"; + +const Footer: Component = () => { + + const themes = [ + 'light', + 'dark', + 'cupcake', + 'bumblebee', + 'emerald', + 'corporate', + 'synthwave', + 'retro', + 'cyberpunk', + 'valentine', + 'halloween', + 'garden', + 'forest', + 'aqua', + 'lofi', + 'pastel', + 'fantasy', + 'wireframe', + 'black', + 'luxury', + 'dracula', + 'cmyk', + ]; + + return ( + <footer class="items-center mt-4 p-4 footer bg-neutral text-neutral-content bottom-0"> + <div class="items-center grid-flow-col"> + <select class="select select-bordered text-base-content w-full max-w-xs" oninput={(e) => setTheme(e.currentTarget.value)}> + <For each={themes}> + {(th) => <option selected={theme() === th} value={th}>{th}</option>} + </For> + </select> + </div> + <div class="grid-flow-col gap-4 md:place-self-center md:justify-self-end"> + <p>{import.meta.env.VITE_PAGE_TITLE}</p> + </div> + </footer> + ); +} + +export default Footer; diff --git a/frontend/src/Home.tsx b/frontend/src/Home.tsx new file mode 100644 index 0000000..970b065 --- /dev/null +++ b/frontend/src/Home.tsx @@ -0,0 +1,45 @@ +import { Link } from "solid-app-router"; +import {Component, createResource, For, onMount, Show} from "solid-js"; +import { useService } from "solid-services"; +import Layout from "./Layout"; +import { AuthService } from "./store/AuthService"; +import Thumbnail from "./Thumbnail"; +import Title from "./Title"; +import ViewCount from "./ViewCount"; + +const Home: Component = () => { + const authService = useService(AuthService); + let t; + + onMount(() => { + authService().loadUsers() + }) + + return <> + <Title value="Home"/> + <Layout> + <div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2 grid-cols-1 gap-4"> + <Show when={authService().loaded()}> + <For each={authService().users}> + {(user) => + <div ref={t} class="aspect-video card shadow-xl card-bordered image-full"> + <Thumbnail hover={t} interval={10000} name={user.username} token={authService().token} username={authService().user.username}></Thumbnail> + <div class="justify-end card-body"> + <h2 class="card-title">{user.username}</h2> + <Show when={authService().loaded()} fallback={"?"}> + <ViewCount interval={10000} name={user.username} user={authService().user.username} token={authService().token}/> + </Show> + <div class="card-actions"> + <Link href={`/${user.username}`} class="btn btn-primary">Watch</Link> + </div> + </div> + </div> + } + </For> + </Show> + </div> + </Layout> + </>; +}; + +export default Home; diff --git a/frontend/src/Layout.tsx b/frontend/src/Layout.tsx new file mode 100644 index 0000000..3eb3a58 --- /dev/null +++ b/frontend/src/Layout.tsx @@ -0,0 +1,11 @@ +import { Component } from "solid-js"; + +const Layout: Component = (props) => { + return ( + <div class="container mx-auto"> + {props.children} + </div> + ); +} + +export default Layout; \ No newline at end of file diff --git a/frontend/src/Login.tsx b/frontend/src/Login.tsx new file mode 100644 index 0000000..a3077e5 --- /dev/null +++ b/frontend/src/Login.tsx @@ -0,0 +1,63 @@ +import { Component, createMemo, createSignal, Show } from "solid-js"; +import { useService } from "solid-services"; +import { AuthService } from "./store/AuthService"; +import { prevent } from "./utils/preventDefault"; +import { useLocation, useNavigate } from "solid-app-router"; +import Layout from "./Layout"; +import Title from "./Title"; + + +const Login: Component = () => { + const [errors, setErrors] = createSignal<Error | Record<string, string[]>>(); + const authService = useService(AuthService); + const location = useLocation<{ redirectTo?: string }>(); + const navigate = useNavigate(); + + createMemo(() => { + if (authService().loggedIn()) { + navigate('/', { replace: true }); + } + }) + + const redirectTo = createMemo(() => { + return location.state?.redirectTo || '/'; + }); + + const submit = (e) => { + const data = new FormData(e.currentTarget); + const body = Object.fromEntries(data) as any; + + authService() + .login(body) + .then(() => { + navigate(redirectTo()); + }) + .catch(setErrors) + } + + return ( + <Layout> + <Title value="Login" /> + <form onSubmit={prevent(submit)}> + <div class="form-control"> + <label class="label"> + <span class="label-text">Username</span> + </label> + <input type="text" name="username" placeholder="Username" class="input input-bordered" /> + </div> + <div class="form-control"> + <label class="label"> + <span class="label-text">Password</span> + </label> + <input type="password" name="password" placeholder="Password" class="input input-bordered" /> + </div> + <input type="submit" class="float-right btn btn-primary" value="Login" /> + </form> + <Show when={errors()}> + {(errors) => <div>{JSON.stringify(errors)}</div>} + </Show> + </Layout> + ); +}; + +export default Login; diff --git a/frontend/src/Navbar.tsx b/frontend/src/Navbar.tsx new file mode 100644 index 0000000..6966f83 --- /dev/null +++ b/frontend/src/Navbar.tsx @@ -0,0 +1,74 @@ +import { NavLink, useNavigate } from "solid-app-router"; +import { Component, Switch, Match, createSignal } from "solid-js"; +import { useService } from "solid-services"; +import { AuthService } from "./store/AuthService"; + + +const Navbar: Component = () => { + + const navigate = useNavigate(); + + const authService = useService(AuthService); + + const logout = async () => { + await authService().logout(); + }; + + const [navbarOpen, setNavbarOpen] = createSignal(false); + + return ( + <nav class="flex items-center justify-between flex-wrap bg-neutral text-neutral-content p-6"> + <div class="flex-none px-2 mx-2" onclick={ () => navigate("/", { replace: true })} + onTouchEnd={ () => navigate("/", { replace: true }) } > + <span class="text-lg font-bold"> + {import.meta.env.VITE_PAGE_TITLE} + </span> + </div> + <div class="flex-1 px-2 mx-2"> + <div class="items-stretch hidden lg:flex"> + <NavLink activeClass="btn-active" end href="/" class="btn btn-ghost btn-sm rounded-btn"> + Home + </NavLink> + </div> + </div> + <div class="block lg:hidden"> + <button data-collapse-toggle="mobile-menu-4" class="flex items-center px-3 py-2 border rounded text-default-200 border-white-400 hover:text-white hover:border-white" onclick={ () => { setNavbarOpen(!navbarOpen());}}> + <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>Menu + + + +
+
+ + 0}> +
+ + {authService().user.username} + +
+
+ +
+
+ +
+ + Login + +
+
+ + Register + +
+
+
+
+
+ + ) +} + +export default Navbar; diff --git a/frontend/src/Player.tsx b/frontend/src/Player.tsx new file mode 100644 index 0000000..04b0478 --- /dev/null +++ b/frontend/src/Player.tsx @@ -0,0 +1,74 @@ +import {Component, createEffect, createSignal, JSX, onCleanup, onMount, splitProps} from "solid-js"; +import OvenPlayer from 'ovenplayer'; + +export interface PlayerProps { + url: string, + autoplay: boolean, + instance: string, + scroll?: boolean, + token: string, + user: string, + name: string +} + +// TODO: make this a directive instead of a component +const Stream: Component> = (props) => { + let ref: HTMLDivElement; + + const [playerProps, divProps] = splitProps(props, ['url', 'autoplay', 'instance', 'scroll']); + + onMount(() => { + const [volume, setVolume] = createSignal(+(localStorage.getItem(`volume_${playerProps.instance}`) || 100)); + + createEffect(() => localStorage.setItem(`volume_${playerProps.instance}`, volume().toString(10))); + + if (playerProps.scroll) { + const doscroll = () => setTimeout(() => ref.scrollIntoView({ + behavior: 'smooth', + block: 'start', + }), 0); + window.addEventListener('resize', doscroll); + doscroll(); + + onCleanup(() => window.removeEventListener('resize', doscroll)); + } + + const url = playerProps.url + "?username=" + props.user + "&token=" + props.token + "&streamname=" + props.name; + + const player = OvenPlayer.create(ref.firstElementChild as HTMLDivElement, { + volume: volume(), + autoStart: playerProps.autoplay ?? false, + webrtcConfig: { + timeoutMaxRetry: 1000000, + connectionTimeout: 5000 + }, + sources: [ + { + type: 'webrtc', + file: url, + } + ] + }); + let timeout: number; + player.once('ready', () => player.play()); + player.on('volumeChanged', n => setVolume(n.volume)); + player.on('stateChanged', s => { + if (['playing', 'loading'].includes(s.prevstate) && s.newstate === 'error') { + timeout = setTimeout(() => player.play(), 1000); + } + }); + + onCleanup(() => { + clearTimeout(timeout); + player.remove(); + }); + }); + + return ( +
+
+
+ ); +}; + +export default Stream; diff --git a/frontend/src/Register.tsx b/frontend/src/Register.tsx new file mode 100644 index 0000000..3965d64 --- /dev/null +++ b/frontend/src/Register.tsx @@ -0,0 +1,77 @@ +import { useLocation, useNavigate } from "solid-app-router"; +import { Component, createMemo, createSignal, Show } from "solid-js"; +import { useService } from "solid-services"; +import Layout from "./Layout"; +import { AuthService } from "./store/AuthService"; +import Title from "./Title"; +import { prevent } from "./utils/preventDefault"; + +const Register: Component = () => { + + const [errors, setErrors] = createSignal(); + + const authService = useService(AuthService); + const navigate = useNavigate(); + const location = useLocation<{ redirectTo?: string }>(); + + createMemo(() => { + if (authService().user != null && authService().user.id != 0) { + navigate('/', { replace: true }); + } + }); + + const redirectTo = createMemo(() => { + return location.state?.redirectTo || '/'; + }); + + const submit = (e) => { + const data = new FormData(e.currentTarget); + const body = Object.fromEntries(data) as any; + + authService() + .register(body) + .then(() => { + navigate(redirectTo()); + }) + .catch(setErrors); + }; + + return ( + + + <form onSubmit={prevent(submit)}> + <div class="form-control"> + <label class="label"> + <span class="label-text">Username</span> + </label> + <input type="text" name="username" placeholder="Username" class="input input-bordered" /> + </div> + <div class="form-control"> + <label class="label"> + <span class="label-text">Password</span> + </label> + <input type="password" name="password" placeholder="Password" class="input input-bordered" /> + </div> + <div class="form-control"> + <label class="label"> + <span class="label-text">Password (Confirmation)</span> + </label> + <input type="password" name="password_confirmation" placeholder="Password" class="input input-bordered" /> + </div> + <div class="form-control"> + <label class="label"> + <span class="label-text">Secret</span> + </label> + <input type="password" name="secret_code" placeholder="Secret Code" class="input input-bordered" /> + </div> + <input type="submit" class="float-right btn btn-primary" value="Register" /> + </form> + <Show when={errors()}> + {(errors) => <div>{JSON.stringify(errors)}</div>} + </Show> + + </Layout> + ); +} + +export default Register; \ No newline at end of file diff --git a/frontend/src/Stream.tsx b/frontend/src/Stream.tsx new file mode 100644 index 0000000..77b216b --- /dev/null +++ b/frontend/src/Stream.tsx @@ -0,0 +1,61 @@ +import { useParams } from "solid-app-router"; +import { Component, createResource, Show} from "solid-js"; +import { useService } from "solid-services"; +import Player from "./Player"; +import {AuthService} from "./store/AuthService"; +import { viewCounter } from "./directives/viewCounter" + +viewCounter + +const Stream: Component = () => { + const params = useParams(); + + const endpoint = import.meta.env.VITE_BASEURL; + + const css = { + 'aspect-ratio': '16 / 9', + 'max-width': '100%', + 'max-height': '100vh', + margin: '0 auto' + }; + + const authService = useService(AuthService); + + authService().refreshToken() + + const loginFallback = <div style={{'text-align': 'center', 'font-size': '5vh'}}>Du musschd di jedzd abr scho no neilogga weischt?</div> + const whitelistFallback = <div style={{'text-align': 'center', 'font-size': '5vh'}}>Du bisch leidr ned whidelischded :(</div> + + + const [allowedResource, { }] = createResource(() => { + return authService().allowedToWatch(params.user).catch(() => false); + }); + + const allowed = () => { + return allowedResource(); + }; + + return ( + <> + <Show when={(authService().token !== 'uninit') || allowed()} fallback={loginFallback}> + <div use:viewCounter={[params.user, authService().user.username, 10000, authService().token]}></div> + <div> + <Show when={!allowedResource.loading && allowed()} fallback={whitelistFallback}> + <Player + style={css} + url={`wss://${endpoint}/ws/${params.user}`} + name={params.user} + instance={params.user} autoplay={true} + scroll={true} + token={authService().token} + user={authService().user.username} + id="player"> + </Player> + </Show> + </div> + </Show> + </> + ); +}; + +export default Stream; diff --git a/frontend/src/Thumbnail.tsx b/frontend/src/Thumbnail.tsx new file mode 100644 index 0000000..dc44c8c --- /dev/null +++ b/frontend/src/Thumbnail.tsx @@ -0,0 +1,77 @@ +import { Component, createEffect, createResource, createSignal, ErrorBoundary, onCleanup, onMount } from "solid-js"; + +const Thumbnail: Component<{ name: string, interval?: number, hover?: HTMLElement, token?: string, username?: string}> = (props) => { + const endpoint = import.meta.env.VITE_PROTOCOL + import.meta.env.VITE_BASEURL; + + const fbpx = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; + + const [intervalDuration, setIntervalDuration] = createSignal(props.interval ?? 10000); + + const fetcher = async (name: string) => { + const res = await fetch(`${endpoint}/thumbs/${name}/thumb.png?t=${Date.now()}&username=${props.username}&token=${props.token}&streamname=${name}`); + if (!res.ok) { + //throw new Error(res.statusText); + } + return URL.createObjectURL(await res.blob()); + } + + const [img, { refetch }] = createResource(() => props.name, fetcher); + + let timeout; + + const update = () => { + refetch(); + timeout = setTimeout(update, intervalDuration()); + } + + let oldintervaldur = intervalDuration(); + + let enter = (e: MouseEvent) => { + oldintervaldur = intervalDuration(); + setIntervalDuration(1000); + } + let leave = (e) => { + setIntervalDuration(oldintervaldur); + } + + onMount(() => { + if (props.hover) { + props.hover.addEventListener('mouseenter', enter); + props.hover.addEventListener('mouseleave', leave); + } + + onCleanup(() => { + if (props.hover) { + props.hover.removeEventListener('mouseenter', enter); + props.hover.removeEventListener('mouseleave', leave); + } + }) + }); + + createEffect(() => { + clearTimeout(timeout); + timeout = setTimeout(async () => { + update(); + }, intervalDuration()); + + onCleanup(() => clearTimeout(timeout)); + }); + + createEffect(() => { + if (img.error) { + setIntervalDuration(60000); + } else { + setIntervalDuration(props.interval ?? 10000); + } + }); + + return ( + <figure class="aspect-video"> + <ErrorBoundary fallback={<img class="bg-gradient-to-tl from-neutral-content to-neutral" src={fbpx} />}> + <img class="bg-gradient-to-tl from-neutral-content to-neutral" src={img()} /> + </ErrorBoundary> + </figure> + ) +} + +export default Thumbnail; diff --git a/frontend/src/Title.tsx b/frontend/src/Title.tsx new file mode 100644 index 0000000..40dc631 --- /dev/null +++ b/frontend/src/Title.tsx @@ -0,0 +1,21 @@ +import { Component, createEffect, onMount, createResource, onCleanup} from "solid-js"; + +interface TitleProps { + interval?: number | boolean; + name: string; + +} + +const Title: Component<TitleProps> = (props) => { + + const title = import.meta.env.VITE_PAGE_TITLE as string; + + createEffect(() => { + document.title = title; + }); + + return <></>; +}; + + +export default Title; diff --git a/frontend/src/ViewCount.tsx b/frontend/src/ViewCount.tsx new file mode 100644 index 0000000..a294798 --- /dev/null +++ b/frontend/src/ViewCount.tsx @@ -0,0 +1,38 @@ +import { Component, createResource, ErrorBoundary, onCleanup, onMount, Show } from "solid-js"; +import { useService } from "solid-services"; +import { StatService } from "./store/StatService"; + +interface ViewCountProps { + name: string; + interval?: number | boolean; + token: string; + user: string; +} + +const ViewCount: Component<ViewCountProps> = (props) => { + const statService = useService(StatService); + + const fetcher = (name: string) => statService().getViewers(name, props.token, props.user, props.name); + + const [vc, { refetch }] = createResource(() => props.name, fetcher); + + const viewers = () => { + let count = vc(); + return count == -404 ? 'Offline' : count == -500 ? '?' : count === 1 ? count + ' Viewer' : count + ' Viewers'; + }; + + onMount(() => { + if (props.interval !== false && typeof props.interval === 'number') { + const interval = setInterval(() => refetch(), props.interval); + onCleanup(() => clearInterval(interval)); + } + }); + + return (<h5> + <Show when={!vc.loading || typeof vc() === 'number'} fallback={'Loading....'}> + {viewers()} + </Show> + </h5>); +} + +export default ViewCount; diff --git a/frontend/src/components/loadingSpinner.tsx b/frontend/src/components/loadingSpinner.tsx new file mode 100644 index 0000000..293c546 --- /dev/null +++ b/frontend/src/components/loadingSpinner.tsx @@ -0,0 +1,11 @@ +import {Component} from "solid-js"; + +const LoadingSpinner: Component = () => { + return ( + <div class="spinner-container"> + <div class="loading-spinner"></div> + </div> + ); +} + +export default LoadingSpinner; \ No newline at end of file diff --git a/frontend/src/components/recordings.tsx b/frontend/src/components/recordings.tsx new file mode 100644 index 0000000..09c8a03 --- /dev/null +++ b/frontend/src/components/recordings.tsx @@ -0,0 +1,94 @@ +import {Component, createResource, createSignal, JSX, onCleanup, Show} from "solid-js"; +import {useService} from "solid-services"; +import {RecordService} from "../store/RecordService"; +import {Recording} from "../types/user.interface"; +import {AuthService} from "../store/AuthService"; +import {PlayerProps} from "../Player"; +import Vod from "./vod"; + +export interface RecordingProps { + token: string, +} + +const Recordings: Component<PlayerProps & JSX.HTMLAttributes<HTMLDivElement>> = (props) => { + + const recordService = useService(RecordService) + const authService = useService(AuthService) + + const [firstRecordStart, setFirstRecordStart] = createSignal("first"); + + const [status, { refetch }] = createResource(() => { + return recordService().status(authService().user.username, authService().token) + .then((result) => { + if (result.length == 0 || (result.length === 1 && result[0].state === "stopped")) { + setFirstRecordStart("stopped"); + } else { + setFirstRecordStart("recording"); + } + return result; + }) + }); + + + const [vods, { }] = createResource(firstRecordStart, () => { + return recordService().vods(authService().user.username, props.token); + }); + + const i = setInterval(() => refetch(), 5000); + onCleanup(() => clearInterval(i)); + + function msToHMS( ms: number ) { + // 1- Convert to seconds: + let seconds = ms / 1000; + // 2- Extract hours: + const hours = parseInt( seconds / 3600 ); // 3,600 seconds in 1 hour + seconds = seconds % 3600; // seconds remaining after extracting hours + // 3- Extract minutes: + const minutes = parseInt( seconds / 60 ); // 60 seconds in 1 minute + // 4- Keep only seconds not extracted to minutes: + seconds = seconds % 60; + return hours+"Stunden "+minutes+"Minuten "+seconds.toFixed(0)+"Sekunden"; + } + + const start = <button class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded" onclick={ () => recordService().startRecord(authService().user.username, authService().token).then(() => refetch())}>Start Recording</button>; + + return ( + <> + + <Show when={status()}> + { () => { + const st: Recording = status()[0]; + return <ul> + <li>State: {st.state}</li> + <Show when={st.totalRecordTime != undefined}> + <li>Recordingtime: {msToHMS(st.totalRecordTime)}</li> + </Show> + <Show when={st.totalRecordBytes != undefined}> + <li>Size: {(st.totalRecordBytes * (8) / (8*1024*1024)).toFixed(2) } MiB </li> + </Show> + </ul>; + }} + </Show> + + <span> + <Show when={status()} fallback={start}> + <button class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded" onclick={ () => recordService().stopRecord(authService().user.username, authService().token).then(() => refetch())}>Stop Recording</button> + </Show> + </span> + <div class="items-center"> + <Show when={vods()}> + <div class="flex justify-center"> + <div class="bg-default-400 shadow-xl rounded-lg"> + <ul class="divide-y divide-default-800"> + {vods().map(vod => <Vod vod={vod}></Vod>)} + </ul> + </div> + </div> + + </Show> + </div> + </> + ); +}; + +export default Recordings; \ No newline at end of file diff --git a/frontend/src/components/vieweraccess.tsx b/frontend/src/components/vieweraccess.tsx new file mode 100644 index 0000000..9a37cdf --- /dev/null +++ b/frontend/src/components/vieweraccess.tsx @@ -0,0 +1,123 @@ +import {Component, createResource, createSignal, For, Show} from "solid-js"; +import { AuthService } from "../store/AuthService"; +import {useService} from "solid-services"; +import LoadingSpinner from "./loadingSpinner"; + +const ViewerAccess: Component = () => { + + const authService = useService(AuthService); + + const [viewers, { refetch }] = createResource(() => { + return authService().allowedUsers(); + }); + + const [loading, setLoading] = createSignal(false) + const [error, setError] = createSignal(false) + + function togglePermission(el, viewer) { + const checked = el.target.checked; + authService().setViewerPermission(viewer.username, checked) + .then(_ => refetch()) + .then(() => setLoading(false)) + .catch(() => { + setLoading(false) + setError(true); + }); + } + + function togglePublic(el) { + const checked = el.target.checked; + authService().setPublic(checked) + .then(_ => authService().authMe()) + .then(() => setLoading(false)) + .then(() => el.target.removeAttribute('disabled')) + .catch(e => { + console.error(e); + setLoading(false); + setError(true); + }) + } + + const errorFallback = <div>Error</div> + + const fallback = <Show when={error() == false} fallback={errorFallback}> + <div style={{'text-align': 'center', 'font-size': '5rem'}} /> + </Show>; + + return ( + <> + <div> + + <Show when={loading()}> + <div class="flex items-center justify-center w-full mb-4"> + <LoadingSpinner></LoadingSpinner> + </div> + </Show> + + <label class="flex items-center cursor-pointer"> + <div class="relative"> + <input type="checkbox" class="sr-only" checked={authService().user.public} + onclick={(el) => { + el.target.setAttribute('disabled', ''); + setLoading(true); + togglePublic(el) + }}/> + + <div class="block bg-gray-600 w-14 h-8 rounded-full"/> + <div class="dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition"/> + </div> + + <div class="ml-3 text-default-700 font-medium"> + Public Stream + </div> + </label> + + <p class="text-lg font-light leading-relaxed mt-6 mb-4 text-default-800"> + Nichts ausgewählt: Für alle zugreifbar + <br /> + Mindestens ein user ausgewählt: Nur für ausgewählte Accounts zugreifbar + </p> + <Show when={(!viewers.loading || typeof viewers() === 'string') && error() == false} fallback={fallback}> + + <div> + <For each={viewers()}> + {(viewer) => + <div> + + <div class="flex items-start justify-start w-full mb-4"> + + <label class="flex items-center cursor-pointer"> + + <div class="relative"> + <input type="checkbox" class="sr-only" checked={viewer.permitted} + onclick={(el) => { + el.target.setAttribute('disabled', ''); + setLoading(true); + togglePermission(el, viewer.user); + }}/> + + <div class="block bg-gray-600 w-14 h-8 rounded-full"></div> + + <div + class="dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition"></div> + </div> + + <div class="ml-3 text-default-700 font-medium"> + {viewer.user.username} + </div> + </label> + + </div> + + </div> + } + </For> + </div> + </Show> + </div> + </> + ); + +} + +export default ViewerAccess; \ No newline at end of file diff --git a/frontend/src/components/vod.tsx b/frontend/src/components/vod.tsx new file mode 100644 index 0000000..f9c2395 --- /dev/null +++ b/frontend/src/components/vod.tsx @@ -0,0 +1,84 @@ +import {Component, createSignal, Show} from "solid-js"; +import LoadingSpinner from "./loadingSpinner"; +import {useService} from "solid-services"; +import {AuthService} from "../store/AuthService"; +import {VodInfo} from "../types/user.interface"; + +export interface VodProps { + vod: VodInfo, +} + +const Vod: Component<VodProps> = (props) => { + + const endpoint = import.meta.env.VITE_PROTOCOL + import.meta.env.VITE_BASEURL + (import.meta.env.VITE_APIPATH || ''); + const [loading, setLoading] = createSignal(false) + const authService = useService(AuthService) + + function formatBytes(bytes, decimals = 2) { + if (!+bytes) return '0 Bytes' + + const k = 1024 + const dm = decimals < 0 ? 0 : decimals + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + + const i = Math.floor(Math.log(bytes) / Math.log(k)) + + return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` + } + + function downloadVOD (vodpath, user, token) { + setLoading(true) + fetch(vodpath, { + method: 'GET', + headers: { + 'Content-Type': 'application/mp2t', + "username": user, + "token": token + }, + }) + .then((response) => { + if (response.status != 200) { + setLoading(false) + throw "error" + } + return response.blob() + }) + .then((blob) => { + // Create blob link to download + const url = window.URL.createObjectURL( + new Blob([blob]), + ); + const link = document.createElement('a'); + link.href = url; + link.setAttribute( + 'download', + `${vodpath.substring(vodpath.lastIndexOf('/')+1)}` + ); + + // Append to html link element page + document.body.appendChild(link); + + // Start download + link.click(); + setLoading(false) + + // Clean up and remove the link + link.parentNode.removeChild(link); + }); + } + + return ( + <div style={{ padding: '1rem', display: 'flex', "align-items": 'center'}}> + <Show when={loading()}> + <LoadingSpinner></LoadingSpinner> + </Show> + <li onclick={() =>downloadVOD(`${endpoint}/vods/${authService().user.username}/${props.vod.name}`, authService().user.username, authService().token)} class="hover:bg-default-50 cursor-pointer" style={{ "padding-left" : "8px" }}> + {props.vod.name} - ({formatBytes(props.vod.size)}) + <Show when={loading()}> + </Show> + </li> + </div> + ); +} + +export default Vod; \ No newline at end of file diff --git a/frontend/src/directives/viewCounter.tsx b/frontend/src/directives/viewCounter.tsx new file mode 100644 index 0000000..6b0a77d --- /dev/null +++ b/frontend/src/directives/viewCounter.tsx @@ -0,0 +1,30 @@ +import { createResource, createEffect, onCleanup } from "solid-js"; +import { useService } from "solid-services"; +import { StatService } from "../store/StatService"; +import { AuthService } from "../store/AuthService"; + +export function viewCounter(el, value) { + const [user, loggedInUser, interval, token] = value(); + + const statService = useService(StatService); + + const fetcher = (name: string) => statService().getViewers(name, token, loggedInUser); + + const [vc, { refetch }] = createResource(() => user, fetcher); + + const getViewCount = () => { + let count = vc(); + return count == -404 ? 'Offline' : count == -500 ? '?' : count ; + }; + + createEffect( () => { + let vc = getViewCount(); + document.title = (typeof vc === 'number' ? " 👁" + vc : " Offline") + " - " + user; + }) + + if (interval !== false && typeof interval === 'number') { + const i = setInterval(() => refetch(), interval); + onCleanup(() => clearInterval(i)); + } + +}; diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts new file mode 100644 index 0000000..1ab1d10 --- /dev/null +++ b/frontend/src/env.d.ts @@ -0,0 +1,11 @@ +/// <reference types="vite/client" /> + +interface ImportMetaEnv { + readonly VITE_BASEURL: string; + readonly VITE_PROTOCOL: string; + readonly VITE_APIPATH: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} \ No newline at end of file diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..ba19f23 --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,36 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* Toggle A */ +input:checked ~ .dot { + transform: translateX(100%); + background-color: #48bb78; +} + +/* Toggle B */ +input:checked ~ .dot { + transform: translateX(100%); + background-color: #48bb78; +} + +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +.loading-spinner { + width: 20px; + height: 20px; + border: 2px solid #f3f3f3; /* Light grey */ + border-top: 2px solid #383636; /* Black */ + border-radius: 50%; + animation: spinner 1.5s linear infinite; +} + +.fix-content-height { + max-height: fit-content !important +} diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx new file mode 100644 index 0000000..c53f99d --- /dev/null +++ b/frontend/src/index.tsx @@ -0,0 +1,25 @@ +import "./index.css"; +import { render } from "solid-js/web"; +import { Router } from 'solid-app-router'; + +import App from "./App"; +import { ServiceRegistry } from "solid-services"; + +declare module "solid-js" { + namespace JSX { + interface Directives { + viewCounter: [String, number]; + } + } + } + +render( + () => ( + <ServiceRegistry> + <Router> + <App /> + </Router> + </ServiceRegistry> + ), + document.getElementById("root") +); diff --git a/frontend/src/routes.ts b/frontend/src/routes.ts new file mode 100644 index 0000000..e896692 --- /dev/null +++ b/frontend/src/routes.ts @@ -0,0 +1,23 @@ +import { lazy } from 'solid-js'; +export const routes = [ + { + path: "/:user", + component: lazy(() => import("./Stream")), + }, + { + path: '**', + component: lazy(() => import("./Home")), + }, + { + path: '/login', + component: lazy(() => import("./Login")), + }, + { + path: '/register', + component: lazy(() => import("./Register")), + }, + { + path: '/dashboard', + component: lazy(() => import("./Dashboard")), + } +]; diff --git a/frontend/src/store/AuthService.ts b/frontend/src/store/AuthService.ts new file mode 100644 index 0000000..9292662 --- /dev/null +++ b/frontend/src/store/AuthService.ts @@ -0,0 +1,118 @@ +import {createSignal} from 'solid-js'; +import {IUser, UserPermission} from '../types/user.interface'; +import {ovenAuthClient} from './api'; + +let UNINIT = "uninit"; + +export function AuthService() { + const [getUser, setUser] = createSignal<IUser>(); + const [users, setUsers] = createSignal([]); + const [token, setToken] = createSignal(UNINIT); + const endpoint = import.meta.env.VITE_PROTOCOL + import.meta.env.VITE_BASEURL + (import.meta.env.VITE_APIPATH || ''); + const client = ovenAuthClient(endpoint); + + const guest : IUser = { + id: 0, + username: "guest", + hidden: true, + public: true + } + + function authMe() { + return client.auth.me().then(setUser).catch(() => setUser(() => guest)) + } + + function refreshToken() { + setToken(UNINIT); + return client.auth.refreshToken().then(setToken).catch(() => setToken("guest_token")) + } + + authMe().then(() => refreshToken()) + loadUsers(); + + function loadUsers() { + client.common.users().then(setUsers).catch(() => setUsers([])); + } + + return { + + loaded() { + return getUser() && token() !== UNINIT + }, + + loggedIn() { + return getUser() && getUser().id != 0 + }, + + refreshToken() { + refreshToken(); + }, + + authMe() { + authMe(); + }, + + loadUsers() { + loadUsers(); + }, + + get user() { + return getUser(); + }, + + setUser(user) { + setUser(user); + }, + + get users() { + return users(); + }, + + get client() { + return client; + }, + + async login(creds): Promise<IUser> { + const user = await client.auth.login(creds); + setUser(user); + refreshToken(); + return user; + }, + + async logout(): Promise<void> { + await client.auth.logout(); + setUser(guest); + setToken("guest_token"); + }, + + async register(creds): Promise<IUser> { + const user = await client.auth.register(creds); + setUser(user); + return user; + }, + + async allowedUsers(): Promise<Array<UserPermission>> { + const viewers = await client.auth.allowedViewers(); + const all = await client.common.users(); + return all.map(u => { + return { user: u, permitted: viewers.filter(us => us.id === u.id).length > 0 } + }); + }, + + async setViewerPermission(user: string, allowed: boolean): Promise<void> { + return await client.auth.setViewerPermission(user, allowed); + }, + + async allowedToWatch(stream: string): Promise<boolean> { + return await client.auth.allowedToWatch(stream); + }, + + async setPublic(isPublic: boolean): Promise<void> { + return await client.auth.setPublic(isPublic) + }, + + get token() { + return token(); + }, + } +} diff --git a/frontend/src/store/RecordService.ts b/frontend/src/store/RecordService.ts new file mode 100644 index 0000000..ee9ed7c --- /dev/null +++ b/frontend/src/store/RecordService.ts @@ -0,0 +1,22 @@ +import { ovenAuthClient } from './api'; +import {Recording, VodInfo} from "../types/user.interface"; + +export function RecordService() { + const endpoint = import.meta.env.VITE_PROTOCOL + import.meta.env.VITE_BASEURL + (import.meta.env.VITE_APIPATH || ''); + const client = ovenAuthClient(endpoint); + + return { + startRecord(stream: string, token: string): Promise<void> { + return client.record.startRecord(stream, token); + }, + stopRecord(stream: string, token: string): Promise<void> { + return client.record.stopRecord(stream, token); + }, + status(stream: string, token: string): Promise<Recording[]> { + return client.record.status(stream, token); + }, + vods(stream: string, token: string): Promise<VodInfo[]> { + return client.record.getVods(stream, token); + } + } +} diff --git a/frontend/src/store/StatService.ts b/frontend/src/store/StatService.ts new file mode 100644 index 0000000..d274ff1 --- /dev/null +++ b/frontend/src/store/StatService.ts @@ -0,0 +1,12 @@ +import { ovenAuthClient } from './api'; + +export function StatService(user: string) { + const endpoint = import.meta.env.VITE_PROTOCOL + import.meta.env.VITE_BASEURL + (import.meta.env.VITE_APIPATH || ''); + const client = ovenAuthClient(endpoint); + + return { + getViewers(user: string, token: string, loggedInUser: string): Promise<number> { + return client.stats.viewerCount(user, token, loggedInUser); + } + } +} diff --git a/frontend/src/store/api.ts b/frontend/src/store/api.ts new file mode 100644 index 0000000..2d53b30 --- /dev/null +++ b/frontend/src/store/api.ts @@ -0,0 +1,172 @@ +import {IStreamOption, IUser, Recording, VodInfo} from "../types/user.interface"; +import stream from "../Stream"; + +function httpClient(endpoint: string, request: typeof fetch) { + // let auth = ""; + + async function makeRequest( + method: 'GET' | 'POST' | 'PUT' | 'DELETE', + url: string, + body?: any, + key?: string, + username?: string, + token?: string + ) { + const usrname = username ? { username: `${username}` } : {}; + const tken = token ? { token: `${token}` } : {}; + + const opts: RequestInit = { + method, + body: body ? JSON.stringify(body) : null, + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + credentials: 'same-origin', + ...usrname, + ...tken + }, + }; + + const cleanURL = endpoint + url.replace(/\?$/, ''); + + const response = await request(cleanURL, opts); + const json = await response.json(); + if (response.status >= 400 || "errors" in json) { + throw json.errors || new Error(response.statusText); + } + + return key ? json[key] : json; + } + + return { + get(url: string, params: Record<string, string | number> = {}, username?: string, token?: string) { + return (key = "") => + makeRequest( + 'GET', + `${url}?${new URLSearchParams(params as any)}`, + undefined, + key, + username, + token + ); + }, + delete(url: string, params: Record<string, string | number> = {}) { + return (key = "") => + makeRequest( + 'DELETE', + `${url}?${new URLSearchParams(params as any)}`, + undefined, + key + ); + }, + post(url: string, body: Record<string, unknown> = {}, username?: string, token?: string) { + return (key = "") => makeRequest('POST', url, body, key, username, token); + }, + put(url: string, body: Record<string, unknown> = {}) { + return (key = "") => makeRequest('PUT', url, body, key); + }, + }; +} + +export function ovenAuthClient(endpoint: string, request = fetch) { + const client = httpClient(endpoint, request); + + return { + stats: { + viewerCount(user: string, token: string, loggedInUser: string): Promise<number> { + const url = '/viewers/' + user + "?username=" + loggedInUser + "&token=" + token + "&streamname=" + user; + return client.get(url)('response').then(response => { + return response.totalConnections + }).catch(e => { + if (e.toString() === "Error: Not Found") { + return -404; + } else { + return -500; + } + }); + } + }, + common: { + users(): Promise<IUser[]> { + return client.get('/users')('users'); + }, + allowedUsers(): Promise<IUser[]> { + return client.get('/allowedViewers')('users'); + }, + options(): Promise<IStreamOption> { + return client.get('/options')('options'); + }, + reset(): Promise<void> { + return client.post('/reset')(); + } + }, + + auth: { + login(user: { username: string, password: string }): Promise<IUser> { + return client.post('/login', { user })('user'); + }, + + register(user: { username: string, password: string, password_confirmation: string, secret_code: string }): Promise<IUser> { + return client.post('/register', { user })('user'); + }, + + me(): Promise<IUser> { + return client.get('/user')('user'); + }, + + logout(): Promise<void> { + return client.post('/logout')('user'); + }, + refreshToken(): Promise<string> { + return client.put('/generateToken')("token").catch(_ => "guest_token") + }, + allowedViewers(): Promise<IUser[]> { + return client.get('/allowedViewers')('users').catch(_ => []); + }, + setViewerPermission(user: string, allowed: boolean): Promise<void> { + return client.get(`/setViewerPermission?username=${user}&allowed=${allowed}`)("ok"); + }, + allowedToWatch(stream: string): Promise<boolean> { + return client.get(`/allowedToWatch?stream=${stream}`)("whitelisted"); + }, + setPublic(state: boolean): Promise<void> { + return client.get(`/setPublic?is_public=${state}`)("ok") + } + + }, + + record: { + + startRecord(streamname: string, token: string): Promise<void> { + const body = { + "id": streamname, + "stream": { + "name": streamname, + }, + "schedule" : "0 0 */1", + "segmentationRule" : "continuity" + } + return client.post(`/startRecord`, body, streamname, token )(''); + }, + + stopRecord(streamname: string, token: string): Promise<void> { + const body = { + "id": streamname + } + return client.post(`/stopRecord`, body, streamname, token )(''); + }, + + status(streamname: string, token: string): Promise<Recording[]> { + const body = { + "id": streamname + } + return client.post(`/recordStatus`, body, streamname, token )("response").catch(e => ""); + }, + + getVods(streamname: string, token: string): Promise<VodInfo[]> { + return client.get(`/vods/${streamname}/`, {}, streamname, token)("").catch(e => []); + } + + } + } +} diff --git a/frontend/src/types/user.interface.ts b/frontend/src/types/user.interface.ts new file mode 100644 index 0000000..611e7d5 --- /dev/null +++ b/frontend/src/types/user.interface.ts @@ -0,0 +1,47 @@ +export interface IUser { + id: number; + username: string; + hidden: boolean; + public: boolean; +} + +export interface UserPermission { + user: IUser, + permitted: boolean +} + +export interface IStreamOption { + token: string; + user_id: number; + name: string; +} + +export interface Recording { + app: string, + createdTime: string, + finishTime: string, + id: string, + outputFilePath?: string, + outputInfoPath?: string, + schedule: string, + segmentationRule: string, + sequence?: number, + startTime?: string, + state: string, + stream: Stream, + totalRecordBytes?: number, + totalRecordTime?: number, + vhost: string +} + +export interface Stream { + name: string, + tracks: string[] +} + +export interface VodInfo { + name: string, + type: string, + mtime: string, + size: number +} diff --git a/frontend/src/utils/preventDefault.ts b/frontend/src/utils/preventDefault.ts new file mode 100644 index 0000000..4c227f7 --- /dev/null +++ b/frontend/src/utils/preventDefault.ts @@ -0,0 +1,9 @@ +export function prevent<HandlerFn extends Function>( + eventHandler: HandlerFn, + ...args: unknown[] + ) { + return <Ev extends Event>(event: Ev) => { + eventHandler(event, ...args); + event.preventDefault(); + }; +} diff --git a/frontend/src/utils/theme.ts b/frontend/src/utils/theme.ts new file mode 100644 index 0000000..5d4fedb --- /dev/null +++ b/frontend/src/utils/theme.ts @@ -0,0 +1,13 @@ +import { createEffect, createSignal } from "solid-js"; + +const setThemeDom = (theme) => { + document.documentElement.setAttribute('data-theme', theme); +}; + +export const [theme, setTheme] = createSignal(localStorage.getItem('theme') || 'dark'); + +createEffect(() => { + const themev = theme(); + setThemeDom(theme()); + localStorage.setItem('theme', themev); +}); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js new file mode 100644 index 0000000..050aa41 --- /dev/null +++ b/frontend/tailwind.config.js @@ -0,0 +1,10 @@ +module.exports = { + content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"], + darkMode: 'class', + theme: { + extend: {}, + }, + plugins: [ + require('daisyui'), + ], +}; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..e27ffb7 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "types": ["vite/client"] + } +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..31ca950 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vite"; +import solidPlugin from "vite-plugin-solid"; + +export default defineConfig({ + plugins: [solidPlugin()], + build: { + target: "esnext", + polyfillDynamicImport: false, + }, +}); diff --git a/migrations/20211219203428_add_token_table.sql b/migrations/20211219203428_add_token_table.sql new file mode 100644 index 0000000..58a4809 --- /dev/null +++ b/migrations/20211219203428_add_token_table.sql @@ -0,0 +1,5 @@ +create table tokens ( + user_id integer not null references users (id) on delete cascade on update cascade, + token text not null primary key, + name text not null +); diff --git a/migrations/20220118174037_change_tokens_to_options.sql b/migrations/20220118174037_change_tokens_to_options.sql new file mode 100644 index 0000000..c23ac84 --- /dev/null +++ b/migrations/20220118174037_change_tokens_to_options.sql @@ -0,0 +1 @@ +alter table tokens rename to options; diff --git a/migrations/20220118174400_add_hidden_to_users.sql b/migrations/20220118174400_add_hidden_to_users.sql new file mode 100644 index 0000000..d7bd738 --- /dev/null +++ b/migrations/20220118174400_add_hidden_to_users.sql @@ -0,0 +1 @@ +alter table users add column hidden boolean not null default false; diff --git a/migrations/20220118201424_make_userid_unique.sql b/migrations/20220118201424_make_userid_unique.sql new file mode 100644 index 0000000..1eace23 --- /dev/null +++ b/migrations/20220118201424_make_userid_unique.sql @@ -0,0 +1 @@ +alter table options add unique (user_id); diff --git a/migrations/20220608133050_auth_webhook.sql b/migrations/20220608133050_auth_webhook.sql new file mode 100644 index 0000000..2cddaea --- /dev/null +++ b/migrations/20220608133050_auth_webhook.sql @@ -0,0 +1,5 @@ +create table webauthtokens ( + id integer generated by default as identity primary key, + token text not null unique, + FOREIGN KEY (id) REFERENCES users(id) +); \ No newline at end of file diff --git a/migrations/20220613142550_per_account_access.sql b/migrations/20220613142550_per_account_access.sql new file mode 100644 index 0000000..431dce3 --- /dev/null +++ b/migrations/20220613142550_per_account_access.sql @@ -0,0 +1,7 @@ +create table vieweraccess ( + id integer, + viewer integer, + PRIMARY KEY (id, viewer), + FOREIGN KEY (id) REFERENCES users(id), + FOREIGN KEY (viewer) REFERENCES users(id) +); \ No newline at end of file diff --git a/migrations/20220919161650_public_for_all.sql b/migrations/20220919161650_public_for_all.sql new file mode 100644 index 0000000..a2098ed --- /dev/null +++ b/migrations/20220919161650_public_for_all.sql @@ -0,0 +1,2 @@ +ALTER TABLE users +ADD COLUMN public BOOL NOT NULL default false ; \ No newline at end of file diff --git a/publish-docker b/publish-docker new file mode 100755 index 0000000..70feee6 --- /dev/null +++ b/publish-docker @@ -0,0 +1,5 @@ +#!/bin/sh +cd frontend +npm run dockerbuild +cd .. +rsync -avz --delete frontend/dist/ ./docker/nginx/site \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json index f88b196..bcdc69c 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -1,68 +1,414 @@ { "db": "PostgreSQL", - "781491287efc1c424be304dfb98da17c4e7d8eed89d1b9ea25c8be55335353cf": { - "query": "insert into users (username, password) values ($1, $2) returning *", + "035ac2413901672740e7489d36c6cc203e5eb5dced90a8b3a6ae1a51ddd1dbb6": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4", + "Int4" + ] + } + }, + "query": "insert into vieweraccess (id, viewer) VALUES ($1,$2);" + }, + "16edda85ef35e4116c9896a763d77e687dff418f64c925027b351d4c3fd06d06": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4" + ] + } + }, + "query": "\n insert into options\n (name, user_id, token)\n values\n ('Stream Token', $1, MD5(random()::text))\n on conflict (user_id) do update\n set token = MD5(random()::text)" + }, + "4a2acc5f1c9f5b2a0e3a5b2f0cc6be02c3220be83d661cb2808a2a1ed54dec98": { "describe": { "columns": [ { - "ordinal": 0, "name": "id", + "ordinal": 0, "type_info": "Int4" }, { - "ordinal": 1, "name": "username", + "ordinal": 1, "type_info": "Text" }, { + "name": "password", "ordinal": 2, + "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int4" + ] + } + }, + "query": "select * from users where users.id in (select viewer from vieweraccess where vieweraccess.id = $1);" + }, + "635f767578d70e7ce415a9c4bb98b0e1bcda0f094683eb3492f5a3161adff2fa": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { "name": "password", + "ordinal": 2, "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" } ], + "nullable": [ + false, + false, + false, + false, + false + ], "parameters": { "Left": [ - "Text", "Text" ] - }, + } + }, + "query": "select id, username, password, hidden, public from users where username = $1" + }, + "77b1d7f7189cb2355bad601fad20a927a0dddee44a81355b1011b9abe9dd1cdf": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" + } + ], "nullable": [ + false, + false, false, false, false - ] - } + ], + "parameters": { + "Left": [ + "Int4" + ] + } + }, + "query": "select id, username, password, hidden, public from users where id = $1" }, - "9d00617966f8aeebb08de6ad981dc3b8697c65f0b23cea4684f525732d8f6706": { - "query": "select * from users where username = $1", + "7967f38ca17eccaad08e2e58b766d27d68be095cb066de10899adf773b21adba": { "describe": { "columns": [ { + "name": "token", "ordinal": 0, - "name": "id", + "type_info": "Text" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "select token from webauthtokens where id = (select id from users where username = $1)" + }, + "7e5bd5781f7618f3e9423c44729d2b452e9372db15e0e22f348b71d157465dd8": { + "describe": { + "columns": [ + { + "name": "token", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "user_id", + "ordinal": 1, "type_info": "Int4" }, { + "name": "name", + "ordinal": 2, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false + ], + "parameters": { + "Left": [ + "Int4" + ] + } + }, + "query": "select token, user_id, name from options where user_id = $1" + }, + "7f7936653a94a67e8379259cfb0496b6229175220e1a1cb42f7cacf4903153ca": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4", + "Int4" + ] + } + }, + "query": "delete from vieweraccess where id = $1 and viewer = $2;" + }, + "9545a4087790343207d689a5fecb45a794dff481ad0f69681117460ebd1704a6": { + "describe": { + "columns": [ + { + "name": "token", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "user_id", "ordinal": 1, + "type_info": "Int4" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false + ], + "parameters": { + "Left": [ + "Int4" + ] + } + }, + "query": "select o.token, o.user_id, o.name from options o where o.user_id = $1" + }, + "a38e160075d36c0277b7fb3198679277f1c7119b59422ec5e047bbfde92e3ea8": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + } + }, + "query": "insert into webauthtokens (id, token)\n values ($1, $2)\n on CONFLICT (id)\n do\n update set token = $2\n " + }, + "afe468aaeb63669c958bd2a6d0beb2100d6c09179256234d156982b82584406e": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Bool", + "Int4" + ] + } + }, + "query": "update users set public = $1 where users.id = $2 " + }, + "cffdcaf762dbf3f870c07bea0907d218819c71cb86804227ed20bb0fb4a7c2e1": { + "describe": { + "columns": [ + { "name": "username", + "ordinal": 0, "type_info": "Text" }, { + "name": "id", + "ordinal": 1, + "type_info": "Int4" + }, + { + "name": "password", "ordinal": 2, + "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "select u.username, u.id, u.password, u.hidden, u.public from users u, options o where u.id = o.user_id and o.token = $1" + }, + "d82d7ac33d8d8fbd83eba9933e7088a44850c2adb19e03ef2d42b755dab1a881": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { "name": "password", + "ordinal": 2, "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" } ], + "nullable": [ + false, + false, + false, + false, + false + ], "parameters": { "Left": [ + "Text", "Text" ] - }, + } + }, + "query": "insert into users (username, password) values ($1, $2) returning id, username, password, hidden, public" + }, + "f6bd67f63b29b20a46a61be88ee59fa60b0eed682c94b38dfa3b64ebec3201d0": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "password", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "hidden", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "public", + "ordinal": 4, + "type_info": "Bool" + } + ], "nullable": [ + false, + false, false, false, false - ] - } + ], + "parameters": { + "Left": [] + } + }, + "query": "select * from users where hidden = false order by id" } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index cfd0d1f..bf909ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,24 @@ use actix_cors::Cors; -use actix_identity::{CookieIdentityPolicy, Identity, IdentityService}; -use actix_web::{post, web, App, HttpResponse, HttpServer, Responder}; -use anyhow::bail; +use actix_identity::{CookieIdentityPolicy, IdentityService}; +use actix_web::{ + body::BoxBody, middleware::Logger, post, web, App, HttpRequest, HttpResponse, HttpServer, + Responder, +}; use chrono::Utc; use dotenv::dotenv; +use env_logger::Env; +use log::{error, info}; use rand::Rng; use serde::{Deserialize, Serialize}; -use sqlx::{postgres::PgPoolOptions, FromRow, Pool, Postgres}; -use std::{collections::HashMap, env}; +use sqlx::PgPool; +use std::env; +use actix_web::cookie::time::Duration; use url::Url; +mod user; + +use crate::user::StreamOption; + #[derive(Debug, Serialize, Deserialize)] struct Config { client: Client, @@ -38,13 +47,18 @@ enum Direction { } #[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] enum Protocol { + #[serde(rename = "WebRTC")] WebRTC, + #[serde(rename = "RTMP")] Rtmp, + #[serde(rename = "SRT")] Srt, + #[serde(rename = "HLS")] Hls, + #[serde(rename = "DASH")] Dash, + #[serde(rename = "LLDASH")] LLDash, } @@ -74,166 +88,63 @@ impl Response { fn allowed() -> Self { Self::new(true, None, None, None) } + + fn redirect(new_url: String) -> Self { + Self::new(true, Some(new_url), None, None) + } + + fn denied(reason: String) -> Self { + Self::new(false, None, None, Some(reason)) + } +} + +impl Responder for Response { + type Body = BoxBody; + fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> { + HttpResponse::Ok().json(&self) + } } // TODO: verify X-OME-Signature #[post("/webhook")] -async fn webhook(body: web::Json<Config>, db: web::Data<PgPool>) -> impl Responder { +async fn webhook(body: web::Json<Config>, db: web::Data<PgPool>) -> Response { if let Direction::Outgoing = body.request.direction { - return HttpResponse::Ok().json(Response::allowed()); + // TODO Implement correct redirects + return Response::allowed(); } - let url = match Url::parse(&body.request.url) { + let mut url = match Url::parse(&body.request.url) { Ok(url) => url, Err(e) => { - println!("{}", e); - return HttpResponse::Unauthorized().json(Response::new( - false, - None, - None, - Some(format!("{}", e)), - )); + error!("{}", e); + return Response::denied(format!("{}", e)); } }; - let creds = url - .query_pairs() - .map(|(l, r)| (l.to_string(), r.to_string())) - .collect::<HashMap<String, String>>(); - if let (Some(username), Some(password)) = (creds.get("username"), creds.get("password")) { - let creds = LoginCredentials { - username: username.to_string(), - password: password.to_string(), - }; + let creds: Option<Vec<&str>> = url.path_segments().map(|s| s.collect()); - if let Ok(_user) = creds.verify(&db).await { - return HttpResponse::Ok().json(Response::allowed()); - } + if creds.is_none() { + return Response::denied("Invalid URL".to_string()); } - HttpResponse::Unauthorized().json(Response::new( - false, - None, - None, - Some("Missing credentials".to_string()), - )) -} - -#[derive(Debug, Serialize, Deserialize)] -struct LoginCredentials { - username: String, - password: String, -} - -impl LoginCredentials { - async fn verify(&self, db: &PgPool) -> anyhow::Result<User> { - let user = sqlx::query_as!( - User, - "select * from users where username = $1", - self.username - ) - .fetch_one(db) - .await?; - let verified = argon2::verify_encoded(&user.password, self.password.as_bytes())?; + let creds = creds.unwrap(); - if verified { - Ok(user) - } else { - bail!("Invalid credentials") - } + if creds.len() != 2 || creds[0] != "app" { + return Response::denied("Unknown Application".to_string()); } -} -#[derive(Debug, FromRow, Serialize, Deserialize)] -struct User { - id: i32, - username: String, - #[serde(skip)] - password: String, -} - -#[post("/login")] -async fn login( - id: Identity, - creds: web::Json<LoginCredentials>, - db: web::Data<PgPool>, -) -> impl Responder { - if id.identity().is_some() { - return HttpResponse::Ok().json("Already logged in"); - } + let token = creds[1]; - let creds = creds.into_inner(); - if let Ok(user) = creds.verify(&db).await { - id.remember(user.id.to_string()); - HttpResponse::Ok().json(user) - } else { - HttpResponse::Unauthorized().json("Invalid username or password") - } -} - -#[post("/logout")] -async fn logout(id: Identity) -> impl Responder { - id.forget(); - - HttpResponse::Ok().json("Logged out") -} - -#[derive(Debug, Serialize, Deserialize)] -struct RegisterCreds { - username: String, - password: String, - secret_code: String, -} - -#[post("/register")] -async fn register( - id: Identity, - db: web::Data<PgPool>, - creds: web::Json<RegisterCreds>, -) -> impl Responder { - let creds = creds.into_inner(); - let secret = match env::var("SECRET_CODE") { - Ok(secret) => secret, - Err(e) => { - dbg!(e); - return HttpResponse::InternalServerError().finish(); - } - }; - if creds.secret_code != secret { - return HttpResponse::Unauthorized().json("Invalid secret code"); - } - let salt = rand::thread_rng().gen::<[u8; 16]>(); - let password = - match argon2::hash_encoded(creds.password.as_bytes(), &salt, &argon2::Config::default()) { - Ok(password) => password, - Err(e) => { - dbg!(e); - return HttpResponse::InternalServerError().finish(); - } - }; - - let user = sqlx::query_as!( - User, - "insert into users (username, password) values ($1, $2) returning *", - creds.username, - password - ) - .fetch_one(&**db) - .await; - - let user = match user { + let user = match StreamOption::get_user_from_token(token, &db).await { Ok(user) => user, Err(e) => { - dbg!(e); - return HttpResponse::InternalServerError().finish(); + error!("{}", e); + return Response::denied(format!("{}", e)); } }; - - id.remember(user.id.to_string()); - HttpResponse::Ok().json(user) + url.set_path(&format!("app/{}", user.username.clone())); + Response::redirect(url.to_string()) } -type PgPool = Pool<Postgres>; - #[actix_web::main] async fn main() -> anyhow::Result<()> { dotenv().ok(); @@ -241,21 +152,39 @@ async fn main() -> anyhow::Result<()> { let db_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set"); let host = env::var("HOST").expect("HOST is not set"); let port = env::var("PORT").expect("PORT is not set"); - let db_pool: PgPool = PgPoolOptions::new().connect(&db_url).await?; + + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + + let db_pool = PgPool::connect(&db_url).await?; sqlx::migrate!("./migrations").run(&db_pool).await?; let secret: [u8; 32] = rand::thread_rng().gen(); + + info!("Starting server on {}:{}", host, port); HttpServer::new(move || { App::new() + .wrap(Logger::default()) .wrap(Cors::permissive()) .wrap(IdentityService::new( - CookieIdentityPolicy::new(&secret).name("auth").secure(true), + CookieIdentityPolicy::new(&secret).name("auth").secure(true).max_age(Duration::days(90)), )) .app_data(web::Data::new(db_pool.clone())) .service(webhook) - .service(login) - .service(logout) + .service(user::login) + .service(user::logout) + .service(user::register) + .service(user::index) + .service(user::me) + .service(user::options) + .service(user::reset) + .service(user::submit_token) + .service(user::generate_token) + .service(user::get_allowed_viewers) + .service(user::set_viewer_permission) + .service(user::allowed_to_watch) + .service(user::submit_header_token) + .service(user::set_public) }) .bind(format!("{}:{}", host, port))? .run() diff --git a/src/user.rs b/src/user.rs new file mode 100644 index 0000000..34c955a --- /dev/null +++ b/src/user.rs @@ -0,0 +1,564 @@ +use std::env; + +use actix_identity::Identity; +use actix_web::{get, post, put, web, HttpResponse, Responder, HttpRequest}; +use anyhow::{bail, Result}; +use log::error; +use rand::Rng; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use sqlx::{FromRow, PgPool}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize)] +pub struct UserWrapper<T: std::fmt::Debug + Serialize> { + user: T, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct LoginCredentials { + pub username: String, + pub password: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct RegisterCreds { + username: String, + password: String, + password_confirmation: String, + secret_code: String, +} + +#[derive(FromRow, Debug, Serialize)] +pub struct User { + pub id: i32, + pub username: String, + #[serde(skip)] + pub password: String, + pub hidden: bool, + pub public: bool, +} + +#[derive(FromRow, Debug, Serialize)] +pub struct StreamOption { + pub token: String, + pub user_id: i32, + pub name: String, +} + +#[derive(FromRow, Debug, Serialize)] +pub struct WebAuthToken { + pub token: String, +} + +pub struct StreamViewerAuthentication { + +} + +pub struct AccessToken { + +} + +impl StreamOption { + + pub async fn get_user_from_token(token: &str, pool: &PgPool) -> Result<User> { + let user = sqlx::query_as!( + User, + "select u.username, u.id, u.password, u.hidden, u.public from users u, options o where u.id = o.user_id and o.token = $1", + token + ) + .fetch_one(pool) + .await?; + + Ok(user) + } + + pub async fn from_user_id(user_id: i32, pool: &PgPool) -> Result<Option<Self>> { + let ooptions = sqlx::query_as!( + Self, + "select o.token, o.user_id, o.name from options o where o.user_id = $1", + user_id + ) + .fetch_optional(pool) + .await?; + + Ok(ooptions) + } +} + +impl StreamViewerAuthentication { + pub async fn get_allowed_viewers(userid: i32, pool: &PgPool) -> Result<Vec<User>> { + let allowed_users = sqlx::query_as!( + User, + "select * from users where users.id in (select viewer from vieweraccess where vieweraccess.id = $1);", + userid + ).fetch_all(pool) + .await?; + + Ok(allowed_users) + } + + pub async fn add_allowed_viewer(userid: i32, viewer: i32, pool: &PgPool) -> Result<()> { + let _ = sqlx::query_as!( + User, + "insert into vieweraccess (id, viewer) VALUES ($1,$2);", + userid, + viewer + ).fetch_all(pool) + .await?; + + Ok(()) + } + + pub async fn delete_allowed_viewer(userid: i32, viewer: i32, pool: &PgPool) -> Result<()> { + let _ = sqlx::query_as!( + User, + "delete from vieweraccess where id = $1 and viewer = $2;", + userid, + viewer + ).fetch_all(pool) + .await?; + + Ok(()) + } +} + +impl AccessToken { + pub async fn put_webauth_token(id: i32, token: &str, db: &PgPool) -> Result<()> { + + let _ = sqlx::query_as!( + WebAuthToken, + "insert into webauthtokens (id, token) + values ($1, $2) + on CONFLICT (id) + do + update set token = $2 + ", + id, + &token + ) + .fetch_optional(db) + .await?; + + Ok(()) + } + + pub async fn from_webauth_token(username: &str, db: &PgPool) -> Result<WebAuthToken> { + + let token = sqlx::query_as!( + WebAuthToken, + "select token from webauthtokens where id = (select id from users where username = $1)", + username + ) + .fetch_one(db) + .await?; + + Ok(token) + } + +} + +impl User { + pub async fn from_id(id: i32, db: &PgPool) -> Result<User> { + let user = sqlx::query_as!( + User, + "select id, username, password, hidden, public from users where id = $1", + id + ) + .fetch_one(db) + .await?; + + Ok(user) + } + + pub async fn from_username(username: &str, db: &PgPool) -> Result<User> { + let user = sqlx::query_as!( + User, + "select id, username, password, hidden, public from users where username = $1", + username + ) + .fetch_one(db) + .await?; + + Ok(user) + } + + pub async fn from_creds(creds: &LoginCredentials, db: &PgPool) -> Result<User> { + let user = sqlx::query_as!( + User, + "select id, username, password, hidden, public from users where username = $1", + &creds.username + ) + .fetch_one(db) + .await?; + + let verified = argon2::verify_encoded(&user.password, creds.password.as_bytes())?; + + if verified { + Ok(user) + } else { + bail!("Invalid credentials") + } + } + + pub async fn create_from_creds(creds: &RegisterCreds, db: &PgPool) -> Result<User> { + let salt = rand::thread_rng().gen::<[u8; 16]>(); + let password = + argon2::hash_encoded(creds.password.as_bytes(), &salt, &argon2::Config::default())?; + + let user = sqlx::query_as!( + User, + "insert into users (username, password) values ($1, $2) returning id, username, password, hidden, public", + &creds.username, + &password + ) + .fetch_one(db) + .await?; + + Ok(user) + } + + #[allow(dead_code)] + pub async fn get_tokens(&self, db: &PgPool) -> Result<StreamOption> { + let tokens = sqlx::query_as!( + StreamOption, + "select token, user_id, name from options where user_id = $1", + self.id + ) + .fetch_one(db) + .await?; + + Ok(tokens) + } + + pub async fn all(db: &PgPool) -> Result<Vec<User>> { + let users = sqlx::query_as!(User, "select * from users where hidden = false order by id") + .fetch_all(db) + .await?; + + Ok(users) + } + + pub async fn set_public(db: &PgPool, is_public: bool, id: i32) -> Result<()> { + sqlx::query!("update users set public = $1 where users.id = $2 ", is_public, id) + .execute(db) + .await?; + Ok(()) + } +} + +// ROUTES + +#[post("/register")] +pub async fn register( + id: Identity, + db: web::Data<PgPool>, + creds: web::Json<UserWrapper<RegisterCreds>>, +) -> impl Responder { + let creds = creds.into_inner().user; + let secret = match env::var("SECRET_CODE") { + Ok(secret) => secret, + Err(e) => { + error!("{}", e); + return HttpResponse::InternalServerError().finish(); + } + }; + if creds.secret_code != secret { + return HttpResponse::Unauthorized().json("Invalid secret code"); + } + match User::create_from_creds(&creds, &db).await { + Ok(user) => { + id.remember(user.id.to_string()); + HttpResponse::Ok().json(json!({ "user": user })) + } + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[post("/logout")] +pub async fn logout(id: Identity) -> impl Responder { + id.forget(); + + HttpResponse::Ok().json(json!({})) +} + +#[post("/login")] +async fn login( + id: Identity, + creds: web::Json<UserWrapper<LoginCredentials>>, + db: web::Data<PgPool>, +) -> impl Responder { + // if id.identity().is_some() { + // return HttpResponse::Ok().json("Already logged in"); + // } + + if let Ok(user) = User::from_creds(&creds.user, &db).await { + id.remember(user.id.to_string()); + HttpResponse::Ok().json(json!({ "user": user })) + } else { + HttpResponse::Unauthorized().json("Invalid username or password") + } +} + +#[get("/users")] +pub async fn index(db: web::Data<PgPool>) -> impl Responder { + match User::all(&db).await { + Ok(users) => HttpResponse::Ok().json(json!({ "users": users })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[get("/allowedViewers")] +pub async fn get_allowed_viewers(id: Identity, db: web::Data<PgPool>) -> impl Responder { + + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + match StreamViewerAuthentication::get_allowed_viewers(id, &db).await { + Ok(users) => HttpResponse::Ok().json(json!({ "users": users })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[derive(Deserialize)] +pub struct AllowedDTO { + stream: String, +} + +#[get("/allowedToWatch")] +pub async fn allowed_to_watch(id: Identity, db: web::Data<PgPool>, web::Query(info): web::Query<AllowedDTO>) -> impl Responder { + + let streamer = User::from_username(&info.stream, &db).await.unwrap(); + + if streamer.public { + return HttpResponse::Ok().json(json!({ "whitelisted": "true" })) + } + + let user_id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + match StreamViewerAuthentication::get_allowed_viewers(streamer.id, &db).await.and_then(|users| { + return Ok(users.is_empty() || users.into_iter().filter(|user| user.id == user_id).count() > 0); + }) { + Ok(allowed) => HttpResponse::Ok().json(json!({ "whitelisted": allowed })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[derive(Deserialize)] +pub struct PermissionDTO { + username: String, + allowed: bool +} + +#[get("/setViewerPermission")] +pub async fn set_viewer_permission(id: Identity, web::Query(info): web::Query<PermissionDTO>, db: web::Data<PgPool>) -> impl Responder { + + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + let user_id = User::from_username(&info.username, &db).await.unwrap(); + + if info.allowed { + match StreamViewerAuthentication::add_allowed_viewer(id, user_id.id, &db).await { + Ok(_) => HttpResponse::Ok().json(json!({ "ok" : "ok" })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } + } else { + match StreamViewerAuthentication::delete_allowed_viewer(id, user_id.id, &db).await { + Ok(_) => HttpResponse::Ok().json(json!({ "ok" : "ok" })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } + } +} + +#[get("/submitHeaderToken")] +pub async fn submit_header_token(request: HttpRequest, db: web::Data<PgPool>) -> impl Responder { + + let headers = request.headers(); + let username = headers.get("username").expect("username").to_str().unwrap(); + let token = headers.get("token").expect("token").to_str().unwrap(); + + match AccessToken::from_webauth_token(&username, &db).await { + Ok(db_token) => { + if db_token.token.eq(&token) { + HttpResponse::Ok().finish() + } else { + HttpResponse::InternalServerError().finish() + } + } + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[derive(Deserialize)] +pub struct TokenInfo { + username: String, + token: String, + streamname: String +} + +#[get("/submitToken")] +pub async fn submit_token(db: web::Data<PgPool>, web::Query(info): web::Query<TokenInfo>) -> impl Responder { + + + let username = info.username; + let token = info.token; + let stream = info.streamname; + + match AccessToken::from_webauth_token(&username, &db).await { + Ok(db_token) => { + if db_token.token.eq(&token) { + let streamer_id = User::from_username(&stream, &db).await.expect("expected existing account"); + + let allowed = StreamViewerAuthentication::get_allowed_viewers(streamer_id.id, &db).await.expect("expected whitelisted users"); + if allowed.len() == 0 { + return HttpResponse::Ok().finish(); + } + if allowed.iter().filter(|entry| entry.username.eq(&username)).count() == 0 { + return HttpResponse::Unauthorized().json(json!({ "errors": ["You are not whitelisted"] })) + } + HttpResponse::Ok().finish() + //TODO maybe drop token + } else { + HttpResponse::InternalServerError().finish() + } + } + Err(e) => { + error!("{}", e); + + let streamer_id = User::from_username(&stream, &db).await.expect("expected existing account"); + if streamer_id.public { + HttpResponse::Ok().finish() + } else { + HttpResponse::InternalServerError().finish() + } + } + } +} + +#[derive(Deserialize)] +pub struct IsPublic { + is_public: bool +} + +#[get("/setPublic")] +pub async fn set_public(db: web::Data<PgPool>, id: Identity, web::Query(info): web::Query<IsPublic>) -> impl Responder { + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + match User::set_public(&db, info.is_public, id).await { + Ok(_) => HttpResponse::Ok().json(json!({ "ok" : "ok" })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[get("/user")] +pub async fn me(id: Identity, db: web::Data<PgPool>) -> impl Responder { + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + match User::from_id(id, &db).await { + Ok(user) => HttpResponse::Ok().json(json!({ "user": user })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[get("/options")] +pub async fn options(id: Identity, db: web::Data<PgPool>) -> impl Responder { + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + match StreamOption::from_user_id(id, &db).await { + Ok(options) => HttpResponse::Ok().json(json!({ "options": options })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +} + +#[post("/reset")] +pub async fn reset(id: Identity, db: web::Data<PgPool>) -> impl Responder { + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + let q = sqlx::query!( + " + insert into options + (name, user_id, token) + values + ('Stream Token', $1, MD5(random()::text)) + on conflict (user_id) do update + set token = MD5(random()::text)", + id + ); + + match q.execute(&**db).await { + Ok(_) => HttpResponse::Ok().json(json!({})), + Err(e) => { + error!("{}", e); + return HttpResponse::InternalServerError().finish(); + } + } +} + +#[put("/generateToken")] +pub async fn generate_token(id: Identity, db: web::Data<PgPool>) -> impl Responder { + + let id = match id.identity() { + Some(id) => id.parse::<i32>().unwrap(), + None => return HttpResponse::Unauthorized().json(json!({ "errors": ["Not logged in"] })), + }; + + let token = Uuid::new_v4().to_string(); + + match AccessToken::put_webauth_token(id, &token, &db).await { + Ok(_) => HttpResponse::Ok().json(json!({ "token": token })), + Err(e) => { + error!("{}", e); + HttpResponse::InternalServerError().finish() + } + } +}