From 0ffb4d651bbd25dae5b6b6738cc7d9ab7f1a4520 Mon Sep 17 00:00:00 2001 From: Shubham Girdhar Date: Wed, 12 Jan 2022 20:43:00 +0530 Subject: [PATCH 01/95] Doc: Add outline (#815) * doc: add categories * refactor: doc structure refactored * fix: package-lock.json removed * refactor: create outline sub-directories * refactor: rename test to testing --- docs/website/docs/client/_category_.json | 4 + docs/website/docs/client/index.md | 1 + docs/website/docs/dsl/_category_.json | 4 + docs/website/docs/dsl/cookies/_category_.json | 4 + docs/website/docs/dsl/cookies/index.md | 1 + docs/website/docs/dsl/headers/_category_.json | 4 + docs/website/docs/dsl/headers/index.md | 1 + .../docs/dsl/http-data/_category_.json | 4 + docs/website/docs/dsl/http-data/index.md | 1 + .../docs/dsl/http-endpoint/_category_.json | 4 + docs/website/docs/dsl/http-endpoint/index.md | 1 + docs/website/docs/dsl/http/_category_.json | 4 + docs/website/docs/dsl/http/index.md | 1 + .../docs/dsl/middleware/_category_.json | 4 + docs/website/docs/dsl/middleware/index.md | 1 + docs/website/docs/dsl/request/_category_.json | 4 + docs/website/docs/dsl/request/index.md | 1 + .../website/docs/dsl/response/_category_.json | 4 + docs/website/docs/dsl/response/index.md | 1 + docs/website/docs/dsl/server/_category_.json | 4 + docs/website/docs/dsl/server/config.md | 3 + docs/website/docs/dsl/socket/_category_.json | 4 + docs/website/docs/dsl/socket/index.md | 1 + docs/website/docs/examples/_category_.json | 4 + .../advanced-examples/_category_.json | 2 +- .../advanced-examples/authentication.md | 0 .../advanced-examples/concrete-entity.md | 0 .../{ => examples}/advanced-examples/cors.md | 0 .../advanced-examples/hello-world-advanced.md | 0 .../advanced-examples/sticky-threads.md | 0 .../advanced-examples/stream-file.md | 0 .../advanced-examples/stream-response.md | 0 .../advanced-examples/web-socket-advanced.md | 0 .../zio-http-basic-examples/_category_.json | 2 +- .../zio-http-basic-examples/hello-world.md | 0 .../zio-http-basic-examples/https-client.md | 0 .../zio-http-basic-examples/https-server.md | 0 .../zio-http-basic-examples/simple-client.md | 0 .../zio-http-basic-examples/web-socket.md | 0 docs/website/docs/getting-started.md | 150 + docs/website/docs/index.md | 149 +- .../website/docs/integrations/_category_.json | 4 + docs/website/docs/integrations/index.md | 1 + docs/website/docs/testing/_category_.json | 4 + docs/website/docs/testing/index.md | 1 + docs/website/package-lock.json | 10970 ---------------- 46 files changed, 230 insertions(+), 11118 deletions(-) create mode 100644 docs/website/docs/client/_category_.json create mode 100644 docs/website/docs/client/index.md create mode 100644 docs/website/docs/dsl/_category_.json create mode 100644 docs/website/docs/dsl/cookies/_category_.json create mode 100644 docs/website/docs/dsl/cookies/index.md create mode 100644 docs/website/docs/dsl/headers/_category_.json create mode 100644 docs/website/docs/dsl/headers/index.md create mode 100644 docs/website/docs/dsl/http-data/_category_.json create mode 100644 docs/website/docs/dsl/http-data/index.md create mode 100644 docs/website/docs/dsl/http-endpoint/_category_.json create mode 100644 docs/website/docs/dsl/http-endpoint/index.md create mode 100644 docs/website/docs/dsl/http/_category_.json create mode 100644 docs/website/docs/dsl/http/index.md create mode 100644 docs/website/docs/dsl/middleware/_category_.json create mode 100644 docs/website/docs/dsl/middleware/index.md create mode 100644 docs/website/docs/dsl/request/_category_.json create mode 100644 docs/website/docs/dsl/request/index.md create mode 100644 docs/website/docs/dsl/response/_category_.json create mode 100644 docs/website/docs/dsl/response/index.md create mode 100644 docs/website/docs/dsl/server/_category_.json create mode 100644 docs/website/docs/dsl/server/config.md create mode 100644 docs/website/docs/dsl/socket/_category_.json create mode 100644 docs/website/docs/dsl/socket/index.md create mode 100644 docs/website/docs/examples/_category_.json rename docs/website/docs/{ => examples}/advanced-examples/_category_.json (69%) rename docs/website/docs/{ => examples}/advanced-examples/authentication.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/concrete-entity.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/cors.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/hello-world-advanced.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/sticky-threads.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/stream-file.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/stream-response.md (100%) rename docs/website/docs/{ => examples}/advanced-examples/web-socket-advanced.md (100%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/_category_.json (67%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/hello-world.md (100%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/https-client.md (100%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/https-server.md (100%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/simple-client.md (100%) rename docs/website/docs/{ => examples}/zio-http-basic-examples/web-socket.md (100%) create mode 100644 docs/website/docs/getting-started.md create mode 100644 docs/website/docs/integrations/_category_.json create mode 100644 docs/website/docs/integrations/index.md create mode 100644 docs/website/docs/testing/_category_.json create mode 100644 docs/website/docs/testing/index.md delete mode 100644 docs/website/package-lock.json diff --git a/docs/website/docs/client/_category_.json b/docs/website/docs/client/_category_.json new file mode 100644 index 0000000000..2375b2e5de --- /dev/null +++ b/docs/website/docs/client/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Client", + "position": 4 +} diff --git a/docs/website/docs/client/index.md b/docs/website/docs/client/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/client/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/_category_.json b/docs/website/docs/dsl/_category_.json new file mode 100644 index 0000000000..26a54df6b1 --- /dev/null +++ b/docs/website/docs/dsl/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "DSL", + "position": 3 +} diff --git a/docs/website/docs/dsl/cookies/_category_.json b/docs/website/docs/dsl/cookies/_category_.json new file mode 100644 index 0000000000..9b211dec85 --- /dev/null +++ b/docs/website/docs/dsl/cookies/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Cookies", + "position": 6 +} diff --git a/docs/website/docs/dsl/cookies/index.md b/docs/website/docs/dsl/cookies/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/cookies/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/headers/_category_.json b/docs/website/docs/dsl/headers/_category_.json new file mode 100644 index 0000000000..e262285346 --- /dev/null +++ b/docs/website/docs/dsl/headers/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Headers", + "position": 5 +} diff --git a/docs/website/docs/dsl/headers/index.md b/docs/website/docs/dsl/headers/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/headers/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http-data/_category_.json b/docs/website/docs/dsl/http-data/_category_.json new file mode 100644 index 0000000000..b75e6fa5f0 --- /dev/null +++ b/docs/website/docs/dsl/http-data/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "HttpData", + "position": 4 +} diff --git a/docs/website/docs/dsl/http-data/index.md b/docs/website/docs/dsl/http-data/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http-data/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http-endpoint/_category_.json b/docs/website/docs/dsl/http-endpoint/_category_.json new file mode 100644 index 0000000000..32aac10e88 --- /dev/null +++ b/docs/website/docs/dsl/http-endpoint/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Endpoint", + "position": 7 +} diff --git a/docs/website/docs/dsl/http-endpoint/index.md b/docs/website/docs/dsl/http-endpoint/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http-endpoint/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http/_category_.json b/docs/website/docs/dsl/http/_category_.json new file mode 100644 index 0000000000..36e5fb9e60 --- /dev/null +++ b/docs/website/docs/dsl/http/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Http", + "position": 1 +} diff --git a/docs/website/docs/dsl/http/index.md b/docs/website/docs/dsl/http/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/middleware/_category_.json b/docs/website/docs/dsl/middleware/_category_.json new file mode 100644 index 0000000000..56c8cbc188 --- /dev/null +++ b/docs/website/docs/dsl/middleware/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Middleware", + "position": 9 +} diff --git a/docs/website/docs/dsl/middleware/index.md b/docs/website/docs/dsl/middleware/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/middleware/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/request/_category_.json b/docs/website/docs/dsl/request/_category_.json new file mode 100644 index 0000000000..c942703c4e --- /dev/null +++ b/docs/website/docs/dsl/request/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Request", + "position": 2 +} diff --git a/docs/website/docs/dsl/request/index.md b/docs/website/docs/dsl/request/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/request/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/response/_category_.json b/docs/website/docs/dsl/response/_category_.json new file mode 100644 index 0000000000..cf41ce17cb --- /dev/null +++ b/docs/website/docs/dsl/response/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Response", + "position": 3 +} diff --git a/docs/website/docs/dsl/response/index.md b/docs/website/docs/dsl/response/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/response/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/server/_category_.json b/docs/website/docs/dsl/server/_category_.json new file mode 100644 index 0000000000..2e000bb553 --- /dev/null +++ b/docs/website/docs/dsl/server/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Server", + "position": 8 +} diff --git a/docs/website/docs/dsl/server/config.md b/docs/website/docs/dsl/server/config.md new file mode 100644 index 0000000000..50b2454a71 --- /dev/null +++ b/docs/website/docs/dsl/server/config.md @@ -0,0 +1,3 @@ +# Config + +Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/socket/_category_.json b/docs/website/docs/dsl/socket/_category_.json new file mode 100644 index 0000000000..095acccf27 --- /dev/null +++ b/docs/website/docs/dsl/socket/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Socket", + "position": 10 +} diff --git a/docs/website/docs/dsl/socket/index.md b/docs/website/docs/dsl/socket/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/socket/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/examples/_category_.json b/docs/website/docs/examples/_category_.json new file mode 100644 index 0000000000..2dc4c4fe79 --- /dev/null +++ b/docs/website/docs/examples/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Examples", + "position": 7 +} diff --git a/docs/website/docs/advanced-examples/_category_.json b/docs/website/docs/examples/advanced-examples/_category_.json similarity index 69% rename from docs/website/docs/advanced-examples/_category_.json rename to docs/website/docs/examples/advanced-examples/_category_.json index d996d51894..0621e5caa1 100644 --- a/docs/website/docs/advanced-examples/_category_.json +++ b/docs/website/docs/examples/advanced-examples/_category_.json @@ -1,4 +1,4 @@ { "label": "Advanced Examples", - "position": 3 + "position": 2 } diff --git a/docs/website/docs/advanced-examples/authentication.md b/docs/website/docs/examples/advanced-examples/authentication.md similarity index 100% rename from docs/website/docs/advanced-examples/authentication.md rename to docs/website/docs/examples/advanced-examples/authentication.md diff --git a/docs/website/docs/advanced-examples/concrete-entity.md b/docs/website/docs/examples/advanced-examples/concrete-entity.md similarity index 100% rename from docs/website/docs/advanced-examples/concrete-entity.md rename to docs/website/docs/examples/advanced-examples/concrete-entity.md diff --git a/docs/website/docs/advanced-examples/cors.md b/docs/website/docs/examples/advanced-examples/cors.md similarity index 100% rename from docs/website/docs/advanced-examples/cors.md rename to docs/website/docs/examples/advanced-examples/cors.md diff --git a/docs/website/docs/advanced-examples/hello-world-advanced.md b/docs/website/docs/examples/advanced-examples/hello-world-advanced.md similarity index 100% rename from docs/website/docs/advanced-examples/hello-world-advanced.md rename to docs/website/docs/examples/advanced-examples/hello-world-advanced.md diff --git a/docs/website/docs/advanced-examples/sticky-threads.md b/docs/website/docs/examples/advanced-examples/sticky-threads.md similarity index 100% rename from docs/website/docs/advanced-examples/sticky-threads.md rename to docs/website/docs/examples/advanced-examples/sticky-threads.md diff --git a/docs/website/docs/advanced-examples/stream-file.md b/docs/website/docs/examples/advanced-examples/stream-file.md similarity index 100% rename from docs/website/docs/advanced-examples/stream-file.md rename to docs/website/docs/examples/advanced-examples/stream-file.md diff --git a/docs/website/docs/advanced-examples/stream-response.md b/docs/website/docs/examples/advanced-examples/stream-response.md similarity index 100% rename from docs/website/docs/advanced-examples/stream-response.md rename to docs/website/docs/examples/advanced-examples/stream-response.md diff --git a/docs/website/docs/advanced-examples/web-socket-advanced.md b/docs/website/docs/examples/advanced-examples/web-socket-advanced.md similarity index 100% rename from docs/website/docs/advanced-examples/web-socket-advanced.md rename to docs/website/docs/examples/advanced-examples/web-socket-advanced.md diff --git a/docs/website/docs/zio-http-basic-examples/_category_.json b/docs/website/docs/examples/zio-http-basic-examples/_category_.json similarity index 67% rename from docs/website/docs/zio-http-basic-examples/_category_.json rename to docs/website/docs/examples/zio-http-basic-examples/_category_.json index cd2491b9a3..8afc5e6543 100644 --- a/docs/website/docs/zio-http-basic-examples/_category_.json +++ b/docs/website/docs/examples/zio-http-basic-examples/_category_.json @@ -1,4 +1,4 @@ { "label": "Basic Examples", - "position": 2 + "position": 1 } diff --git a/docs/website/docs/zio-http-basic-examples/hello-world.md b/docs/website/docs/examples/zio-http-basic-examples/hello-world.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/hello-world.md rename to docs/website/docs/examples/zio-http-basic-examples/hello-world.md diff --git a/docs/website/docs/zio-http-basic-examples/https-client.md b/docs/website/docs/examples/zio-http-basic-examples/https-client.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/https-client.md rename to docs/website/docs/examples/zio-http-basic-examples/https-client.md diff --git a/docs/website/docs/zio-http-basic-examples/https-server.md b/docs/website/docs/examples/zio-http-basic-examples/https-server.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/https-server.md rename to docs/website/docs/examples/zio-http-basic-examples/https-server.md diff --git a/docs/website/docs/zio-http-basic-examples/simple-client.md b/docs/website/docs/examples/zio-http-basic-examples/simple-client.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/simple-client.md rename to docs/website/docs/examples/zio-http-basic-examples/simple-client.md diff --git a/docs/website/docs/zio-http-basic-examples/web-socket.md b/docs/website/docs/examples/zio-http-basic-examples/web-socket.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/web-socket.md rename to docs/website/docs/examples/zio-http-basic-examples/web-socket.md diff --git a/docs/website/docs/getting-started.md b/docs/website/docs/getting-started.md new file mode 100644 index 0000000000..934852d5bb --- /dev/null +++ b/docs/website/docs/getting-started.md @@ -0,0 +1,150 @@ +--- +sidebar_position: 2 +--- + +# Getting Started + +## Http + +### Creating a "_Hello World_" app + +```scala +import zhttp.http._ + +val app = Http.text("Hello World!") +``` + +An application can be made using any of the available operators on `zhttp.Http`. In the above program for any Http request, the response is always `"Hello World!"`. + +### Routing + +```scala +import zhttp.http._ + +val app = Http.collect[Request] { + case Method.GET -> Root / "fruits" / "a" => Response.text("Apple") + case Method.GET -> Root / "fruits" / "b" => Response.text("Banana") +} +``` + +Pattern matching on route is supported by the framework + +### Composition + +```scala +import zhttp.http._ + +val a = Http.collect[Request] { case Method.GET -> Root / "a" => Response.ok } +val b = Http.collect[Request] { case Method.GET -> Root / "b" => Response.ok } + +val app = a <> b +``` + +Apps can be composed using the `<>` operator. The way it works is, if none of the routes match in `a` , or a `NotFound` error is thrown from `a`, and then the control is passed on to the `b` app. + +### ZIO Integration + +```scala +val app = Http.collectM[Request] { + case Method.GET -> Root / "hello" => ZIO.succeed(Response.text("Hello World")) +} +``` + +`Http.collectM` allow routes to return a ZIO effect value. + +### Accessing the Request + +```scala +import zhttp.http._ + +val app = Http.collect[Request] { + case req @ Method.GET -> Root / "fruits" / "a" => + Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) + case req @ Method.POST -> Root / "fruits" / "a" => + Response.text(req.getBodyAsString.getOrElse("No body!")) +} +``` + +### Testing + +zhttp provides a `zhttp-test` package for use in unit tests. You can utilize it as follows: + +```scala +import zio.test._ +import zhttp.test._ +import zhttp.http._ + +object Spec extends DefaultRunnableSpec { + val app = Http.collect[Request] { + case Method.GET -> Root / "text" => Response.text("Hello World!") + } + + def spec = suite("http") ( + testM("should be ok") { + val req = ??? + val expectedRes = resp => resp.status.toJHttpStatus.code() == Status.OK + assertM(app(req))(expectedRes) // an apply method is added via `zhttp.test` package + } + ) +} +``` + +```scala +import zhttp.http._ + +val app = Http.collect[Request] { + case req @ Method.GET -> Root / "fruits" / "a" => + Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) + case req @ Method.POST -> Root / "fruits" / "a" => + Response.text(req.getBodyAsString.getOrElse("No body!")) +} +``` + +## Socket + +### Creating a socket app + +```scala +import zhttp.socket._ + +private val socket = Socket.collect[WebSocketFrame] { + case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) +} + +private val app = Http.collect[Request] { + case Method.GET -> Root / "greet" / name => Response.text(s"Greetings {$name}!") + case Method.GET -> Root / "ws" => Response.socket(socket) +} +``` + +## Server + +### Starting an Http App + +```scala +import zhttp.http._ +import zhttp.service.Server +import zio._ + +object HelloWorld extends App { + val app = Http.ok + + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app).exitCode +} +``` + +A simple Http app that responds with empty content and a `200` status code is deployed on port `8090` using `Server.start`. + +## Examples + +- [Simple Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorld.scala) +- [Advanced Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorldAdvanced.scala) +- [WebSocket Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SocketEchoServer.scala) +- [Streaming Response](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/StreamingResponse.scala) +- [Simple Client](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SimpleClient.scala) +- [File Streaming](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/FileStreaming.scala) +- [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) + + + diff --git a/docs/website/docs/index.md b/docs/website/docs/index.md index 19eca45937..5819dcca26 100644 --- a/docs/website/docs/index.md +++ b/docs/website/docs/index.md @@ -1,150 +1,7 @@ --- sidebar_position: 1 +sidebar_label: "Setup" --- -# Getting Started - -## Http - -### Creating a "_Hello World_" app - -```scala -import zhttp.http._ - -val app = Http.text("Hello World!") -``` - -An application can be made using any of the available operators on `zhttp.Http`. In the above program for any Http request, the response is always `"Hello World!"`. - -### Routing - -```scala -import zhttp.http._ - -val app = Http.collect[Request] { - case Method.GET -> Root / "fruits" / "a" => Response.text("Apple") - case Method.GET -> Root / "fruits" / "b" => Response.text("Banana") -} -``` - -Pattern matching on route is supported by the framework - -### Composition - -```scala -import zhttp.http._ - -val a = Http.collect[Request] { case Method.GET -> Root / "a" => Response.ok } -val b = Http.collect[Request] { case Method.GET -> Root / "b" => Response.ok } - -val app = a <> b -``` - -Apps can be composed using the `<>` operator. The way it works is, if none of the routes match in `a` , or a `NotFound` error is thrown from `a`, and then the control is passed on to the `b` app. - -### ZIO Integration - -```scala -val app = Http.collectM[Request] { - case Method.GET -> Root / "hello" => ZIO.succeed(Response.text("Hello World")) -} -``` - -`Http.collectM` allow routes to return a ZIO effect value. - -### Accessing the Request - -```scala -import zhttp.http._ - -val app = Http.collect[Request] { - case req @ Method.GET -> Root / "fruits" / "a" => - Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) - case req @ Method.POST -> Root / "fruits" / "a" => - Response.text(req.getBodyAsString.getOrElse("No body!")) -} -``` - -### Testing - -zhttp provides a `zhttp-test` package for use in unit tests. You can utilize it as follows: - -```scala -import zio.test._ -import zhttp.test._ -import zhttp.http._ - -object Spec extends DefaultRunnableSpec { - val app = Http.collect[Request] { - case Method.GET -> Root / "text" => Response.text("Hello World!") - } - - def spec = suite("http") ( - testM("should be ok") { - val req = ??? - val expectedRes = resp => resp.status.toJHttpStatus.code() == Status.OK - assertM(app(req))(expectedRes) // an apply method is added via `zhttp.test` package - } - ) -} -``` - -```scala -import zhttp.http._ - -val app = Http.collect[Request] { - case req @ Method.GET -> Root / "fruits" / "a" => - Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) - case req @ Method.POST -> Root / "fruits" / "a" => - Response.text(req.getBodyAsString.getOrElse("No body!")) -} -``` - -## Socket - -### Creating a socket app - -```scala -import zhttp.socket._ - -private val socket = Socket.collect[WebSocketFrame] { - case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) -} - -private val app = Http.collect[Request] { - case Method.GET -> Root / "greet" / name => Response.text(s"Greetings {$name}!") - case Method.GET -> Root / "ws" => Response.socket(socket) -} -``` - -## Server - -### Starting an Http App - -```scala -import zhttp.http._ -import zhttp.service.Server -import zio._ - -object HelloWorld extends App { - val app = Http.ok - - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode -} -``` - -A simple Http app that responds with empty content and a `200` status code is deployed on port `8090` using `Server.start`. - -## Examples - -- [Simple Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorld.scala) -- [Advanced Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorldAdvanced.scala) -- [WebSocket Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SocketEchoServer.scala) -- [Streaming Response](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/StreamingResponse.scala) -- [Simple Client](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SimpleClient.scala) -- [File Streaming](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/FileStreaming.scala) -- [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) - - - +# Setup +Work in progress \ No newline at end of file diff --git a/docs/website/docs/integrations/_category_.json b/docs/website/docs/integrations/_category_.json new file mode 100644 index 0000000000..3e6c5308c1 --- /dev/null +++ b/docs/website/docs/integrations/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Integrations", + "position": 6 +} diff --git a/docs/website/docs/integrations/index.md b/docs/website/docs/integrations/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/integrations/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/testing/_category_.json b/docs/website/docs/testing/_category_.json new file mode 100644 index 0000000000..ed8fcad563 --- /dev/null +++ b/docs/website/docs/testing/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Testing", + "position": 5 +} diff --git a/docs/website/docs/testing/index.md b/docs/website/docs/testing/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/testing/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/package-lock.json b/docs/website/package-lock.json deleted file mode 100644 index 843088c7ed..0000000000 --- a/docs/website/package-lock.json +++ /dev/null @@ -1,10970 +0,0 @@ -{ - "name": "zio-http-docs", - "version": "0.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@algolia/autocomplete-core": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.2.2.tgz", - "integrity": "sha512-JOQaURze45qVa8OOFDh+ozj2a/ObSRsVyz6Zd0aiBeej+RSTqrr1hDVpGNbbXYLW26G5ujuc9QIdH+rBHn95nw==", - "requires": { - "@algolia/autocomplete-shared": "1.2.2" - } - }, - "@algolia/autocomplete-preset-algolia": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.2.2.tgz", - "integrity": "sha512-AZkh+bAMaJDzMZTelFOXJTJqkp5VPGH8W3n0B+Ggce7DdozlMRsDLguKTCQAkZ0dJ1EbBPyFL5ztL/JImB137Q==", - "requires": { - "@algolia/autocomplete-shared": "1.2.2" - } - }, - "@algolia/autocomplete-shared": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.2.2.tgz", - "integrity": "sha512-mLTl7d2C1xVVazHt/bqh9EE/u2lbp5YOxLDdcjILXmUqOs5HH1D4SuySblXaQG1uf28FhTqMGp35qE5wJQnqAw==" - }, - "@algolia/cache-browser-local-storage": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.11.0.tgz", - "integrity": "sha512-4sr9vHIG1fVA9dONagdzhsI/6M5mjs/qOe2xUP0yBmwsTsuwiZq3+Xu6D3dsxsuFetcJgC6ydQoCW8b7fDJHYQ==", - "requires": { - "@algolia/cache-common": "4.11.0" - } - }, - "@algolia/cache-common": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.11.0.tgz", - "integrity": "sha512-lODcJRuPXqf+6mp0h6bOxPMlbNoyn3VfjBVcQh70EDP0/xExZbkpecgHyyZK4kWg+evu+mmgvTK3GVHnet/xKw==" - }, - "@algolia/cache-in-memory": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.11.0.tgz", - "integrity": "sha512-aBz+stMSTBOBaBEQ43zJXz2DnwS7fL6dR0e2myehAgtfAWlWwLDHruc/98VOy1ZAcBk1blE2LCU02bT5HekGxQ==", - "requires": { - "@algolia/cache-common": "4.11.0" - } - }, - "@algolia/client-account": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.11.0.tgz", - "integrity": "sha512-jwmFBoUSzoMwMqgD3PmzFJV/d19p1RJXB6C1ADz4ju4mU7rkaQLtqyZroQpheLoU5s5Tilmn/T8/0U2XLoJCRQ==", - "requires": { - "@algolia/client-common": "4.11.0", - "@algolia/client-search": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "@algolia/client-analytics": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.11.0.tgz", - "integrity": "sha512-v5U9585aeEdYml7JqggHAj3E5CQ+jPwGVztPVhakBk8H/cmLyPS2g8wvmIbaEZCHmWn4TqFj3EBHVYxAl36fSA==", - "requires": { - "@algolia/client-common": "4.11.0", - "@algolia/client-search": "4.11.0", - "@algolia/requester-common": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "@algolia/client-common": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.11.0.tgz", - "integrity": "sha512-Qy+F+TZq12kc7tgfC+FM3RvYH/Ati7sUiUv/LkvlxFwNwNPwWGoZO81AzVSareXT/ksDDrabD4mHbdTbBPTRmQ==", - "requires": { - "@algolia/requester-common": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "@algolia/client-personalization": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.11.0.tgz", - "integrity": "sha512-mI+X5IKiijHAzf9fy8VSl/GTT67dzFDnJ0QAM8D9cMPevnfX4U72HRln3Mjd0xEaYUOGve8TK/fMg7d3Z5yG6g==", - "requires": { - "@algolia/client-common": "4.11.0", - "@algolia/requester-common": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "@algolia/client-search": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.11.0.tgz", - "integrity": "sha512-iovPLc5YgiXBdw2qMhU65sINgo9umWbHFzInxoNErWnYoTQWfXsW6P54/NlKx5uscoLVjSf+5RUWwFu5BX+lpw==", - "requires": { - "@algolia/client-common": "4.11.0", - "@algolia/requester-common": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "@algolia/logger-common": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.11.0.tgz", - "integrity": "sha512-pRMJFeOY8hoWKIxWuGHIrqnEKN/kqKh7UilDffG/+PeEGxBuku+Wq5CfdTFG0C9ewUvn8mAJn5BhYA5k8y0Jqg==" - }, - "@algolia/logger-console": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.11.0.tgz", - "integrity": "sha512-wXztMk0a3VbNmYP8Kpc+F7ekuvaqZmozM2eTLok0XIshpAeZ/NJDHDffXK2Pw+NF0wmHqurptLYwKoikjBYvhQ==", - "requires": { - "@algolia/logger-common": "4.11.0" - } - }, - "@algolia/requester-browser-xhr": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.11.0.tgz", - "integrity": "sha512-Fp3SfDihAAFR8bllg8P5ouWi3+qpEVN5e7hrtVIYldKBOuI/qFv80Zv/3/AMKNJQRYglS4zWyPuqrXm58nz6KA==", - "requires": { - "@algolia/requester-common": "4.11.0" - } - }, - "@algolia/requester-common": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.11.0.tgz", - "integrity": "sha512-+cZGe/9fuYgGuxjaBC+xTGBkK7OIYdfapxhfvEf03dviLMPmhmVYFJtJlzAjQ2YmGDJpHrGgAYj3i/fbs8yhiA==" - }, - "@algolia/requester-node-http": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.11.0.tgz", - "integrity": "sha512-qJIk9SHRFkKDi6dMT9hba8X1J1z92T5AZIgl+tsApjTGIRQXJLTIm+0q4yOefokfu4CoxYwRZ9QAq+ouGwfeOg==", - "requires": { - "@algolia/requester-common": "4.11.0" - } - }, - "@algolia/transporter": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.11.0.tgz", - "integrity": "sha512-k4dyxiaEfYpw4UqybK9q7lrFzehygo6KV3OCYJMMdX0IMWV0m4DXdU27c1zYRYtthaFYaBzGF4Kjcl8p8vxCKw==", - "requires": { - "@algolia/cache-common": "4.11.0", - "@algolia/logger-common": "4.11.0", - "@algolia/requester-common": "4.11.0" - } - }, - "@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", - "requires": { - "@babel/highlight": "^7.16.0" - } - }, - "@babel/compat-data": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz", - "integrity": "sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==" - }, - "@babel/core": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", - "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helpers": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0", - "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" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", - "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", - "requires": { - "@babel/types": "^7.16.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz", - "integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.0.tgz", - "integrity": "sha512-9KuleLT0e77wFUku6TUkqZzCEymBdtuQQ27MhEKzf9UOOJu3cYj98kyaDAzxpC7lV6DGiZFuC8XqDsq8/Kl6aQ==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz", - "integrity": "sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg==", - "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.0.tgz", - "integrity": "sha512-XLwWvqEaq19zFlF5PTgOod4bUA+XbkR4WLQBct1bkzmxJGB0ZEJaoKF4c8cgH9oBtCDuYJ8BP5NB9uFiEgO5QA==", - "requires": { - "@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" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz", - "integrity": "sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "regexpu-core": "^4.7.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.4.tgz", - "integrity": "sha512-OrpPZ97s+aPi6h2n1OXzdhVis1SGSsMU2aMHgLcOKfsp4/v1NWpx3CWT3lBj5eeBq9cDkPkh+YCfdF7O12uNDQ==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", - "integrity": "sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", - "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", - "requires": { - "@babel/helper-get-function-arity": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", - "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", - "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", - "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@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==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-module-transforms": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", - "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", - "requires": { - "@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.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", - "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.0.tgz", - "integrity": "sha512-MLM1IOMe9aQBqMWxcRw8dcb9jlM86NIw7KA0Wri91Xkfied+dE0QuBFSBjMNvqzmS0OSIDsMNC24dBEkPUi7ew==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-replace-supers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", - "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", - "requires": { - "@babel/helper-member-expression-to-functions": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-simple-access": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", - "integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", - "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" - }, - "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" - }, - "@babel/helper-wrap-function": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz", - "integrity": "sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g==", - "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/helpers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.0.tgz", - "integrity": "sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ==", - "requires": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", - "requires": { - "@babel/helper-validator-identifier": "^7.15.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.2.tgz", - "integrity": "sha512-h37CvpLSf8gb2lIJ2CgC3t+EjFbi0t8qS7LCS1xcJIlEXE4czlofwaW7W1HA8zpgOCzI9C1nmoqNR1zWkk0pQg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz", - "integrity": "sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.0.tgz", - "integrity": "sha512-nyYmIo7ZqKsY6P4lnVmBlxp9B3a96CscbLotlsNuktMHahkDwoPYEjXrZHU0Tj844Z9f1IthVxQln57mhkcExw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.0.tgz", - "integrity": "sha512-mCF3HcuZSY9Fcx56Lbn+CGdT44ioBMMvjNVldpKtj8tpniETdLjnxdHI1+sDWXIM1nNt+EanJOZ3IG9lzVjs7A==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.0.tgz", - "integrity": "sha512-mAy3sdcY9sKAkf3lQbDiv3olOfiLqI51c9DR9b19uMoR2Z6r5pmGl7dfNFqEvqOyqbf1ta4lknK4gc5PJn3mfA==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.0.tgz", - "integrity": "sha512-QGSA6ExWk95jFQgwz5GQ2Dr95cf7eI7TKutIXXTb7B1gCLTCz5hTjFTQGfLFBBiC5WSNi7udNwWsqbbMh1c4yQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.0.tgz", - "integrity": "sha512-CjI4nxM/D+5wCnhD11MHB1AwRSAYeDT+h8gCdcVJZ/OK7+wRzFsf7PFPWVpVpNRkHMmMkQWAHpTq+15IXQ1diA==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.0.tgz", - "integrity": "sha512-kouIPuiv8mSi5JkEhzApg5Gn6hFyKPnlkO0a9YSzqRurH8wYzSlf6RJdzluAsbqecdW5pBvDJDfyDIUR/vLxvg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.0.tgz", - "integrity": "sha512-pbW0fE30sVTYXXm9lpVQQ/Vc+iTeQKiXlaNRZPPN2A2VdlWyAtsUrsQ3xydSlDW00TFMK7a8m3cDTkBF5WnV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.0.tgz", - "integrity": "sha512-3bnHA8CAFm7cG93v8loghDYyQ8r97Qydf63BeYiGgYbjKKB/XP53W15wfRC7dvKfoiJ34f6Rbyyx2btExc8XsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.0.tgz", - "integrity": "sha512-FAhE2I6mjispy+vwwd6xWPyEx3NYFS13pikDBWUAFGZvq6POGs5eNchw8+1CYoEgBl9n11I3NkzD7ghn25PQ9Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.0.tgz", - "integrity": "sha512-LU/+jp89efe5HuWJLmMmFG0+xbz+I2rSI7iLc1AlaeSMDMOGzWlc5yJrMN1d04osXN4sSfpo4O+azkBNBes0jg==", - "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.0" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.0.tgz", - "integrity": "sha512-kicDo0A/5J0nrsCPbn89mTG3Bm4XgYi0CZtvex9Oyw7gGZE3HXGD0zpQNH+mo+tEfbo8wbmMvJftOwpmPy7aVw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.0.tgz", - "integrity": "sha512-Y4rFpkZODfHrVo70Uaj6cC1JJOt3Pp0MdWSwIKtb8z1/lsjl9AmnB7ErRFV+QNGIfcY1Eruc2UMx5KaRnXjMyg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.0.tgz", - "integrity": "sha512-IvHmcTHDFztQGnn6aWq4t12QaBXTKr1whF/dgp9kz84X6GUcwq9utj7z2wFCUfeOup/QKnOlt2k0zxkGFx9ubg==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.0.tgz", - "integrity": "sha512-3jQUr/HBbMVZmi72LpjQwlZ55i1queL8KcDTQEkAHihttJnAPrcvG9ZNXIfsd2ugpizZo595egYV6xy+pv4Ofw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.0.tgz", - "integrity": "sha512-ti7IdM54NXv29cA4+bNNKEMS4jLMCbJgl+Drv+FgYy0erJLAxNAIXcNjNjrRZEcWq0xJHsNVwQezskMFpF8N9g==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.0.tgz", - "integrity": "sha512-8zv2+xiPHwly31RK4RmnEYY5zziuF3O7W2kIDW+07ewWDh6Oi0dRq8kwvulRkFgt6DB97RlKs5c1y068iPlCUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", - "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.0.tgz", - "integrity": "sha512-vIFb5250Rbh7roWARvCLvIJ/PtAU5Lhv7BtZ1u24COwpI9Ypjsh+bZcKk6rlIyalK+r0jOc1XQ8I4ovNxNrWrA==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz", - "integrity": "sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw==", - "requires": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-remap-async-to-generator": "^7.16.0" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.0.tgz", - "integrity": "sha512-V14As3haUOP4ZWrLJ3VVx5rCnrYhMSHN/jX7z6FAt5hjRkLsb0snPCmJwSOML5oxkKO4FNoNv7V5hw/y2bjuvg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.0.tgz", - "integrity": "sha512-27n3l67/R3UrXfizlvHGuTwsRIFyce3D/6a37GRxn28iyTPvNXaW4XvznexRh1zUNLPjbLL22Id0XQElV94ruw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.0.tgz", - "integrity": "sha512-HUxMvy6GtAdd+GKBNYDWCIA776byUQH8zjnfjxwT1P1ARv/wFu8eBDpmXQcLS/IwRtrxIReGiplOwMeyO7nsDQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.0.tgz", - "integrity": "sha512-63l1dRXday6S8V3WFY5mXJwcRAnPYxvFfTlt67bwV1rTyVTM5zrp0DBBb13Kl7+ehkCVwIZPumPpFP/4u70+Tw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.0.tgz", - "integrity": "sha512-Q7tBUwjxLTsHEoqktemHBMtb3NYwyJPTJdM+wDwb0g8PZ3kQUIzNvwD5lPaqW/p54TXBc/MXZu9Jr7tbUEUM8Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.0.tgz", - "integrity": "sha512-FXlDZfQeLILfJlC6I1qyEwcHK5UpRCFkaoVyA1nk9A1L1Yu583YO4un2KsLBsu3IJb4CUbctZks8tD9xPQubLw==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.0.tgz", - "integrity": "sha512-LIe2kcHKAZOJDNxujvmp6z3mfN6V9lJxubU4fJIGoQCkKe3Ec2OcbdlYP+vW++4MpxwG0d1wSDOJtQW5kLnkZQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.0.tgz", - "integrity": "sha512-OwYEvzFI38hXklsrbNivzpO3fh87skzx8Pnqi4LoSYeav0xHlueSoCJrSgTPfnbyzopo5b3YVAJkFIcUpK2wsw==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.0.tgz", - "integrity": "sha512-5QKUw2kO+GVmKr2wMYSATCTTnHyscl6sxFRAY+rvN7h7WB0lcG0o4NoV6ZQU32OZGVsYUsfLGgPQpDFdkfjlJQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.0.tgz", - "integrity": "sha512-lBzMle9jcOXtSOXUpc7tvvTpENu/NuekNJVova5lCCWCV9/U1ho2HH2y0p6mBg8fPm/syEAbfaaemYGOHCY3mg==", - "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.0.tgz", - "integrity": "sha512-gQDlsSF1iv9RU04clgXqRjrPyyoJMTclFt3K1cjLmTKikc0s/6vE3hlDeEVC71wLTRu72Fq7650kABrdTc2wMQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.0.tgz", - "integrity": "sha512-WRpw5HL4Jhnxw8QARzRvwojp9MIE7Tdk3ez6vRyUk1MwgjJN0aNpRoXainLR5SgxmoXx/vsXGZ6OthP6t/RbUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.0.tgz", - "integrity": "sha512-rWFhWbCJ9Wdmzln1NmSCqn7P0RAD+ogXG/bd9Kg5c7PKWkJtkiXmYsMBeXjDlzHpVTJ4I/hnjs45zX4dEv81xw==", - "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.0.tgz", - "integrity": "sha512-Dzi+NWqyEotgzk/sb7kgQPJQf7AJkQBWsVp1N6JWc1lBVo0vkElUnGdr1PzUBmfsCCN5OOFya3RtpeHk15oLKQ==", - "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-simple-access": "^7.16.0", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.0.tgz", - "integrity": "sha512-yuGBaHS3lF1m/5R+6fjIke64ii5luRUg97N2wr+z1sF0V+sNSXPxXDdEEL/iYLszsN5VKxVB1IPfEqhzVpiqvg==", - "requires": { - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-identifier": "^7.15.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "dependencies": { - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - } - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.0.tgz", - "integrity": "sha512-nx4f6no57himWiHhxDM5pjwhae5vLpTK2zCnDH8+wNLJy0TVER/LJRHl2bkt6w9Aad2sPD5iNNoUpY3X9sTGDg==", - "requires": { - "@babel/helper-module-transforms": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.0.tgz", - "integrity": "sha512-LogN88uO+7EhxWc8WZuQ8vxdSyVGxhkh8WTC3tzlT8LccMuQdA81e9SGV6zY7kY2LjDhhDOFdQVxdGwPyBCnvg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.0.tgz", - "integrity": "sha512-fhjrDEYv2DBsGN/P6rlqakwRwIp7rBGLPbrKxwh7oVt5NNkIhZVOY2GRV+ULLsQri1bDqwDWnU3vhlmx5B2aCw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.0.tgz", - "integrity": "sha512-fds+puedQHn4cPLshoHcR1DTMN0q1V9ou0mUjm8whx9pGcNvDrVVrgw+KJzzCaiTdaYhldtrUps8DWVMgrSEyg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-replace-supers": "^7.16.0" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.0.tgz", - "integrity": "sha512-XgnQEm1CevKROPx+udOi/8f8TiGhrUWiHiaUCIp47tE0tpFDjzXNTZc9E5CmCwxNjXTWEVqvRfWZYOTFvMa/ZQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.0.tgz", - "integrity": "sha512-XLldD4V8+pOqX2hwfWhgwXzGdnDOThxaNTgqagOcpBgIxbUvpgU2FMvo5E1RyHbk756WYgdbS0T8y0Cj9FKkWQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.0.tgz", - "integrity": "sha512-OgtklS+p9t1X37eWA4XdvvbZG/3gqzX569gqmo3q4/Ui6qjfTQmOs5UTSrfdD9nVByHhX6Gbm/Pyc4KbwUXGWA==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.0.tgz", - "integrity": "sha512-FJFdJAqaCpndL+pIf0aeD/qlQwT7QXOvR6Cc8JPvNhKJBi2zc/DPc4g05Y3fbD/0iWAMQFGij4+Xw+4L/BMpTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.0.tgz", - "integrity": "sha512-rqDgIbukZ44pqq7NIRPGPGNklshPkvlmvqjdx3OZcGPk4zGIenYkxDTvl3LsSL8gqcc3ZzGmXPE6hR/u/voNOw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-jsx": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.0.tgz", - "integrity": "sha512-qq65iSqBRq0Hr3wq57YG2AmW0H6wgTnIzpffTphrUWUgLCOK+zf1f7G0vuOiXrp7dU1qq+fQBoqZ3wCDAkhFzw==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.0" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.0.tgz", - "integrity": "sha512-NC/Bj2MG+t8Ef5Pdpo34Ay74X4Rt804h5y81PwOpfPtmAK3i6CizmQqwyBQzIepz1Yt8wNr2Z2L7Lu3qBMfZMA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.0.tgz", - "integrity": "sha512-JAvGxgKuwS2PihiSFaDrp94XOzzTUeDeOQlcKzVAyaPap7BnZXK/lvMDiubkPTdotPKOIZq9xWXWnggUMYiExg==", - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.0.tgz", - "integrity": "sha512-Dgs8NNCehHSvXdhEhln8u/TtJxfVwGYCgP2OOr5Z3Ar+B+zXicEOKNTyc+eca2cuEOMtjW6m9P9ijOt8QdqWkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.0.tgz", - "integrity": "sha512-zlPf1/XFn5+vWdve3AAhf+Sxl+MVa5VlwTwWgnLx23u4GlatSRQJ3Eoo9vllf0a9il3woQsT4SK+5Z7c06h8ag==", - "requires": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "babel-plugin-polyfill-corejs2": "^0.2.3", - "babel-plugin-polyfill-corejs3": "^0.3.0", - "babel-plugin-polyfill-regenerator": "^0.2.3", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.0.tgz", - "integrity": "sha512-iVb1mTcD8fuhSv3k99+5tlXu5N0v8/DPm2mO3WACLG6al1CGZH7v09HJyUb1TtYl/Z+KrM6pHSIJdZxP5A+xow==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.0.tgz", - "integrity": "sha512-Ao4MSYRaLAQczZVp9/7E7QHsCuK92yHRrmVNRe/SlEJjhzivq0BSn8mEraimL8wizHZ3fuaHxKH0iwzI13GyGg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.0.tgz", - "integrity": "sha512-/ntT2NljR9foobKk4E/YyOSwcGUXtYWv5tinMK/3RkypyNBNdhHUaq6Orw5DWq9ZcNlS03BIlEALFeQgeVAo4Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.0.tgz", - "integrity": "sha512-Rd4Ic89hA/f7xUSJQk5PnC+4so50vBoBfxjdQAdvngwidM8jYIBVxBZ/sARxD4e0yMXRbJVDrYf7dyRtIIKT6Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.0.tgz", - "integrity": "sha512-++V2L8Bdf4vcaHi2raILnptTBjGEFxn5315YU+e8+EqXIucA+q349qWngCLpUYqqv233suJ6NOienIVUpS9cqg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.16.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz", - "integrity": "sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/plugin-syntax-typescript": "^7.16.0" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.0.tgz", - "integrity": "sha512-VFi4dhgJM7Bpk8lRc5CMaRGlKZ29W9C3geZjt9beuzSUrlJxsNwX7ReLwaL6WEvsOf2EQkyIJEPtF8EXjB/g2A==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.0.tgz", - "integrity": "sha512-jHLK4LxhHjvCeZDWyA9c+P9XH1sOxRd1RO9xMtDVRAOND/PczPqizEtVdx4TQF/wyPaewqpT+tgQFYMnN/P94A==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/preset-env": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.0.tgz", - "integrity": "sha512-cdTu/W0IrviamtnZiTfixPfIncr2M1VqRrkjzZWlr1B4TVYimCFK5jkyOdP4qw2MrlKHi+b3ORj6x8GoCew8Dg==", - "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-compilation-targets": "^7.16.0", - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.0", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-async-generator-functions": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-class-static-block": "^7.16.0", - "@babel/plugin-proposal-dynamic-import": "^7.16.0", - "@babel/plugin-proposal-export-namespace-from": "^7.16.0", - "@babel/plugin-proposal-json-strings": "^7.16.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-object-rest-spread": "^7.16.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-proposal-private-property-in-object": "^7.16.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.0", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.0", - "@babel/plugin-transform-async-to-generator": "^7.16.0", - "@babel/plugin-transform-block-scoped-functions": "^7.16.0", - "@babel/plugin-transform-block-scoping": "^7.16.0", - "@babel/plugin-transform-classes": "^7.16.0", - "@babel/plugin-transform-computed-properties": "^7.16.0", - "@babel/plugin-transform-destructuring": "^7.16.0", - "@babel/plugin-transform-dotall-regex": "^7.16.0", - "@babel/plugin-transform-duplicate-keys": "^7.16.0", - "@babel/plugin-transform-exponentiation-operator": "^7.16.0", - "@babel/plugin-transform-for-of": "^7.16.0", - "@babel/plugin-transform-function-name": "^7.16.0", - "@babel/plugin-transform-literals": "^7.16.0", - "@babel/plugin-transform-member-expression-literals": "^7.16.0", - "@babel/plugin-transform-modules-amd": "^7.16.0", - "@babel/plugin-transform-modules-commonjs": "^7.16.0", - "@babel/plugin-transform-modules-systemjs": "^7.16.0", - "@babel/plugin-transform-modules-umd": "^7.16.0", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.0", - "@babel/plugin-transform-new-target": "^7.16.0", - "@babel/plugin-transform-object-super": "^7.16.0", - "@babel/plugin-transform-parameters": "^7.16.0", - "@babel/plugin-transform-property-literals": "^7.16.0", - "@babel/plugin-transform-regenerator": "^7.16.0", - "@babel/plugin-transform-reserved-words": "^7.16.0", - "@babel/plugin-transform-shorthand-properties": "^7.16.0", - "@babel/plugin-transform-spread": "^7.16.0", - "@babel/plugin-transform-sticky-regex": "^7.16.0", - "@babel/plugin-transform-template-literals": "^7.16.0", - "@babel/plugin-transform-typeof-symbol": "^7.16.0", - "@babel/plugin-transform-unicode-escapes": "^7.16.0", - "@babel/plugin-transform-unicode-regex": "^7.16.0", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.0", - "babel-plugin-polyfill-corejs2": "^0.2.3", - "babel-plugin-polyfill-corejs3": "^0.3.0", - "babel-plugin-polyfill-regenerator": "^0.2.3", - "core-js-compat": "^3.19.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.0.tgz", - "integrity": "sha512-d31IFW2bLRB28uL1WoElyro8RH5l6531XfxMtCeCmp6RVAF1uTfxxUA0LH1tXl+psZdwfmIbwoG4U5VwgbhtLw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-react-jsx": "^7.16.0", - "@babel/plugin-transform-react-jsx-development": "^7.16.0", - "@babel/plugin-transform-react-pure-annotations": "^7.16.0" - } - }, - "@babel/preset-typescript": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz", - "integrity": "sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-validator-option": "^7.14.5", - "@babel/plugin-transform-typescript": "^7.16.0" - } - }, - "@babel/runtime": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.0.tgz", - "integrity": "sha512-Nht8L0O8YCktmsDV6FqFue7vQLRx3Hb0B37lS5y0jDRqRxlBG4wIJHnf9/bgSE2UyipKFA01YtS+npRdTWBUyw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.0.tgz", - "integrity": "sha512-Oi2qwQ21X7/d9gn3WiwkDTJmq3TQtYNz89lRnoFy8VeZpWlsyXvzSwiRrRZ8cXluvSwqKxqHJ6dBd9Rv+p0ZGQ==", - "requires": { - "core-js-pure": "^3.19.0", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", - "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", - "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0" - } - }, - "@babel/traverse": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", - "integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", - "requires": { - "@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.0", - "@babel/types": "^7.16.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", - "requires": { - "@babel/helper-validator-identifier": "^7.15.7", - "to-fast-properties": "^2.0.0" - } - }, - "@docsearch/css": { - "version": "3.0.0-alpha.41", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.0.0-alpha.41.tgz", - "integrity": "sha512-AP1jqcF/9jCrm4s0lcES3QAtHueyipKjd14L/pguk0CZYK7uI7hC0FWodmRmrgK3/HST9jiHa1waUMR6ZYedlQ==" - }, - "@docsearch/react": { - "version": "3.0.0-alpha.41", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.0.0-alpha.41.tgz", - "integrity": "sha512-UL0Gdter/NUea04lGuBGH0GzQ2/2q/hBfn7Rjo71rRKbjtfkQCM92leJ9tZ+9j9sFLoyuHb9XMm/B8vCjWwTEg==", - "requires": { - "@algolia/autocomplete-core": "1.2.2", - "@algolia/autocomplete-preset-algolia": "1.2.2", - "@docsearch/css": "3.0.0-alpha.41", - "algoliasearch": "^4.0.0" - } - }, - "@docusaurus/core": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.0.0-beta.8.tgz", - "integrity": "sha512-KVbZoOCxQKvbX1RT8qrHAsPVYPGDnXFevTeJbZW1XQb0OPv7oh5nijXJvzNeGupXP561BByrsdHT7IxM/hT0CQ==", - "requires": { - "@babel/core": "^7.12.16", - "@babel/generator": "^7.12.15", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", - "@babel/preset-react": "^7.12.13", - "@babel/preset-typescript": "^7.12.16", - "@babel/runtime": "^7.15.4", - "@babel/runtime-corejs3": "^7.15.4", - "@babel/traverse": "^7.12.13", - "@docusaurus/cssnano-preset": "2.0.0-beta.8", - "@docusaurus/react-loadable": "5.5.0", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-common": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "@slorber/static-site-generator-webpack-plugin": "^4.0.0", - "@svgr/webpack": "^5.5.0", - "autoprefixer": "^10.3.5", - "babel-loader": "^8.2.2", - "babel-plugin-dynamic-import-node": "2.3.0", - "boxen": "^5.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.2", - "clean-css": "^5.1.5", - "commander": "^5.1.0", - "copy-webpack-plugin": "^9.0.1", - "core-js": "^3.18.0", - "css-loader": "^5.1.1", - "css-minimizer-webpack-plugin": "^3.0.2", - "cssnano": "^5.0.8", - "del": "^6.0.0", - "detect-port": "^1.3.0", - "escape-html": "^1.0.3", - "eta": "^1.12.3", - "express": "^4.17.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "globby": "^11.0.2", - "html-minifier-terser": "^6.0.2", - "html-tags": "^3.1.0", - "html-webpack-plugin": "^5.4.0", - "import-fresh": "^3.3.0", - "is-root": "^2.1.0", - "leven": "^3.1.0", - "lodash": "^4.17.20", - "mini-css-extract-plugin": "^1.6.0", - "module-alias": "^2.2.2", - "nprogress": "^0.2.0", - "postcss": "^8.3.7", - "postcss-loader": "^6.1.1", - "prompts": "^2.4.1", - "react-dev-utils": "^11.0.1", - "react-error-overlay": "^6.0.9", - "react-helmet": "^6.1.0", - "react-loadable": "^5.5.0", - "react-loadable-ssr-addon-v5-slorber": "^1.0.1", - "react-router": "^5.2.0", - "react-router-config": "^5.1.1", - "react-router-dom": "^5.2.0", - "remark-admonitions": "^1.2.1", - "resolve-pathname": "^3.0.0", - "rtl-detect": "^1.0.4", - "semver": "^7.3.4", - "serve-handler": "^6.1.3", - "shelljs": "^0.8.4", - "std-env": "^2.2.1", - "strip-ansi": "^6.0.0", - "terser-webpack-plugin": "^5.2.4", - "tslib": "^2.3.1", - "update-notifier": "^5.1.0", - "url-loader": "^4.1.1", - "wait-on": "^6.0.0", - "webpack": "^5.40.0", - "webpack-bundle-analyzer": "^4.4.2", - "webpack-dev-server": "^3.11.2", - "webpack-merge": "^5.8.0", - "webpackbar": "^5.0.0-3" - } - }, - "@docusaurus/cssnano-preset": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.8.tgz", - "integrity": "sha512-RXApzIEaTsTSpz4YV86DBXaFvXH3J4SNIWba/AFSoPBviODjxIu+7TRRs9eh8vUAB32nVBtcdHmRb25b662szQ==", - "requires": { - "cssnano-preset-advanced": "^5.1.4", - "postcss": "^8.3.7", - "postcss-sort-media-queries": "^4.1.0" - } - }, - "@docusaurus/mdx-loader": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.8.tgz", - "integrity": "sha512-unVimkaAGgkt+d/QgQPwm8FaRZVB0jew6Q902KSl1Hx0yWI/x5LKWY/y4kCFUBv7rCsuSqyjoZwggD+evw//bg==", - "requires": { - "@babel/parser": "^7.12.16", - "@babel/traverse": "^7.12.13", - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@mdx-js/mdx": "^1.6.21", - "@mdx-js/react": "^1.6.21", - "chalk": "^4.1.2", - "escape-html": "^1.0.3", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "github-slugger": "^1.4.0", - "gray-matter": "^4.0.3", - "mdast-util-to-string": "^2.0.0", - "remark-emoji": "^2.1.0", - "stringify-object": "^3.3.0", - "unist-util-visit": "^2.0.2", - "url-loader": "^4.1.1", - "webpack": "^5.40.0" - } - }, - "@docusaurus/plugin-content-blog": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.8.tgz", - "integrity": "sha512-sUAk3MZrZL7YMp66h+pIy0rOQYFovB8kh9LbDdTXREDyTViCygfkr/6sFPRWpoFzws/kbXoRCPIPcrzcYj+/Pw==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/mdx-loader": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "chalk": "^4.1.2", - "escape-string-regexp": "^4.0.0", - "feed": "^4.2.2", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "js-yaml": "^4.0.0", - "loader-utils": "^2.0.0", - "lodash": "^4.17.20", - "reading-time": "^1.5.0", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.40.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - } - } - }, - "@docusaurus/plugin-content-docs": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.8.tgz", - "integrity": "sha512-uE8mI5zQFcwtxAbycxv6G7ALtqKgNwd4URuJhv4VQ2DhR5uta/yd9IK8BPduwrbYLWZuGf2uO3jVsPbgNBZ0RQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/mdx-loader": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "chalk": "^4.1.2", - "combine-promises": "^1.1.0", - "escape-string-regexp": "^4.0.0", - "execa": "^5.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "import-fresh": "^3.2.2", - "js-yaml": "^4.0.0", - "loader-utils": "^2.0.0", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "shelljs": "^0.8.4", - "tslib": "^2.3.1", - "utility-types": "^3.10.0", - "webpack": "^5.40.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - } - } - }, - "@docusaurus/plugin-content-pages": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.8.tgz", - "integrity": "sha512-NcYKwwBhOR1eH5FZpktaRtBYDsT8vnwR2mAYqS4Oyl7EeyYNKb1ykMnBn5tDktMuRaLRy1flq5u79Nc5oscHIQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/mdx-loader": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "globby": "^11.0.2", - "lodash": "^4.17.20", - "remark-admonitions": "^1.2.1", - "tslib": "^2.3.1", - "webpack": "^5.40.0" - } - }, - "@docusaurus/plugin-debug": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.8.tgz", - "integrity": "sha512-DCsYnVQ+MTEfGTOEsSCpZDG+xADM3dC5K2BfT4kDUB4De1SKH37NoXXJpGaVEtE4gLjRWoDGfDaQdS/LlVqwiQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "fs-extra": "^10.0.0", - "react-json-view": "^1.21.3", - "tslib": "^2.3.1" - } - }, - "@docusaurus/plugin-google-analytics": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.8.tgz", - "integrity": "sha512-kpk9pXPIfE+5CbcJSbwF6Evfy5kX+4Z0Ph/x/M1N+8omH+StDrR+fa1S3I5GK38lb3/N1fWNgsWE7LembE9xYQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8" - } - }, - "@docusaurus/plugin-google-gtag": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.8.tgz", - "integrity": "sha512-1Wa0yMXZgxp85dGuOD44X+fnZtW8ztmOcGBOgLo9Uwhi+OhxOrW4ZOddhEJA6tmCaRuqkaMK7zN1ss2EUc2g7g==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8" - } - }, - "@docusaurus/plugin-sitemap": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.8.tgz", - "integrity": "sha512-oz2Hu1q34kvsgPb6DWM8cpzKmNy02BYtv+2GTrg016V+beGr8PNcHkxzgGtdN+Se5zJqdtRQvOPQtIZOJQntcA==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-common": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "fs-extra": "^10.0.0", - "sitemap": "^7.0.0", - "tslib": "^2.3.1" - } - }, - "@docusaurus/preset-classic": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.8.tgz", - "integrity": "sha512-tlc+KuMJFmfXYA/FOCbHvMfRWx2SQtJLf6rkBUzRt0Vlym+pI7CG1px3OKON62jaaLm/Vyvn3+47z3yClJRM1A==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/plugin-content-blog": "2.0.0-beta.8", - "@docusaurus/plugin-content-docs": "2.0.0-beta.8", - "@docusaurus/plugin-content-pages": "2.0.0-beta.8", - "@docusaurus/plugin-debug": "2.0.0-beta.8", - "@docusaurus/plugin-google-analytics": "2.0.0-beta.8", - "@docusaurus/plugin-google-gtag": "2.0.0-beta.8", - "@docusaurus/plugin-sitemap": "2.0.0-beta.8", - "@docusaurus/theme-classic": "2.0.0-beta.8", - "@docusaurus/theme-search-algolia": "2.0.0-beta.8" - } - }, - "@docusaurus/react-loadable": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-5.5.0.tgz", - "integrity": "sha512-Ld/kwUE6yATIOTLq3JCsWiTa/drisajwKqBQ2Rw6IcT+sFsKfYek8F2jSH8f68AT73xX97UehduZeCSlnuCBIg==", - "requires": { - "prop-types": "^15.6.2" - } - }, - "@docusaurus/theme-classic": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.8.tgz", - "integrity": "sha512-lC0PGxACbNiq98WwF1O3T0YblqSK6yo7KcDcrOnPJd0XCV4xMjWZSeeSIneotfs2uvJzmG3GOg7EfQcLvhdyIQ==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/plugin-content-blog": "2.0.0-beta.8", - "@docusaurus/plugin-content-docs": "2.0.0-beta.8", - "@docusaurus/plugin-content-pages": "2.0.0-beta.8", - "@docusaurus/theme-common": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-common": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "@mdx-js/mdx": "^1.6.21", - "@mdx-js/react": "^1.6.21", - "chalk": "^4.1.2", - "clsx": "^1.1.1", - "copy-text-to-clipboard": "^3.0.1", - "fs-extra": "^10.0.0", - "globby": "^11.0.2", - "infima": "0.2.0-alpha.34", - "lodash": "^4.17.20", - "parse-numeric-range": "^1.3.0", - "postcss": "^8.3.7", - "prism-react-renderer": "^1.2.1", - "prismjs": "^1.23.0", - "prop-types": "^15.7.2", - "react-router-dom": "^5.2.0", - "rtlcss": "^3.3.0" - } - }, - "@docusaurus/theme-common": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.8.tgz", - "integrity": "sha512-jrlCgFcg0wAfrtzSwU5F8iVdIBmL325d6jupD3N2CirSG6TxAmHDkeAbFyY6ZjaT27XYWXJUwvqvsbbNXAdNzw==", - "requires": { - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/plugin-content-blog": "2.0.0-beta.8", - "@docusaurus/plugin-content-docs": "2.0.0-beta.8", - "@docusaurus/plugin-content-pages": "2.0.0-beta.8", - "@docusaurus/types": "2.0.0-beta.8", - "clsx": "^1.1.1", - "fs-extra": "^10.0.0", - "tslib": "^2.3.1", - "utility-types": "^3.10.0" - } - }, - "@docusaurus/theme-search-algolia": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.8.tgz", - "integrity": "sha512-ryT57Wipems0GbB0WxdrTUJ4q/1DM6xoqJlpGGnTy52FEZi3ZoCp+1yxaBLbKKYevGl1nEF3S0kp1o13UiqKTw==", - "requires": { - "@docsearch/react": "^3.0.0-alpha.39", - "@docusaurus/core": "2.0.0-beta.8", - "@docusaurus/theme-common": "2.0.0-beta.8", - "@docusaurus/utils": "2.0.0-beta.8", - "@docusaurus/utils-validation": "2.0.0-beta.8", - "algoliasearch": "^4.10.5", - "algoliasearch-helper": "^3.5.5", - "clsx": "^1.1.1", - "eta": "^1.12.3", - "lodash": "^4.17.20" - } - }, - "@docusaurus/types": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.0.0-beta.8.tgz", - "integrity": "sha512-wEzyQvku2zNNp3ChPk1x5s7SvlFygTyuqL9dpwvzCsJhxqZ0JH+whellh2YtDQQO617npOM8l6MC1Yd6ePws2Q==", - "requires": { - "commander": "^5.1.0", - "joi": "^17.4.2", - "querystring": "0.2.0", - "utility-types": "^3.10.0", - "webpack": "^5.40.0", - "webpack-merge": "^5.8.0" - } - }, - "@docusaurus/utils": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.8.tgz", - "integrity": "sha512-PMdPg8ft/zdAqhuDvMLzDlwXEp01qAh+eOXciKElDrh1zuQM/Hwjg0G3sKiwKInbpHJcz6lbTJCpEjmvMGlXpg==", - "requires": { - "@docusaurus/types": "2.0.0-beta.8", - "@mdx-js/runtime": "^1.6.22", - "@types/github-slugger": "^1.3.0", - "chalk": "^4.1.2", - "escape-string-regexp": "^4.0.0", - "fs-extra": "^10.0.0", - "globby": "^11.0.4", - "gray-matter": "^4.0.3", - "lodash": "^4.17.20", - "micromatch": "^4.0.4", - "remark-mdx-remove-exports": "^1.6.22", - "remark-mdx-remove-imports": "^1.6.22", - "resolve-pathname": "^3.0.0", - "tslib": "^2.3.1" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - } - } - }, - "@docusaurus/utils-common": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.0.0-beta.8.tgz", - "integrity": "sha512-SWnXd+VHN+YWKJGdaPHLmREaNMKEFQmAN12xA/FufXFDvVZJOA2YShLEAjSJDQTKt9hfGys3JCYF1PBgosB0sA==", - "requires": { - "@docusaurus/types": "2.0.0-beta.8", - "tslib": "^2.3.1" - } - }, - "@docusaurus/utils-validation": { - "version": "2.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.8.tgz", - "integrity": "sha512-zcoJw9Bo/WkRLJhD53ck0rA68cnswc9TB84F/hOm92X4QkhjCUtb5XlMUtTtvO9ScnlgsFiQYaySrFRAM+fr5w==", - "requires": { - "@docusaurus/utils": "2.0.0-beta.8", - "chalk": "^4.1.2", - "joi": "^17.4.2", - "tslib": "^2.3.1" - } - }, - "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==" - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@mdx-js/mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", - "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==", - "requires": { - "@babel/core": "7.12.9", - "@babel/plugin-syntax-jsx": "7.12.1", - "@babel/plugin-syntax-object-rest-spread": "7.8.3", - "@mdx-js/util": "1.6.22", - "babel-plugin-apply-mdx-type-prop": "1.6.22", - "babel-plugin-extract-import-names": "1.6.22", - "camelcase-css": "2.0.1", - "detab": "2.0.4", - "hast-util-raw": "6.0.1", - "lodash.uniq": "4.5.0", - "mdast-util-to-hast": "10.0.1", - "remark-footnotes": "2.0.0", - "remark-mdx": "1.6.22", - "remark-parse": "8.0.3", - "remark-squeeze-paragraphs": "4.0.0", - "style-to-object": "0.3.0", - "unified": "9.2.0", - "unist-builder": "2.0.3", - "unist-util-visit": "2.0.3" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "@mdx-js/react": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz", - "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==" - }, - "@mdx-js/runtime": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/runtime/-/runtime-1.6.22.tgz", - "integrity": "sha512-p17spaO2+55VLCuxXA3LVHC4phRx60NR2XMdZ+qgVU1lKvEX4y88dmFNOzGDCPLJ03IZyKrJ/rPWWRiBrd9JrQ==", - "requires": { - "@mdx-js/mdx": "1.6.22", - "@mdx-js/react": "1.6.22", - "buble-jsx-only": "^0.19.8" - } - }, - "@mdx-js/util": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz", - "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==" - }, - "@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==", - "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==" - }, - "@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==", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==" - }, - "@sideway/address": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", - "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" - }, - "@slorber/static-site-generator-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw==", - "requires": { - "bluebird": "^3.7.1", - "cheerio": "^0.22.0", - "eval": "^0.1.4", - "url": "^0.11.0", - "webpack-sources": "^1.4.3" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } - } - }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==" - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==" - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==" - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==" - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==" - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==" - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==" - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==" - }, - "@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - } - }, - "@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "requires": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - } - }, - "@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "requires": { - "@babel/types": "^7.12.6" - } - }, - "@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "requires": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - } - }, - "@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", - "requires": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - } - } - } - }, - "@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "requires": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - } - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==" - }, - "@types/eslint": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz", - "integrity": "sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==", - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==" - }, - "@types/github-slugger": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz", - "integrity": "sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g==" - }, - "@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/hast": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz", - "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==", - "requires": { - "@types/unist": "*" - } - }, - "@types/html-minifier-terser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz", - "integrity": "sha512-NZwaaynfs1oIoLAV1vg18e7QMVDvw+6SQrdJc8w3BwUaoroVSf6EBj/Sk4PBWGxsq0dzhA2drbsuMC1/6C6KgQ==" - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" - }, - "@types/mdast": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", - "integrity": "sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==", - "requires": { - "@types/unist": "*" - } - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" - }, - "@types/node": { - "version": "16.11.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz", - "integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==" - }, - "@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==" - }, - "@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==" - }, - "@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" - }, - "@types/sax": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.3.tgz", - "integrity": "sha512-+QSw6Tqvs/KQpZX8DvIl3hZSjNFLW/OqE5nlyHXtTwODaJvioN2rOWpBNEWZp2HZUFhOh+VohmJku/WxEXU2XA==", - "requires": { - "@types/node": "*" - } - }, - "@types/unist": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", - "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==" - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" - }, - "address": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz", - "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==" - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" - }, - "algoliasearch": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.11.0.tgz", - "integrity": "sha512-IXRj8kAP2WrMmj+eoPqPc6P7Ncq1yZkFiyDrjTBObV1ADNL8Z/KdZ+dWC5MmYcBLAbcB/mMCpak5N/D1UIZvsA==", - "requires": { - "@algolia/cache-browser-local-storage": "4.11.0", - "@algolia/cache-common": "4.11.0", - "@algolia/cache-in-memory": "4.11.0", - "@algolia/client-account": "4.11.0", - "@algolia/client-analytics": "4.11.0", - "@algolia/client-common": "4.11.0", - "@algolia/client-personalization": "4.11.0", - "@algolia/client-search": "4.11.0", - "@algolia/logger-common": "4.11.0", - "@algolia/logger-console": "4.11.0", - "@algolia/requester-browser-xhr": "4.11.0", - "@algolia/requester-common": "4.11.0", - "@algolia/requester-node-http": "4.11.0", - "@algolia/transporter": "4.11.0" - } - }, - "algoliasearch-helper": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.6.2.tgz", - "integrity": "sha512-Xx0NOA6k4ySn+R2l3UMSONAaMkyfmrZ3AP1geEMo32MxDJQJesZABZYsldO9fa6FKQxH91afhi4hO1G0Zc2opg==", - "requires": { - "events": "^1.1.1" - }, - "dependencies": { - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - } - } - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" - } - } - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "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==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "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==" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "autoprefixer": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.0.tgz", - "integrity": "sha512-7FdJ1ONtwzV1G43GDD0kpVMn/qbiNqyOPMFTX5nRffI+7vgWoFEc6DcXOxHJxrWNDXrZh18eDsZjvZGUljSRGA==", - "requires": { - "browserslist": "^4.17.5", - "caniuse-lite": "^1.0.30001272", - "fraction.js": "^4.1.1", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.1.0" - } - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "babel-plugin-apply-mdx-type-prop": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz", - "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==", - "requires": { - "@babel/helper-plugin-utils": "7.10.4", - "@mdx-js/util": "1.6.22" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", - "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-extract-import-names": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", - "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==", - "requires": { - "@babel/helper-plugin-utils": "7.10.4" - }, - "dependencies": { - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - } - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.3.tgz", - "integrity": "sha512-NDZ0auNRzmAfE1oDDPW2JhzIMXUk+FFe2ICejmt5T4ocKgiQx3e0VCRx9NCAidcMtL2RUZaWtXnmjTCkx0tcbA==", - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.2.4", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.3.0.tgz", - "integrity": "sha512-JLwi9vloVdXLjzACL80j24bG6/T1gYxwowG44dg6HN/7aTPdyPbJJidf6ajoA3RPHHtW0j9KMrSOLpIZpAnPpg==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.4", - "core-js-compat": "^3.18.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.3.tgz", - "integrity": "sha512-JVE78oRZPKFIeUqFGrSORNzQnrDwZR16oiWeGM8ZyjBn2XAT5OjP+wXx5ESuo33nUsFUEJYjtklnsKbxW5L+7g==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.2.4" - } - }, - "bail": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", - "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base16": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - }, - "dependencies": { - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - } - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", - "integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", - "requires": { - "caniuse-lite": "^1.0.30001274", - "electron-to-chromium": "^1.3.886", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "buble-jsx-only": { - "version": "0.19.8", - "resolved": "https://registry.npmjs.org/buble-jsx-only/-/buble-jsx-only-0.19.8.tgz", - "integrity": "sha512-7AW19pf7PrKFnGTEDzs6u9+JZqQwM1VnLS19OlqYDhXomtFFknnoQJAPHeg84RMFWAvOhYrG7harizJNwUKJsA==", - "requires": { - "acorn": "^6.1.1", - "acorn-dynamic-import": "^4.0.0", - "acorn-jsx": "^5.0.1", - "chalk": "^2.4.2", - "magic-string": "^0.25.3", - "minimist": "^1.2.0", - "regexpu-core": "^4.5.4" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" - }, - "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==" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001275", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001275.tgz", - "integrity": "sha512-ihJVvj8RX0kn9GgP43HKhb5q9s2XQn4nEQhdldEJvZhCsuiB2XOq6fAMYQZaN6FPWfsr2qU0cdL0CSbETwbJAg==" - }, - "ccount": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", - "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.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==", - "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==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "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==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" - }, - "character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" - }, - "character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" - }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", - "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" - }, - "dependencies": { - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" - } - }, - "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" - }, - "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", - "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "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" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" - }, - "ci-info": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", - "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-css": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", - "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - } - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "clsx": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", - "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "collapse-white-space": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", - "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.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==", - "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=" - }, - "colord": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.1.tgz", - "integrity": "sha512-4LBMSt09vR0uLnPVkOUBnmxgoaeN4ewRbx801wY/bXcltXfpR/G46OdWn96XpYmCWuYvO46aBZP4NgX8HpNAcw==" - }, - "combine-promises": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz", - "integrity": "sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg==" - }, - "comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" - }, - "consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "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==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "copy-text-to-clipboard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz", - "integrity": "sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q==" - }, - "copy-webpack-plugin": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz", - "integrity": "sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==", - "requires": { - "fast-glob": "^3.2.5", - "glob-parent": "^6.0.0", - "globby": "^11.0.3", - "normalize-path": "^3.0.0", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^6.0.0" - }, - "dependencies": { - "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==", - "requires": { - "is-glob": "^4.0.3" - } - } - } - }, - "core-js": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.19.1.tgz", - "integrity": "sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg==" - }, - "core-js-compat": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.19.1.tgz", - "integrity": "sha512-Q/VJ7jAF/y68+aUsQJ/afPOewdsGkDtcMb40J8MbuWKlK3Y+wtHq8bTHKPj2WKWLIqmS5JhHs4CzHtz6pT2W6g==", - "requires": { - "browserslist": "^4.17.6", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } - }, - "core-js-pure": { - "version": "3.19.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz", - "integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ==" - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "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" - } - }, - "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "requires": { - "node-fetch": "2.6.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" - }, - "css-color-names": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", - "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==" - }, - "css-declaration-sorter": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz", - "integrity": "sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA==", - "requires": { - "timsort": "^0.3.0" - } - }, - "css-loader": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz", - "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==", - "requires": { - "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" - } - }, - "css-minimizer-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-KlB8l5uoNcf9F7i5kXnkxoqJGd2BXH4f0+Lj2vSWSmuvMLYO1kNsJ1KHSzeDW8e45/whgSOPcKVT/3JopkT8dg==", - "requires": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "p-limit": "^3.0.2", - "postcss": "^8.3.5", - "schema-utils": "^3.1.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "cssnano": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.9.tgz", - "integrity": "sha512-Y4olTKBKsPKl5izpcXHRDiB/1rVdbIDM4qVXgEKBt466kYT42SEEsnCYOQFFXzEkUYV8pJNCII9JKzb8KfDk+g==", - "requires": { - "cssnano-preset-default": "^5.1.5", - "is-resolvable": "^1.1.0", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "cssnano-preset-advanced": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-5.1.5.tgz", - "integrity": "sha512-1u66ijw1aYyxxr9F2nFlBGS3UlzsRHUrGxVYf1CLiYZhvkcuX/+NHkgyO4P9da/j2C2Y2EvMsqk9Nd4VZkZ9jA==", - "requires": { - "autoprefixer": "^10.3.7", - "cssnano-preset-default": "^5.1.5", - "postcss-discard-unused": "^5.0.1", - "postcss-merge-idents": "^5.0.1", - "postcss-reduce-idents": "^5.0.1", - "postcss-zindex": "^5.0.1" - } - }, - "cssnano-preset-default": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.5.tgz", - "integrity": "sha512-fF00UI+d3PWkGfMd62geqmoUe5h+LOhGE2GH4Fqq3beNKdCU1LWwLUyIcu4/A72lWv0737cHey5zhhWw3rW0sA==", - "requires": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^2.0.1", - "postcss-calc": "^8.0.0", - "postcss-colormin": "^5.2.1", - "postcss-convert-values": "^5.0.2", - "postcss-discard-comments": "^5.0.1", - "postcss-discard-duplicates": "^5.0.1", - "postcss-discard-empty": "^5.0.1", - "postcss-discard-overridden": "^5.0.1", - "postcss-merge-longhand": "^5.0.2", - "postcss-merge-rules": "^5.0.2", - "postcss-minify-font-values": "^5.0.1", - "postcss-minify-gradients": "^5.0.3", - "postcss-minify-params": "^5.0.1", - "postcss-minify-selectors": "^5.1.0", - "postcss-normalize-charset": "^5.0.1", - "postcss-normalize-display-values": "^5.0.1", - "postcss-normalize-positions": "^5.0.1", - "postcss-normalize-repeat-style": "^5.0.1", - "postcss-normalize-string": "^5.0.1", - "postcss-normalize-timing-functions": "^5.0.1", - "postcss-normalize-unicode": "^5.0.1", - "postcss-normalize-url": "^5.0.2", - "postcss-normalize-whitespace": "^5.0.1", - "postcss-ordered-values": "^5.0.2", - "postcss-reduce-initial": "^5.0.1", - "postcss-reduce-transforms": "^5.0.1", - "postcss-svgo": "^5.0.3", - "postcss-unique-selectors": "^5.0.1" - } - }, - "cssnano-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz", - "integrity": "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ==" - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "requires": { - "css-tree": "^1.1.2" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" - }, - "default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - } - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detab": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz", - "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==", - "requires": { - "repeat-string": "^1.5.4" - } - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "detect-port": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz", - "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==", - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "domhandler": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz", - "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "electron-to-chromium": { - "version": "1.3.887", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.887.tgz", - "integrity": "sha512-QQUumrEjFDKSVYVdaeBmFdyQGoaV+fCSMyWHvfx/u22bRHSTeBQYt6P4jMY+gFd4kgKB9nqk7RMtWkDB49OYPA==" - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" - }, - "emoticon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-3.2.0.tgz", - "integrity": "sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "requires": { - "prr": "~1.0.1" - } - }, - "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==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "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=" - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "eta": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.3.tgz", - "integrity": "sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eval": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.6.tgz", - "integrity": "sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ==", - "requires": { - "require-like": ">= 0.1.1" - } - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "eventsource": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", - "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", - "requires": { - "original": "^1.0.0" - } - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "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" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-url-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", - "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", - "requires": { - "punycode": "^1.3.2" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "requires": { - "reusify": "^1.0.4" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fbemitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", - "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", - "requires": { - "fbjs": "^3.0.0" - } - }, - "fbjs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.1.tgz", - "integrity": "sha512-8+vkGyT4lNDRKHQNPp0yh/6E7FfkLg89XqQbOYnvntRh+8RiSD43yrh9E5ejp1muCizTL4nDVG+y8W4e+LROHg==", - "requires": { - "cross-fetch": "^3.0.4", - "fbjs-css-vars": "^1.0.0", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.30" - } - }, - "fbjs-css-vars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", - "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" - }, - "feed": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", - "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", - "requires": { - "xml-js": "^1.6.11" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true - }, - "filesize": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz", - "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg==" - }, - "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==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "flux": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.2.tgz", - "integrity": "sha512-u/ucO5ezm3nBvdaSGkWpDlzCePoV+a9x3KHmy13TV/5MzOaCZDN8Mfd94jmf0nOi8ZZay+nOKbBUkOe2VNaupQ==", - "requires": { - "fbemitter": "^3.0.0", - "fbjs": "^3.0.0" - } - }, - "follow-redirects": { - "version": "1.14.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz", - "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==" - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "fork-ts-checker-webpack-plugin": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz", - "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==", - "requires": { - "@babel/code-frame": "^7.5.5", - "chalk": "^2.4.1", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "semver": "^5.6.0", - "tapable": "^1.0.0", - "worker-rpc": "^0.1.0" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.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==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fraction.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz", - "integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "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==" - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "github-slugger": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==" - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "requires": { - "ini": "2.0.0" - }, - "dependencies": { - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==" - } - } - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" - }, - "gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "requires": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - } - }, - "gzip-size": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", - "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", - "requires": { - "duplexer": "^0.1.1", - "pify": "^4.0.1" - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" - }, - "hast-to-hyperscript": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz", - "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==", - "requires": { - "@types/unist": "^2.0.3", - "comma-separated-tokens": "^1.0.0", - "property-information": "^5.3.0", - "space-separated-tokens": "^1.0.0", - "style-to-object": "^0.3.0", - "unist-util-is": "^4.0.0", - "web-namespaces": "^1.0.0" - } - }, - "hast-util-from-parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz", - "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==", - "requires": { - "@types/parse5": "^5.0.0", - "hastscript": "^6.0.0", - "property-information": "^5.0.0", - "vfile": "^4.0.0", - "vfile-location": "^3.2.0", - "web-namespaces": "^1.0.0" - } - }, - "hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" - }, - "hast-util-raw": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz", - "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==", - "requires": { - "@types/hast": "^2.0.0", - "hast-util-from-parse5": "^6.0.0", - "hast-util-to-parse5": "^6.0.0", - "html-void-elements": "^1.0.0", - "parse5": "^6.0.0", - "unist-util-position": "^3.0.0", - "vfile": "^4.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - } - }, - "hast-util-to-parse5": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", - "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==", - "requires": { - "hast-to-hyperscript": "^9.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.0.0", - "xtend": "^4.0.0", - "zwitch": "^1.0.0" - } - }, - "hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", - "requires": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - } - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" - }, - "html-minifier-terser": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.0.2.tgz", - "integrity": "sha512-AgYO3UGhMYQx2S/FBJT3EM0ZYcKmH6m9XL9c1v77BeK/tYJxGPxT1/AtsdUi4FcP8kZGmqqnItCcjFPcX9hk6A==", - "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.1.5", - "commander": "^8.1.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.7.2" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" - } - } - }, - "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==" - }, - "html-void-elements": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", - "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==" - }, - "html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", - "requires": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - } - }, - "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - } - } - }, - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - } - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } - } - }, - "http-parser-js": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", - "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==" - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", - "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", - "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" - }, - "dependencies": { - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - } - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==" - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" - }, - "immer": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz", - "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - } - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "infima": { - "version": "0.2.0-alpha.34", - "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.34.tgz", - "integrity": "sha512-Na6A2Tl56i1p9dzu7VOAT1Kmu3f5buz63Wvd+D9ZZWL6siQ47L7wkEZUICVKFgc5gERFZVZ/PoPB57Kl++h37Q==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inline-style-parser": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", - "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" - }, - "internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-absolute-url": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", - "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" - }, - "is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "requires": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "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==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "requires": { - "ci-info": "^2.0.0" - }, - "dependencies": { - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" - } - } - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" - }, - "is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", - "requires": { - "is-path-inside": "^2.1.0" - }, - "dependencies": { - "is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", - "requires": { - "path-is-inside": "^1.0.2" - } - } - } - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-weakref": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", - "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", - "requires": { - "call-bind": "^1.0.0" - } - }, - "is-whitespace-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz", - "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "is-word-character": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz", - "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==" - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "requires": { - "is-docker": "^2.0.0" - } - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "jest-worker": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", - "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "joi": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.2.tgz", - "integrity": "sha512-Lm56PP+n0+Z2A2rfRvsfWVDXGEWjXxatPopkQ8qQ5mxCEhwHG+Ettgg5o98FFaxilOxozoa14cFhrE/hOzh/Nw==", - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.0", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "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==" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, - "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==", - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "requires": { - "json-buffer": "3.0.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, - "klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "requires": { - "package-json": "^6.3.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" - }, - "lilconfig": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz", - "integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==" - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" - }, - "loader-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.1.tgz", - "integrity": "sha512-g4miPa9uUrZz4iElkaVJgDFwKJGh8aQGM7pUL4ejXl6cu7kSb30seQOVGNMP6sW8j7DW77X68hJZ+GM7UGhXeQ==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" - }, - "lodash.bind": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" - }, - "lodash.curry": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" - }, - "lodash.filter": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", - "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" - }, - "lodash.flow": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.map": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", - "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" - }, - "lodash.reduce": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", - "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" - }, - "lodash.reject": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", - "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" - }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "requires": { - "tslib": "^2.0.3" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "markdown-escapes": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", - "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==" - }, - "mdast-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==", - "requires": { - "unist-util-remove": "^2.0.0" - } - }, - "mdast-util-definitions": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", - "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==", - "requires": { - "unist-util-visit": "^2.0.0" - } - }, - "mdast-util-to-hast": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz", - "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==", - "requires": { - "@types/mdast": "^3.0.0", - "@types/unist": "^2.0.0", - "mdast-util-definitions": "^4.0.0", - "mdurl": "^1.0.0", - "unist-builder": "^2.0.0", - "unist-util-generated": "^1.0.0", - "unist-util-position": "^3.0.0", - "unist-util-visit": "^2.0.0" - } - }, - "mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "microevent.ts": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz", - "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==" - }, - "mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", - "requires": { - "mime-db": "1.50.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - }, - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - }, - "mini-css-extract-plugin": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz", - "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==", - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "webpack-sources": "^1.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "module-alias": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", - "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "optional": true - }, - "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node-emoji": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", - "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", - "requires": { - "lodash": "^4.17.21" - } - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, - "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - } - } - }, - "nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E=" - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" - }, - "opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", - "requires": { - "is-wsl": "^1.1.0" - }, - "dependencies": { - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" - } - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "requires": { - "url-parse": "^1.4.3" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", - "requires": { - "retry": "^0.12.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "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==", - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.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==", - "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" - } - }, - "parse-numeric-range": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", - "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==" - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "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==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "requires": { - "find-up": "^4.0.0" - } - }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "requires": { - "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "postcss": { - "version": "8.3.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz", - "integrity": "sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==", - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^0.6.2" - } - }, - "postcss-calc": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.0.0.tgz", - "integrity": "sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g==", - "requires": { - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "postcss-colormin": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.1.tgz", - "integrity": "sha512-VVwMrEYLcHYePUYV99Ymuoi7WhKrMGy/V9/kTS0DkCoJYmmjdOMneyhzYUxcNgteKDVbrewOkSM7Wje/MFwxzA==", - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-convert-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz", - "integrity": "sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-discard-comments": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz", - "integrity": "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg==" - }, - "postcss-discard-duplicates": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz", - "integrity": "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA==" - }, - "postcss-discard-empty": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz", - "integrity": "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw==" - }, - "postcss-discard-overridden": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz", - "integrity": "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q==" - }, - "postcss-discard-unused": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-5.0.1.tgz", - "integrity": "sha512-tD6xR/xyZTwfhKYRw0ylfCY8wbfhrjpKAMnDKRTLMy2fNW5hl0hoV6ap5vo2JdCkuHkP3CHw72beO4Y8pzFdww==", - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.0.tgz", - "integrity": "sha512-H9hv447QjQJVDbHj3OUdciyAXY3v5+UDduzEytAlZCVHCpNAAg/mCSwhYYqZr9BiGYhmYspU8QXxZwiHTLn3yA==", - "requires": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.4", - "semver": "^7.3.5" - } - }, - "postcss-merge-idents": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-5.0.1.tgz", - "integrity": "sha512-xu8ueVU0RszbI2gKkxR6mluupsOSSLvt8q4gA2fcKFkA+x6SlH3cb4cFHpDvcRCNFbUmCR/VUub+Y6zPOjPx+Q==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-merge-longhand": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz", - "integrity": "sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw==", - "requires": { - "css-color-names": "^1.0.1", - "postcss-value-parser": "^4.1.0", - "stylehacks": "^5.0.1" - } - }, - "postcss-merge-rules": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz", - "integrity": "sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg==", - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^2.0.1", - "postcss-selector-parser": "^6.0.5", - "vendors": "^1.0.3" - } - }, - "postcss-minify-font-values": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz", - "integrity": "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-minify-gradients": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz", - "integrity": "sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q==", - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-minify-params": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz", - "integrity": "sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw==", - "requires": { - "alphanum-sort": "^1.0.2", - "browserslist": "^4.16.0", - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0", - "uniqs": "^2.0.0" - } - }, - "postcss-minify-selectors": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz", - "integrity": "sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og==", - "requires": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==" - }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-normalize-charset": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz", - "integrity": "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg==" - }, - "postcss-normalize-display-values": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz", - "integrity": "sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-positions": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz", - "integrity": "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz", - "integrity": "sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-string": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz", - "integrity": "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz", - "integrity": "sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-unicode": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz", - "integrity": "sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA==", - "requires": { - "browserslist": "^4.16.0", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-url": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz", - "integrity": "sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ==", - "requires": { - "is-absolute-url": "^3.0.3", - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-normalize-whitespace": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz", - "integrity": "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-ordered-values": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz", - "integrity": "sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-reduce-idents": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-5.0.1.tgz", - "integrity": "sha512-6Rw8iIVFbqtaZExgWK1rpVgP7DPFRPh0DDFZxJ/ADNqPiH10sPCoq5tgo6kLiTyfh9sxjKYjXdc8udLEcPOezg==", - "requires": { - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-reduce-initial": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz", - "integrity": "sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw==", - "requires": { - "browserslist": "^4.16.0", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz", - "integrity": "sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA==", - "requires": { - "cssnano-utils": "^2.0.1", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-sort-media-queries": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.1.0.tgz", - "integrity": "sha512-pPiw94cMOqGFSlp4QGzOKrhYr8O3VyMNQnb7qlGM25H4EDEii3iKtIUMoFe5gKiCEAt/Iyk2ah47eoRhGqSBGA==", - "requires": { - "sort-css-media-queries": "2.0.4" - } - }, - "postcss-svgo": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.3.tgz", - "integrity": "sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA==", - "requires": { - "postcss-value-parser": "^4.1.0", - "svgo": "^2.7.0" - } - }, - "postcss-unique-selectors": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz", - "integrity": "sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w==", - "requires": { - "alphanum-sort": "^1.0.2", - "postcss-selector-parser": "^6.0.5", - "uniqs": "^2.0.0" - } - }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" - }, - "postcss-zindex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-5.0.1.tgz", - "integrity": "sha512-nwgtJJys+XmmSGoYCcgkf/VczP8Mp/0OfSv3v0+fw0uABY4yxw+eFs0Xp9nAZHIKnS5j+e9ywQ+RD+ONyvl5pA==" - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" - }, - "pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "requires": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" - }, - "prism-react-renderer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz", - "integrity": "sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg==" - }, - "prismjs": { - "version": "1.25.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", - "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "requires": { - "asap": "~2.0.3" - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "requires": { - "xtend": "^4.0.0" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "requires": { - "escape-goat": "^2.0.0" - } - }, - "pure-color": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "react-base16-styling": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz", - "integrity": "sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=", - "requires": { - "base16": "^1.0.0", - "lodash.curry": "^4.0.1", - "lodash.flow": "^3.3.0", - "pure-color": "^1.2.0" - } - }, - "react-dev-utils": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz", - "integrity": "sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A==", - "requires": { - "@babel/code-frame": "7.10.4", - "address": "1.1.2", - "browserslist": "4.14.2", - "chalk": "2.4.2", - "cross-spawn": "7.0.3", - "detect-port-alt": "1.1.6", - "escape-string-regexp": "2.0.0", - "filesize": "6.1.0", - "find-up": "4.1.0", - "fork-ts-checker-webpack-plugin": "4.1.6", - "global-modules": "2.0.0", - "globby": "11.0.1", - "gzip-size": "5.1.1", - "immer": "8.0.1", - "is-root": "2.1.0", - "loader-utils": "2.0.0", - "open": "^7.0.2", - "pkg-up": "3.1.0", - "prompts": "2.4.0", - "react-error-overlay": "^6.0.9", - "recursive-readdir": "2.2.2", - "shell-quote": "1.7.2", - "strip-ansi": "6.0.0", - "text-table": "0.2.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "browserslist": { - "version": "4.14.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz", - "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==", - "requires": { - "caniuse-lite": "^1.0.30001125", - "electron-to-chromium": "^1.3.564", - "escalade": "^3.0.2", - "node-releases": "^1.1.61" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "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=" - } - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - } - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - }, - "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" - }, - "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, - "react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - } - }, - "react-error-overlay": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz", - "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==" - }, - "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" - }, - "react-helmet": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", - "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", - "requires": { - "object-assign": "^4.1.1", - "prop-types": "^15.7.2", - "react-fast-compare": "^3.1.1", - "react-side-effect": "^2.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "react-json-view": { - "version": "1.21.3", - "resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz", - "integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==", - "requires": { - "flux": "^4.0.1", - "react-base16-styling": "^0.6.0", - "react-lifecycles-compat": "^3.0.4", - "react-textarea-autosize": "^8.3.2" - } - }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "react-loadable": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/react-loadable/-/react-loadable-5.5.0.tgz", - "integrity": "sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==", - "requires": { - "prop-types": "^15.5.0" - } - }, - "react-loadable-ssr-addon-v5-slorber": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", - "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", - "requires": { - "@babel/runtime": "^7.10.3" - } - }, - "react-router": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", - "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - } - } - }, - "react-router-config": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", - "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", - "requires": { - "@babel/runtime": "^7.1.2" - } - }, - "react-router-dom": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", - "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", - "requires": { - "@babel/runtime": "^7.12.13", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.1", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - } - }, - "react-side-effect": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz", - "integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==" - }, - "react-textarea-autosize": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz", - "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", - "requires": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.0.0", - "use-latest": "^1.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "reading-time": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", - "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "requires": { - "resolve": "^1.1.6" - } - }, - "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", - "requires": { - "minimatch": "3.0.4" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "requires": { - "rc": "^1.2.8" - } - }, - "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" - }, - "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "rehype-parse": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-6.0.2.tgz", - "integrity": "sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug==", - "requires": { - "hast-util-from-parse5": "^5.0.0", - "parse5": "^5.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "hast-util-from-parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz", - "integrity": "sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA==", - "requires": { - "ccount": "^1.0.3", - "hastscript": "^5.0.0", - "property-information": "^5.0.0", - "web-namespaces": "^1.1.2", - "xtend": "^4.0.1" - } - }, - "hastscript": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz", - "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==", - "requires": { - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" - }, - "remark-admonitions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/remark-admonitions/-/remark-admonitions-1.2.1.tgz", - "integrity": "sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow==", - "requires": { - "rehype-parse": "^6.0.2", - "unified": "^8.4.2", - "unist-util-visit": "^2.0.1" - }, - "dependencies": { - "unified": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/unified/-/unified-8.4.2.tgz", - "integrity": "sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA==", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - } - } - }, - "remark-emoji": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-2.2.0.tgz", - "integrity": "sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w==", - "requires": { - "emoticon": "^3.2.0", - "node-emoji": "^1.10.0", - "unist-util-visit": "^2.0.3" - } - }, - "remark-footnotes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz", - "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==" - }, - "remark-mdx": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz", - "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==", - "requires": { - "@babel/core": "7.12.9", - "@babel/helper-plugin-utils": "7.10.4", - "@babel/plugin-proposal-object-rest-spread": "7.12.1", - "@babel/plugin-syntax-jsx": "7.12.1", - "@mdx-js/util": "1.6.22", - "is-alphabetical": "1.0.4", - "remark-parse": "8.0.3", - "unified": "9.2.0" - }, - "dependencies": { - "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz", - "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "remark-mdx-remove-exports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-exports/-/remark-mdx-remove-exports-1.6.22.tgz", - "integrity": "sha512-7g2uiTmTGfz5QyVb+toeX25frbk1Y6yd03RXGPtqx0+DVh86Gb7MkNYbk7H2X27zdZ3CQv1W/JqlFO0Oo8IxVA==", - "requires": { - "unist-util-remove": "2.0.0" - }, - "dependencies": { - "unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", - "requires": { - "unist-util-is": "^4.0.0" - } - } - } - }, - "remark-mdx-remove-imports": { - "version": "1.6.22", - "resolved": "https://registry.npmjs.org/remark-mdx-remove-imports/-/remark-mdx-remove-imports-1.6.22.tgz", - "integrity": "sha512-lmjAXD8Ltw0TsvBzb45S+Dxx7LTJAtDaMneMAv8LAUIPEyYoKkmGbmVsiF0/pY6mhM1Q16swCmu1TN+ie/vn/A==", - "requires": { - "unist-util-remove": "2.0.0" - }, - "dependencies": { - "unist-util-remove": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.0.0.tgz", - "integrity": "sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g==", - "requires": { - "unist-util-is": "^4.0.0" - } - } - } - }, - "remark-parse": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", - "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==", - "requires": { - "ccount": "^1.0.0", - "collapse-white-space": "^1.0.2", - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-whitespace-character": "^1.0.0", - "is-word-character": "^1.0.0", - "markdown-escapes": "^1.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.5.4", - "state-toggle": "^1.0.0", - "trim": "0.0.1", - "trim-trailing-lines": "^1.0.0", - "unherit": "^1.0.4", - "unist-util-remove-position": "^2.0.0", - "vfile-location": "^3.0.0", - "xtend": "^4.0.1" - } - }, - "remark-squeeze-paragraphs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz", - "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==", - "requires": { - "mdast-squeeze-paragraphs": "^4.0.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - } - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-like": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", - "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - } - } - }, - "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==" - }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, - "rtl-detect": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", - "integrity": "sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==" - }, - "rtlcss": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", - "integrity": "sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A==", - "requires": { - "find-up": "^5.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.3.11", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "requires": { - "p-limit": "^3.0.2" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - } - } - }, - "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==", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", - "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", - "requires": { - "tslib": "~2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" - } - } - }, - "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==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "section-matter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", - "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", - "requires": { - "extend-shallow": "^2.0.1", - "kind-of": "^6.0.0" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "selfsigned": { - "version": "1.10.11", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", - "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-handler": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz", - "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==", - "requires": { - "bytes": "3.0.0", - "content-disposition": "0.5.2", - "fast-url-parser": "1.1.3", - "mime-types": "2.1.18", - "minimatch": "3.0.4", - "path-is-inside": "1.0.2", - "path-to-regexp": "2.2.1", - "range-parser": "1.2.0" - }, - "dependencies": { - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "requires": { - "mime-db": "~1.33.0" - } - }, - "path-to-regexp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", - "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==" - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - } - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==" - }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==" - }, - "sirv": { - "version": "1.0.18", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.18.tgz", - "integrity": "sha512-f2AOPogZmXgJ9Ma2M22ZEhc1dNtRIzcEkiflMFeVTRq+OViOZMvH1IPMVOwrKaxpSaHioBJiDR0SluRqGa7atA==", - "requires": { - "@polka/url": "^1.0.0-next.20", - "mime": "^2.3.1", - "totalist": "^1.0.0" - }, - "dependencies": { - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" - } - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, - "sitemap": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.0.0.tgz", - "integrity": "sha512-Ud0jrRQO2k7fEtPAM+cQkBKoMvxQyPKNXKDLn8tRVHxRCsdDQ2JZvw+aZ5IRYYQVAV9iGxEar6boTwZzev+x3g==", - "requires": { - "@types/node": "^15.0.1", - "@types/sax": "^1.2.1", - "arg": "^5.0.0", - "sax": "^1.2.4" - }, - "dependencies": { - "@types/node": { - "version": "15.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", - "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==" - } - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "sockjs": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", - "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", - "websocket-driver": "^0.7.4" - } - }, - "sockjs-client": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", - "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", - "requires": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", - "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.3" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "sort-css-media-queries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz", - "integrity": "sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw==" - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==" - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" - }, - "space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "state-toggle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz", - "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==" - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "std-env": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.3.1.tgz", - "integrity": "sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g==", - "requires": { - "ci-info": "^3.1.1" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "dependencies": { - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - } - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", - "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "style-to-object": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", - "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", - "requires": { - "inline-style-parser": "0.1.1" - } - }, - "stylehacks": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz", - "integrity": "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA==", - "requires": { - "browserslist": "^4.16.0", - "postcss-selector-parser": "^6.0.4" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" - }, - "svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - } - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" - }, - "terser": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.9.0.tgz", - "integrity": "sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ==", - "requires": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } - } - }, - "terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", - "requires": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, - "tiny-invariant": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", - "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, - "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=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" - }, - "trim": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", - "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=" - }, - "trim-trailing-lines": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz", - "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==" - }, - "trough": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", - "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" - }, - "ts-essentials": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==" - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unherit": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", - "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==", - "requires": { - "inherits": "^2.0.0", - "xtend": "^4.0.0" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" - }, - "unified": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz", - "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==", - "requires": { - "bail": "^1.0.0", - "extend": "^3.0.0", - "is-buffer": "^2.0.0", - "is-plain-obj": "^2.0.0", - "trough": "^1.0.0", - "vfile": "^4.0.0" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "unist-builder": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz", - "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==" - }, - "unist-util-generated": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz", - "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==" - }, - "unist-util-is": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", - "integrity": "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" - }, - "unist-util-position": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz", - "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==" - }, - "unist-util-remove": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz", - "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==", - "requires": { - "unist-util-is": "^4.0.0" - } - }, - "unist-util-remove-position": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz", - "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==", - "requires": { - "unist-util-visit": "^2.0.0" - } - }, - "unist-util-stringify-position": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", - "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", - "requires": { - "@types/unist": "^2.0.2" - } - }, - "unist-util-visit": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz", - "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit-parents": "^3.0.0" - } - }, - "unist-util-visit-parents": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz", - "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-is": "^4.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, - "url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", - "requires": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" - } - }, - "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "requires": { - "prepend-http": "^2.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "use-composed-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", - "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", - "requires": { - "ts-essentials": "^2.0.3" - } - }, - "use-isomorphic-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==" - }, - "use-latest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", - "requires": { - "use-isomorphic-layout-effect": "^1.0.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" - }, - "utility-types": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.10.0.tgz", - "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" - }, - "vfile": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", - "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==", - "requires": { - "@types/unist": "^2.0.0", - "is-buffer": "^2.0.0", - "unist-util-stringify-position": "^2.0.0", - "vfile-message": "^2.0.0" - } - }, - "vfile-location": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz", - "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==" - }, - "vfile-message": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", - "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", - "requires": { - "@types/unist": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" - } - }, - "wait-on": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz", - "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==", - "requires": { - "axios": "^0.21.1", - "joi": "^17.4.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.1.0" - } - }, - "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "web-namespaces": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", - "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" - }, - "webpack": { - "version": "5.61.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.61.0.tgz", - "integrity": "sha512-fPdTuaYZ/GMGFm4WrPi2KRCqS1vDp773kj9S0iI5Uc//5cszsFEDgHNaX4Rj1vobUiU1dFIV3mA9k1eHeluFpw==", - "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.2.0", - "webpack-sources": "^3.2.0" - } - }, - "webpack-bundle-analyzer": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz", - "integrity": "sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==", - "requires": { - "acorn": "^8.0.4", - "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", - "commander": "^7.2.0", - "gzip-size": "^6.0.0", - "lodash": "^4.17.20", - "opener": "^1.5.2", - "sirv": "^1.0.7", - "ws": "^7.3.1" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" - }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "requires": { - "duplexer": "^0.1.2" - } - } - } - }, - "webpack-dev-middleware": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", - "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", - "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" - }, - "dependencies": { - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" - } - } - }, - "webpack-dev-server": { - "version": "3.11.2", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", - "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", - "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.8", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "sockjs-client": "^1.5.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "^1.0.1" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "ws": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", - "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==" - }, - "webpackbar": { - "version": "5.0.0-3", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.0-3.tgz", - "integrity": "sha512-viW6KCYjMb0NPoDrw2jAmLXU2dEOhRrtku28KmOfeE1vxbfwCYuTbTaMhnkrCZLFAFyY9Q49Z/jzYO80Dw5b8g==", - "requires": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.1.0", - "consola": "^2.15.0", - "figures": "^3.2.0", - "pretty-time": "^1.1.0", - "std-env": "^2.2.1", - "text-table": "^0.2.0", - "wrap-ansi": "^7.0.0" - } - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "requires": { - "string-width": "^4.0.0" - } - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" - }, - "worker-rpc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz", - "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==", - "requires": { - "microevent.ts": "~0.1.1" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.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==", - "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==" - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", - "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==" - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" - }, - "xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "requires": { - "sax": "^1.2.4" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - } - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" - }, - "zwitch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz", - "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" - } - } -} From 6410f7e1fe26d399ac79994e6eb1198ef6a80b86 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Wed, 12 Jan 2022 22:06:56 +0530 Subject: [PATCH 02/95] Update netty-all to 4.1.73.Final (#811) --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 78f2eff392..01979e7170 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -2,7 +2,7 @@ import sbt._ object Dependencies { val JwtCoreVersion = "9.0.3" - val NettyVersion = "4.1.72.Final" + val NettyVersion = "4.1.73.Final" val NettyIncubatorVersion = "0.0.11.Final" val ScalaCompactCollectionVersion = "2.6.0" val ZioVersion = "1.0.13" From 3a348239c8a75bb451f56a9d9484488af6875fbe Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Thu, 13 Jan 2022 16:08:59 +0530 Subject: [PATCH 03/95] Disable benchmarks comment on fork pull request (#820) * Disable benchmarks on fork PR * run benchmarks on fork PR but disbable PR comment --- .github/workflows/ci.yml | 6 +++--- project/BenchmarkWorkFlow.scala | 10 +++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c1f7a6d18..d9d303fffa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -259,15 +259,15 @@ jobs: run: | cp ./zio-http/example/src/main/scala/example/PlainTextBenchmarkServer.scala ./FrameworkBenchMarks/frameworks/Scala/zio-http/src/main/scala/Main.scala cd ./FrameworkBenchMarks - echo ${{github.event.pull_request.head.sha}} - sed -i "s/---COMMIT_SHA---/${{github.event.pull_request.head.sha}}/g" frameworks/Scala/zio-http/build.sbt + sed -i "s/---COMMIT_SHA---/${{github.event.pull_request.head.repo.owner.login}}\/zio-http.git#${{github.event.pull_request.head.sha}}/g" frameworks/Scala/zio-http/build.sbt ./tfb --test zio-http | tee result RESULT_REQUEST=$(echo $(grep -B 1 -A 17 "Concurrency: 256 for plaintext" result) | grep -oiE "requests/sec: [0-9]+.[0-9]+") RESULT_CONCURRENCY=$(echo $(grep -B 1 -A 17 "Concurrency: 256 for plaintext" result) | grep -oiE "concurrency: [0-9]+") echo ::set-output name=request_result::$(echo $RESULT_REQUEST) echo ::set-output name=concurrency_result::$(echo $RESULT_CONCURRENCY) - - uses: peter-evans/commit-comment@v1 + - if: ${{github.event.pull_request.head.repo.full_name == 'dream11/zio-http'}} + uses: peter-evans/commit-comment@v1 with: sha: ${{github.event.pull_request.head.sha}} body: | diff --git a/project/BenchmarkWorkFlow.scala b/project/BenchmarkWorkFlow.scala index b9f277548f..acfd278b00 100644 --- a/project/BenchmarkWorkFlow.scala +++ b/project/BenchmarkWorkFlow.scala @@ -7,7 +7,9 @@ object BenchmarkWorkFlow { id = "runBenchMarks", name = "Benchmarks", oses = List("centos"), - cond = Some("${{ github.event_name == 'pull_request'}}"), + cond = Some( + "${{ github.event_name == 'pull_request'}}", + ), steps = List( WorkflowStep.Run( env = Map("GITHUB_TOKEN" -> "${{secrets.ACTIONS_PAT}}"), @@ -34,8 +36,7 @@ object BenchmarkWorkFlow { commands = List( "cp ./zio-http/example/src/main/scala/example/PlainTextBenchmarkServer.scala ./FrameworkBenchMarks/frameworks/Scala/zio-http/src/main/scala/Main.scala", "cd ./FrameworkBenchMarks", - "echo ${{github.event.pull_request.head.sha}}", - """sed -i "s/---COMMIT_SHA---/${{github.event.pull_request.head.sha}}/g" frameworks/Scala/zio-http/build.sbt""", + """sed -i "s/---COMMIT_SHA---/${{github.event.pull_request.head.repo.owner.login}}\/zio-http.git#${{github.event.pull_request.head.sha}}/g" frameworks/Scala/zio-http/build.sbt""", "./tfb --test zio-http | tee result", """RESULT_REQUEST=$(echo $(grep -B 1 -A 17 "Concurrency: 256 for plaintext" result) | grep -oiE "requests/sec: [0-9]+.[0-9]+")""", """RESULT_CONCURRENCY=$(echo $(grep -B 1 -A 17 "Concurrency: 256 for plaintext" result) | grep -oiE "concurrency: [0-9]+")""", @@ -45,6 +46,9 @@ object BenchmarkWorkFlow { ), WorkflowStep.Use( ref = UseRef.Public("peter-evans", "commit-comment", "v1"), + cond = Some( + "${{github.event.pull_request.head.repo.full_name == 'dream11/zio-http'}}", + ), params = Map( "sha" -> "${{github.event.pull_request.head.sha}}", "body" -> From 66a1dea7ba9831cba214963e56b3988c45958d13 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Thu, 13 Jan 2022 18:19:29 +0530 Subject: [PATCH 04/95] Feature: API to modify headers (#824) * feat(Headers):added new api to update headers * renamed api --- zio-http/src/main/scala/zhttp/http/Headers.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index 84a21f36bb..fb03c41b10 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -26,6 +26,8 @@ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList + def modify(f: Header => Header): Headers = Headers(toChunk.map(f(_))) + override def updateHeaders(update: Headers => Headers): Headers = update(self) def when(cond: Boolean): Headers = if (cond) self else Headers.empty From 143ad28aca773503d78ffa2fa5a278f323cadf28 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Thu, 13 Jan 2022 19:31:58 +0530 Subject: [PATCH 05/95] Feature: Signed Cookie (#751) * feat(cookie): added secret in cookie * feat(cookie): added signcookie middleware * feat(cookie): scalafmt * fix(cookie): sign cookie while encoding * scalafmt * fix(Cookie): added unsign method for cookie * fix(cookie): minor changes * fix(signCookieMiddleware: simplified signCookies * fix(cookie): removed try catch from signContent * cookie: throw error in verify * cookie: throw error in verify * verify method changes * fixed test cases * fix: removed decodeResponseSignedCookie * fix: middlewareSpec * added modifyheaders in middleware * removed unwanted changes * scalafmt * refactoring * refactoring * build fix * build fix * fix: decodeResponseCookie * added modify --- .../src/main/scala/example/SignCookies.scala | 23 +++++ .../src/main/scala/zhttp/http/Cookie.scala | 90 +++++++++++++++---- .../main/scala/zhttp/http/Middleware.scala | 18 ++++ .../zhttp/http/headers/HeaderGetters.scala | 4 +- .../test/scala/zhttp/http/CookieSpec.scala | 6 +- .../test/scala/zhttp/internal/HttpGen.scala | 3 +- .../zhttp/middleware/MiddlewareSpec.scala | 7 ++ 7 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 example/src/main/scala/example/SignCookies.scala diff --git a/example/src/main/scala/example/SignCookies.scala b/example/src/main/scala/example/SignCookies.scala new file mode 100644 index 0000000000..5df689905a --- /dev/null +++ b/example/src/main/scala/example/SignCookies.scala @@ -0,0 +1,23 @@ +package example + +import zhttp.http.{Cookie, Method, Response, _} +import zhttp.service.Server +import zio.duration.durationInt +import zio.{App, ExitCode, URIO} + +/** + * Example to make app using signed-cookies + */ +object SignCookies extends App { + + // Setting cookies with an expiry of 5 days + private val cookie = Cookie("key", "hello").withMaxAge(5 days) + + private val app = Http.collect[Request] { case Method.GET -> !! / "cookie" => + Response.ok.addCookie(cookie.sign("secret")) + } + + // Run it like any simple app + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app).exitCode +} diff --git a/zio-http/src/main/scala/zhttp/http/Cookie.scala b/zio-http/src/main/scala/zhttp/http/Cookie.scala index 4ecdc3e883..024b434838 100644 --- a/zio-http/src/main/scala/zhttp/http/Cookie.scala +++ b/zio-http/src/main/scala/zhttp/http/Cookie.scala @@ -2,7 +2,11 @@ package zhttp.http import zio.duration._ +import java.security.MessageDigest import java.time.Instant +import java.util.Base64.getEncoder +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec import scala.util.Try final case class Cookie( @@ -15,6 +19,7 @@ final case class Cookie( isHttpOnly: Boolean = false, maxAge: Option[Long] = None, sameSite: Option[Cookie.SameSite] = None, + secret: Option[String] = None, ) { self => /** @@ -68,6 +73,16 @@ final case class Cookie( */ def withSameSite(v: Cookie.SameSite): Cookie = copy(sameSite = Some(v)) + /** + * Signs the cookie at the time of encoding using the provided secret. + */ + def sign(secret: String): Cookie = copy(secret = Some(secret)) + + /** + * Removes secret in the cookie + */ + def unSign: Cookie = copy(secret = None) + /** * Resets secure flag in the cookie */ @@ -107,8 +122,13 @@ final case class Cookie( * Converts cookie into a string */ def encode: String = { + val c = secret match { + case Some(sec) => content + "." + signContent(sec) + case None => content + } + val cookie = List( - Some(s"$name=$content"), + Some(s"$name=$c"), expires.map(e => s"Expires=$e"), maxAge.map(a => s"Max-Age=${a.toString}"), domain.map(d => s"Domain=$d"), @@ -120,6 +140,24 @@ final case class Cookie( cookie.flatten.mkString("; ") } + /** + * Signs cookie content with a secret and returns signature + */ + private def signContent(secret: String): String = { + val sha256 = Mac.getInstance("HmacSHA256") + val secretKey = new SecretKeySpec(secret.getBytes(), "RSA") + sha256.init(secretKey) + val signed = sha256.doFinal(self.content.getBytes()) + val mda = MessageDigest.getInstance("SHA-512") + getEncoder.encodeToString(mda.digest(signed)) + } + + /** + * Verifies signed-cookie's signature with a secret + */ + private def verify(content: String, signature: String, secret: String): Boolean = + self.withContent(content).signContent(secret) == signature + } object Cookie { @@ -147,10 +185,10 @@ object Cookie { /** * Decodes from Set-Cookie header value inside of Response into a cookie */ - def decodeResponseCookie(headerValue: String): Option[Cookie] = - Try(unsafeDecodeResponseCookie(headerValue)).toOption + def decodeResponseCookie(headerValue: String, secret: Option[String] = None): Option[Cookie] = + Try(unsafeDecodeResponseCookie(headerValue, secret)).toOption - private[zhttp] def unsafeDecodeResponseCookie(headerValue: String): Cookie = { + private[zhttp] def unsafeDecodeResponseCookie(headerValue: String, secret: Option[String] = None): Cookie = { var name: String = null var content: String = null var expires: Instant = null @@ -214,21 +252,37 @@ object Cookie { curr = next + 1 } } + val decodedCookie = + if ((name != null && !name.isEmpty) || (content != null && !content.isEmpty)) + Cookie( + name = name, + content = content, + expires = Option(expires), + maxAge = maxAge, + domain = Option(domain), + path = Option(path), + isSecure = secure, + isHttpOnly = httpOnly, + sameSite = Option(sameSite), + ) + else + null + + secret match { + case Some(s) => { + if (decodedCookie != null) { + val index = decodedCookie.content.lastIndexOf('.') + val signature = decodedCookie.content.slice(index + 1, decodedCookie.content.length) + val content = decodedCookie.content.slice(0, index) + + if (decodedCookie.verify(content, signature, s)) + decodedCookie.withContent(content).sign(s) + else null + } else decodedCookie + } + case None => decodedCookie + } - if ((name != null && !name.isEmpty) || (content != null && !content.isEmpty)) - Cookie( - name = name, - content = content, - expires = Option(expires), - maxAge = maxAge, - domain = Option(domain), - path = Option(path), - isSecure = secure, - isHttpOnly = httpOnly, - sameSite = Option(sameSite), - ) - else - null } /** diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index c1e55d02bf..7b6776b62b 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -1,6 +1,7 @@ package zhttp.http import io.netty.handler.codec.http.HttpHeaderNames +import io.netty.util.AsciiString.contentEqualsIgnoreCase import zhttp.http.CORS.DefaultCORSConfig import zhttp.http.Headers.BasicSchemeName import zhttp.http.Middleware.{Flag, RequestP} @@ -45,6 +46,8 @@ sealed trait Middleware[-R, +E] { self => ): Middleware[R1, E1] = Middleware.fromMiddlewareFunctionZIO((m, u, h) => f(m, u, h)) + final def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[R, E] = Middleware.modifyHeaders(f) + final def orElse[R1 <: R, E1](other: Middleware[R1, E1]): Middleware[R1, E1] = Middleware.OrElse(self, other) @@ -89,6 +92,12 @@ object Middleware { def addHeaders(headers: Headers): Middleware[Any, Nothing] = patch((_, _) => Patch.addHeader(headers)) + /** + * Modifies the provided list of headers to the updated list of headers + */ + def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[Any, Nothing] = + patch((_, _) => Patch.updateHeaders(_.modify(f))) + /** * Creates an authentication middleware that only allows authenticated requests to be passed on to the app. */ @@ -237,6 +246,15 @@ object Middleware { } yield Patch.empty } + /** + * Creates a middleware for signing cookies + */ + def signCookies(secret: String): Middleware[Any, Nothing] = + modifyHeaders { + case h if contentEqualsIgnoreCase(h._1, HeaderNames.setCookie) => + (HeaderNames.setCookie, Cookie.decodeResponseCookie(h._2.toString).get.sign(secret).encode) + } + /** * Creates a new constants middleware that always executes the app provided, independent of where the middleware is * applied diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala index dbac7e800c..72bab03352 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala @@ -276,9 +276,9 @@ trait HeaderGetters[+A] { self => final def getSetCookie: Option[CharSequence] = getHeaderValue(HeaderNames.setCookie) - final def getSetCookiesDecoded: List[Cookie] = + final def getSetCookiesDecoded(secret: Option[String] = None): List[Cookie] = getHeaderValues(HeaderNames.setCookie) - .map(Cookie.decodeResponseCookie) + .map(Cookie.decodeResponseCookie(_, secret)) .collect { case Some(cookie) => cookie } final def getTe: Option[CharSequence] = diff --git a/zio-http/src/test/scala/zhttp/http/CookieSpec.scala b/zio-http/src/test/scala/zhttp/http/CookieSpec.scala index bfc90c0cff..e073c90b6c 100644 --- a/zio-http/src/test/scala/zhttp/http/CookieSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/CookieSpec.scala @@ -7,11 +7,11 @@ import zio.test._ object CookieSpec extends DefaultRunnableSpec { def spec = suite("Cookies") { suite("response cookies") { - testM("encode/decode cookies with ZIO Test Gen") { + testM("encode/decode signed/unsigned cookies with secret") { checkAll(HttpGen.cookies) { cookie => val cookieString = cookie.encode - assert(Cookie.decodeResponseCookie(cookieString))(isSome(equalTo(cookie))) && - assert(Cookie.decodeResponseCookie(cookieString).map(_.encode))(isSome(equalTo(cookieString))) + assert(Cookie.decodeResponseCookie(cookieString, cookie.secret))(isSome(equalTo(cookie))) && + assert(Cookie.decodeResponseCookie(cookieString, cookie.secret).map(_.encode))(isSome(equalTo(cookieString))) } } } + diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 3878e24d86..d71c0238ca 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -38,7 +38,8 @@ object HttpGen { httpOnly <- Gen.boolean maxAge <- Gen.option(Gen.anyLong) sameSite <- Gen.option(Gen.fromIterable(List(Cookie.SameSite.Strict, Cookie.SameSite.Lax))) - } yield Cookie(name, content, expires, domain, path, secure, httpOnly, maxAge, sameSite) + secret <- Gen.option(Gen.anyString) + } yield Cookie(name, content, expires, domain, path, secure, httpOnly, maxAge, sameSite, secret) def header: Gen[Random with Sized, Header] = for { key <- Gen.alphaNumericStringBounded(1, 4) diff --git a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala index b33e5e8db2..cfd82efdf3 100644 --- a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala +++ b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala @@ -210,6 +210,13 @@ object MiddlewareSpec extends DefaultRunnableSpec with HttpAppTestExtensions { res <- r.get } yield assert(res)(equalTo(false)) } + } + + suite("signCookies") { + testM("should sign cookies") { + val cookie = Cookie("key", "value").withHttpOnly + val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") getHeader "set-cookie" + assertM(app(Request()))(isSome(equalTo(cookie.sign("secret").encode))) + } } } From 67650c2029a7cd239b3ca2b68c508598ab7508ce Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Thu, 13 Jan 2022 19:48:44 +0530 Subject: [PATCH 06/95] Update sbt-scalafix to 0.9.34 (#805) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a23457dd46..a3a4d503f6 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,5 @@ addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.11") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.33") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.34") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.1") From 64a8f4af3ef074277db9013710188ddf873beee7 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 14 Jan 2022 13:33:16 +0530 Subject: [PATCH 07/95] Fix: Echo streaming (#828) * Failing test * Fix echo streaming * Pr Comments --- .../main/scala/zhttp/service/Handler.scala | 29 +++++-------------- .../handlers/ServerResponseHandler.scala | 27 +++++++++++++---- .../test/scala/zhttp/service/ServerSpec.scala | 8 +++++ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/Handler.scala b/zio-http/src/main/scala/zhttp/service/Handler.scala index c6e4761c02..51075398d6 100644 --- a/zio-http/src/main/scala/zhttp/service/Handler.scala +++ b/zio-http/src/main/scala/zhttp/service/Handler.scala @@ -45,15 +45,6 @@ private[zhttp] final case class Handler[R]( ) } - /** - * Releases the FullHttpRequest safely. - */ - private def releaseRequest(jReq: FullHttpRequest): Unit = { - if (jReq.refCnt() > 0) { - jReq.release(jReq.refCnt()): Unit - } - } - /** * Executes http apps */ @@ -69,13 +60,13 @@ private[zhttp] final case class Handler[R]( { case Some(cause) => UIO { - ctx.fireChannelRead(Response.fromHttpError(HttpError.InternalServerError(cause = Some(cause)))) - releaseRequest(jReq) + ctx.fireChannelRead( + (Response.fromHttpError(HttpError.InternalServerError(cause = Some(cause))), jReq), + ) } case None => UIO { - ctx.fireChannelRead(Response.status(Status.NOT_FOUND)) - releaseRequest(jReq) + ctx.fireChannelRead((Response.status(Status.NOT_FOUND), jReq)) } }, res => @@ -83,9 +74,8 @@ private[zhttp] final case class Handler[R]( else { for { _ <- UIO { - ctx.fireChannelRead(res) + ctx.fireChannelRead((res, jReq)) } - _ <- Task(releaseRequest(jReq)) } yield () }, ) @@ -95,16 +85,13 @@ private[zhttp] final case class Handler[R]( if (self.isWebSocket(res)) { self.upgradeToWebSocket(ctx, jReq, res) } else { - ctx.fireChannelRead(res) - releaseRequest(jReq) + ctx.fireChannelRead((res, jReq)): Unit } case HExit.Failure(e) => - ctx.fireChannelRead(e) - releaseRequest(jReq) + ctx.fireChannelRead((e, jReq)): Unit case HExit.Empty => - ctx.fireChannelRead(Response.status(Status.NOT_FOUND)) - releaseRequest(jReq) + ctx.fireChannelRead((Response.status(Status.NOT_FOUND), jReq)): Unit } } diff --git a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala index 8914770ae9..fe53a3c501 100644 --- a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala @@ -17,18 +17,24 @@ private[zhttp] case class ServerResponseHandler[R]( runtime: HttpRuntime[R], config: Server.Config[R, Throwable], serverTime: ServerTimeGenerator, -) extends SimpleChannelInboundHandler[Response](false) { +) extends SimpleChannelInboundHandler[(Response, FullHttpRequest)](false) { type Ctx = ChannelHandlerContext - override def channelRead0(ctx: Ctx, response: Response): Unit = { + override def channelRead0(ctx: Ctx, msg: (Response, FullHttpRequest)): Unit = { implicit val iCtx: ChannelHandlerContext = ctx - + val response = msg._1 + val jRequest = msg._2 ctx.write(encodeResponse(response)) response.data match { - case HttpData.BinaryStream(stream) => runtime.unsafeRun(ctx) { writeStreamContent(stream) } - case HttpData.File(file) => unsafeWriteFileContent(file) - case _ => ctx.flush() + case HttpData.BinaryStream(stream) => + runtime.unsafeRun(ctx) { writeStreamContent(stream).ensuring(UIO(releaseRequest(jRequest))) } + case HttpData.File(file) => + unsafeWriteFileContent(file) + releaseRequest(jRequest) + case _ => + ctx.flush() + releaseRequest(jRequest) } () } @@ -37,6 +43,15 @@ private[zhttp] case class ServerResponseHandler[R]( config.error.fold(super.exceptionCaught(ctx, cause))(f => runtime.unsafeRun(ctx)(f(cause))) } + /** + * Releases the FullHttpRequest safely. + */ + private def releaseRequest(jReq: FullHttpRequest): Unit = { + if (jReq.refCnt() > 0) { + jReq.release(jReq.refCnt()): Unit + } + } + /** * Checks if an encoded version of the response exists, uses it if it does. Otherwise, it will return a fresh * response. It will also set the server time if requested by the client. diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 777d897ab0..44acd921c3 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -165,6 +165,14 @@ object ServerSpec extends HttpRunnableSpec { val res = Http.fromStream(ZStream("a", "b", "c")).requestBodyAsString() assertM(res)(equalTo("abc")) } + + testM("echo streaming") { + val res = Http + .collectHttp[Request] { case req => + Http.fromStream(ZStream.fromEffect(req.getBody).flattenChunks) + } + .requestBodyAsString(content = "abc") + assertM(res)(equalTo("abc")) + } + testM("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).requestBodyAsString() From 72d71d39ca8426ca9172813de68ade1b153595ca Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Fri, 14 Jan 2022 14:49:19 +0530 Subject: [PATCH 08/95] Docs: Update Basic Examples (#814) * doc(Getting started): updated examples * docs: updated basic examples --- .../zio-http-basic-examples/hello-world.md | 2 +- .../zio-http-basic-examples/https-client.md | 22 +++--- .../zio-http-basic-examples/https-server.md | 20 ++++-- .../zio-http-basic-examples/simple-client.md | 17 ++--- .../zio-http-basic-examples/web-socket.md | 9 ++- docs/website/docs/getting-started.md | 71 +++++++------------ 6 files changed, 59 insertions(+), 82 deletions(-) diff --git a/docs/website/docs/examples/zio-http-basic-examples/hello-world.md b/docs/website/docs/examples/zio-http-basic-examples/hello-world.md index bea47a1600..db4645bea4 100644 --- a/docs/website/docs/examples/zio-http-basic-examples/hello-world.md +++ b/docs/website/docs/examples/zio-http-basic-examples/hello-world.md @@ -10,7 +10,7 @@ object HelloWorld extends App { // Create HTTP route val app: HttpApp[Any, Nothing] = Http.collect[Request] { case Method.GET -> !! / "text" => Response.text("Hello World!") - case Method.GET -> !! / "json" => Response.jsonString("""{"greetings": "Hello World!"}""") + case Method.GET -> !! / "json" => Response.json("""{"greetings": "Hello World!"}""") } // Run it like any simple app diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-client.md b/docs/website/docs/examples/zio-http-basic-examples/https-client.md index 2c775436bd..5bf84d6c48 100644 --- a/docs/website/docs/examples/zio-http-basic-examples/https-client.md +++ b/docs/website/docs/examples/zio-http-basic-examples/https-client.md @@ -2,7 +2,7 @@ ```scala import io.netty.handler.ssl.SslContextBuilder -import zhttp.http.{Header, HttpData} +import zhttp.http.Headers import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio._ @@ -14,11 +14,11 @@ import javax.net.ssl.TrustManagerFactory object HttpsClient extends App { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "https://sports.api.decathlon.com/groups/water-aerobics" - val headers = List(Header.host("sports.api.decathlon.com")) + val headers = Headers.host("sports.api.decathlon.com") - //Configuring Truststore for https(optional) + // Configuring Truststore for https(optional) val trustStore: KeyStore = KeyStore.getInstance("JKS") - val trustStorePath: InputStream = getClass.getResourceAsStream("truststore.jks") + val trustStorePath: InputStream = getClass.getClassLoader.getResourceAsStream("truststore.jks") val trustStorePassword: String = "changeit" val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) @@ -27,18 +27,12 @@ object HttpsClient extends App { trustManagerFactory.init(trustStore) val sslOption: ClientSSLOptions = - ClientSSLOptions - .CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) + ClientSSLOptions.CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) val program = for { - res <- Client.request(url, headers, sslOption) - _ <- console.putStrLn { - res.content match { - case HttpData.CompleteData(data) => data.map(_.toChar).mkString - case HttpData.StreamData(_) => "" - case HttpData.Empty => "" - } - } + res <- Client.request(url, headers, sslOption) + data <- res.getBodyAsString + _ <- console.putStrLn { data } } yield () override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-server.md b/docs/website/docs/examples/zio-http-basic-examples/https-server.md index 21bc7cbfc2..e645fe586c 100644 --- a/docs/website/docs/examples/zio-http-basic-examples/https-server.md +++ b/docs/website/docs/examples/zio-http-basic-examples/https-server.md @@ -2,26 +2,32 @@ ```scala import zhttp.http._ import zhttp.service.server.ServerChannelFactory -import zhttp.service.server.ServerSSLHandler.{ServerSSLOptions, ctxFromKeystore} +import zhttp.service.server.ServerSSLHandler._ import zhttp.service.{EventLoopGroup, Server} import zio._ object HttpsHelloWorld extends App { - // Create HTTP route val app: HttpApp[Any, Nothing] = Http.collect[Request] { case Method.GET -> !! / "text" => Response.text("Hello World!") - case Method.GET -> !! / "json" => Response.jsonString("""{"greetings": "Hello World!"}""") + case Method.GET -> !! / "json" => Response.json("""{"greetings": "Hello World!"}""") } /** - * sslcontext can be created using SslContexBuilder. - * In this example an inbuilt API using keystore is used + * sslcontext can be created using SslContexBuilder. In this example an inbuilt API using keystore is used. For + * testing this example using curl, setup the certificate named "server.crt" from resources for the OS. Alternatively + * you can create the keystore and certificate using the following link + * https://medium.com/@maanadev/netty-with-https-tls-9bf699e07f01 */ - val sslctx = ctxFromKeystore(getClass.getResourceAsStream("keystore.jks"), "password", "password") + val sslctx = ctxFromCert( + getClass().getClassLoader().getResourceAsStream("server.crt"), + getClass().getClassLoader().getResourceAsStream("server.key"), + ) private val server = - Server.port(8090) ++ Server.app(app) ++ Server.ssl(ServerSSLOptions(sslctx)) + Server.port(8090) ++ Server.app(app) ++ Server.ssl( + ServerSSLOptions(sslctx, SSLHttpBehaviour.Accept), + ) override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { server.make.useForever diff --git a/docs/website/docs/examples/zio-http-basic-examples/simple-client.md b/docs/website/docs/examples/zio-http-basic-examples/simple-client.md index b073dc7950..4df170c1be 100644 --- a/docs/website/docs/examples/zio-http-basic-examples/simple-client.md +++ b/docs/website/docs/examples/zio-http-basic-examples/simple-client.md @@ -1,26 +1,21 @@ # Simple HTTP Client ```scala -import zhttp.http.{Header, HttpData} +import zhttp.http.Headers import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio._ object SimpleClient extends App { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "http://sports.api.decathlon.com/groups/water-aerobics" - val headers = List(Header.host("sports.api.decathlon.com")) + val headers = Headers.host("sports.api.decathlon.com") val program = for { - res <- Client.request(url, headers) - _ <- console.putStrLn { - res.content match { - case HttpData.CompleteData(data) => data.map(_.toChar).mkString - case HttpData.StreamData(_) => "" - case HttpData.Empty => "" - } - } + res <- Client.request(url, headers) + data <- res.getBodyAsString + _ <- console.putStrLn { data } } yield () - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = program.exitCode.provideCustomLayer(env) } diff --git a/docs/website/docs/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/examples/zio-http-basic-examples/web-socket.md index d11c4029f4..8b119c992b 100644 --- a/docs/website/docs/examples/zio-http-basic-examples/web-socket.md +++ b/docs/website/docs/examples/zio-http-basic-examples/web-socket.md @@ -15,14 +15,13 @@ object WebSocketEcho extends App { case WebSocketFrame.Text("BAR") => ZStream.succeed(WebSocketFrame.text("FOO")) case WebSocketFrame.Ping => ZStream.succeed(WebSocketFrame.pong) case WebSocketFrame.Pong => ZStream.succeed(WebSocketFrame.ping) - case fr @ WebSocketFrame.Text(_) => ZStream.repeat(fr) - .schedule(Schedule.spaced(1 second)).take(10) + case fr @ WebSocketFrame.Text(_) => ZStream.repeat(fr).schedule(Schedule.spaced(1 second)).take(10) } private val app = - Http.collect[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!") - case Method.GET -> !! / "subscriptions" => Response.socket(socket) + Http.collectZIO[Request] { + case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "subscriptions" => socket.toResponse } override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = diff --git a/docs/website/docs/getting-started.md b/docs/website/docs/getting-started.md index 934852d5bb..e3a09048b8 100644 --- a/docs/website/docs/getting-started.md +++ b/docs/website/docs/getting-started.md @@ -22,8 +22,8 @@ An application can be made using any of the available operators on `zhttp.Http`. import zhttp.http._ val app = Http.collect[Request] { - case Method.GET -> Root / "fruits" / "a" => Response.text("Apple") - case Method.GET -> Root / "fruits" / "b" => Response.text("Banana") + case Method.GET -> !! / "fruits" / "a" => Response.text("Apple") + case Method.GET -> !! / "fruits" / "b" => Response.text("Banana") } ``` @@ -34,8 +34,8 @@ Pattern matching on route is supported by the framework ```scala import zhttp.http._ -val a = Http.collect[Request] { case Method.GET -> Root / "a" => Response.ok } -val b = Http.collect[Request] { case Method.GET -> Root / "b" => Response.ok } +val a = Http.collect[Request] { case Method.GET -> !! / "a" => Response.ok } +val b = Http.collect[Request] { case Method.GET -> !! / "b" => Response.ok } val app = a <> b ``` @@ -45,24 +45,24 @@ Apps can be composed using the `<>` operator. The way it works is, if none of th ### ZIO Integration ```scala -val app = Http.collectM[Request] { - case Method.GET -> Root / "hello" => ZIO.succeed(Response.text("Hello World")) +val app = Http.collectZIO[Request] { + case Method.GET -> !! / "hello" => Response.text("Hello World").wrapZIO } ``` -`Http.collectM` allow routes to return a ZIO effect value. +`Http.collectZIO` allow routes to return a ZIO effect value. ### Accessing the Request ```scala import zhttp.http._ -val app = Http.collect[Request] { - case req @ Method.GET -> Root / "fruits" / "a" => - Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) - case req @ Method.POST -> Root / "fruits" / "a" => - Response.text(req.getBodyAsString.getOrElse("No body!")) -} +val app = Http.collectZIO[Request] { + case req @ Method.GET -> !! / "fruits" / "a" => + Response.text("URL:" + req.url.path.asString + " Headers: " + req.getHeaders).wrapZIO + case req @ Method.POST -> !! / "fruits" / "a" => + req.getBodyAsString.map(Response.text(_)) + } ``` ### Testing @@ -75,28 +75,14 @@ import zhttp.test._ import zhttp.http._ object Spec extends DefaultRunnableSpec { - val app = Http.collect[Request] { - case Method.GET -> Root / "text" => Response.text("Hello World!") - } - def spec = suite("http") ( - testM("should be ok") { - val req = ??? - val expectedRes = resp => resp.status.toJHttpStatus.code() == Status.OK - assertM(app(req))(expectedRes) // an apply method is added via `zhttp.test` package - } - ) -} -``` - -```scala -import zhttp.http._ - -val app = Http.collect[Request] { - case req @ Method.GET -> Root / "fruits" / "a" => - Response.text("URL:" + req.url.path.asString + " Headers: " + r.headers) - case req @ Method.POST -> Root / "fruits" / "a" => - Response.text(req.getBodyAsString.getOrElse("No body!")) + def spec = suite("http")( + testM("should be ok") { + val app = Http.ok + val req = Request() + assertM(app(req))(equalTo(Response.ok)) // an apply method is added via `zhttp.test` package + } + ) } ``` @@ -107,14 +93,14 @@ val app = Http.collect[Request] { ```scala import zhttp.socket._ -private val socket = Socket.collect[WebSocketFrame] { - case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) -} +private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text("FOO") => + ZStream.succeed(WebSocketFrame.text("BAR")) + } -private val app = Http.collect[Request] { - case Method.GET -> Root / "greet" / name => Response.text(s"Greetings {$name}!") - case Method.GET -> Root / "ws" => Response.socket(socket) -} + private val app = Http.collectZIO[Request] { + case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "ws" => socket.toResponse + } ``` ## Server @@ -145,6 +131,3 @@ A simple Http app that responds with empty content and a `200` status code is de - [Simple Client](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SimpleClient.scala) - [File Streaming](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/FileStreaming.scala) - [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) - - - From 569bd1dcef62b97753d08a7179f64a67bee6d6d1 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Fri, 14 Jan 2022 16:32:50 +0530 Subject: [PATCH 09/95] docs: update advanced examples (#816) --- .../advanced-examples/authentication.md | 31 ++++++------ .../advanced-examples/concrete-entity.md | 13 +++-- .../docs/examples/advanced-examples/cors.md | 26 +++++----- .../advanced-examples/hello-world-advanced.md | 13 ++--- .../advanced-examples/sticky-threads.md | 48 ------------------- .../examples/advanced-examples/stream-file.md | 24 ++++++---- .../advanced-examples/stream-response.md | 26 +++++----- .../advanced-examples/web-socket-advanced.md | 36 +++++++++----- 8 files changed, 90 insertions(+), 127 deletions(-) delete mode 100644 docs/website/docs/examples/advanced-examples/sticky-threads.md diff --git a/docs/website/docs/examples/advanced-examples/authentication.md b/docs/website/docs/examples/advanced-examples/authentication.md index 15818d2c2f..a77f3252d7 100644 --- a/docs/website/docs/examples/advanced-examples/authentication.md +++ b/docs/website/docs/examples/advanced-examples/authentication.md @@ -2,7 +2,7 @@ ```scala import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim} -import zhttp.http.{Method, _} +import zhttp.http._ import zhttp.service.Server import zio._ @@ -27,36 +27,33 @@ object Authentication extends App { } // Authentication middleware - // Takes in a Failing HttpApp and a Succeed HttpApp which are - // called based on Authentication success or failure + // Takes in a Failing HttpApp and a Succeed HttpApp which are called based on Authentication success or failure // For each request tries to read the `X-ACCESS-TOKEN` header // Validates JWT Claim - def authenticate[R, E](fail: HttpApp[R, E], success: JwtClaim => HttpApp[R, E]): HttpApp[R, E] = - Http.flatten { - Http.fromFunction[Request] { + def authenticate[R, E](fail: HttpApp[R, E], success: JwtClaim => HttpApp[R, E]): HttpApp[R, E] = + Http + .fromFunction[Request] { _.getHeader("X-ACCESS-TOKEN") - .flatMap(header => jwtDecode(header.value.toString)) - .fold[HttpApp[R, E]](fail)(success) - } - } + .flatMap(header => jwtDecode(header._2.toString)) + .fold[HttpApp[R, E]](fail)(success) + } + .flatten // Http app that requires a JWT claim - def user(claim: JwtClaim): UHttpApp = Http.collect { - case Method.GET -> !! / "user" / name / "greet" => - Response.text(s"Welcome to the ZIO party! ${name}") - case Method.GET -> !! / "user" / "expiration" => - Response.text(s"Expires in: ${claim.expiration.getOrElse(-1L)}") + def user(claim: JwtClaim): UHttpApp = Http.collect[Request] { + case Method.GET -> !! / "user" / name / "greet" => Response.text(s"Welcome to the ZIO party! ${name}") + case Method.GET -> !! / "user" / "expiration" => Response.text(s"Expires in: ${claim.expiration.getOrElse(-1L)}") } // App that let's the user login // Login is successful only if the password is the reverse of the username - def login: UHttpApp = Http.collect { case Method.GET -> !! / "login" / username / password => + def login: UHttpApp = Http.collect[Request] { case Method.GET -> !! / "login" / username / password => if (password.reverse == username) Response.text(jwtEncode(username)) else Response.fromHttpError(HttpError.Unauthorized("Invalid username of password\n")) } // Composing all the HttpApps together - val app: UHttpApp = login +++ authenticate(Http.forbidden("Not allowed!"), user) + val app: UHttpApp = login ++ authenticate(Http.forbidden("Not allowed!"), user) // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = diff --git a/docs/website/docs/examples/advanced-examples/concrete-entity.md b/docs/website/docs/examples/advanced-examples/concrete-entity.md index 9f309ce399..7e1b7f7fd9 100644 --- a/docs/website/docs/examples/advanced-examples/concrete-entity.md +++ b/docs/website/docs/examples/advanced-examples/concrete-entity.md @@ -8,10 +8,10 @@ import zio._ * Example to build app on concrete entity */ object ConcreteEntity extends App { - //Request + // Request case class CreateUser(name: String) - //Response + // Response case class UserCreated(id: Long) val user: Http[Any, Nothing, CreateUser, UserCreated] = @@ -19,11 +19,10 @@ object ConcreteEntity extends App { UserCreated(2) } - val app: Http[Any, Nothing, Request, Response[Any, Nothing]] = user - .contramap[Request](req => CreateUser(req.endpoint._2.toString)) - //Http[Any, Nothing, Request, UserCreated] - .map(userCreated => Response.text(userCreated.id.toString)) - //Http[Any, Nothing, Request, Response] + val app: HttpApp[Any, Nothing] = + user + .contramap[Request](req => CreateUser(req.path.toString)) // Http[Any, Nothing, Request, UserCreated] + .map(userCreated => Response.text(userCreated.id.toString)) // Http[Any, Nothing, Request, Response] // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = diff --git a/docs/website/docs/examples/advanced-examples/cors.md b/docs/website/docs/examples/advanced-examples/cors.md index d540fbc9a1..187cdeeb89 100644 --- a/docs/website/docs/examples/advanced-examples/cors.md +++ b/docs/website/docs/examples/advanced-examples/cors.md @@ -6,17 +6,19 @@ import zhttp.service.Server import zio._ object HelloWorldWithCORS extends App { - // Create HTTP route with CORS enabled - val app: HttpApp[Any, Nothing] = CORS( - Http.collect[Request] { - case Method.GET -> !! / "text" => Response.text("Hello World!") - case Method.GET -> !! / "json" => Response.jsonString("""{"greetings": "Hello World!"}""") - }, - config = CORSConfig(anyOrigin = true), - ) - - // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + // Create CORS configuration + val config: CORSConfig = + CORSConfig(allowedOrigins = _ == "dev", allowedMethods = Some(Set(Method.PUT, Method.DELETE))) + + // Create HTTP route with CORS enabled + val app: HttpApp[Any, Nothing] = + Http.collect[Request] { + case Method.GET -> !! / "text" => Response.text("Hello World!") + case Method.GET -> !! / "json" => Response.json("""{"greetings": "Hello World!"}""") + } @@ cors(config) + + // Run it like any simple app + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app.silent).exitCode } ``` \ No newline at end of file diff --git a/docs/website/docs/examples/advanced-examples/hello-world-advanced.md b/docs/website/docs/examples/advanced-examples/hello-world-advanced.md index 9ec035b5f1..a49feb9487 100644 --- a/docs/website/docs/examples/advanced-examples/hello-world-advanced.md +++ b/docs/website/docs/examples/advanced-examples/hello-world-advanced.md @@ -10,22 +10,22 @@ import scala.util.Try object HelloWorldAdvanced extends App { // Set a port - private val PORT = 8090 + private val PORT = 0 private val fooBar: HttpApp[Any, Nothing] = Http.collect[Request] { case Method.GET -> !! / "foo" => Response.text("bar") case Method.GET -> !! / "bar" => Response.text("foo") } - private val app = Http.collectM[Request] { - case Method.GET -> !! / "random" => random.nextString(10).map(Response.text) + private val app = Http.collectZIO[Request] { + case Method.GET -> !! / "random" => random.nextString(10).map(Response.text(_)) case Method.GET -> !! / "utc" => clock.currentDateTime.map(s => Response.text(s.toString)) } private val server = Server.port(PORT) ++ // Setup port Server.paranoidLeakDetection ++ // Paranoid leak detection (affects performance) - Server.app(fooBar +++ app) // Setup the Http app + Server.app(fooBar ++ app) // Setup the Http app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { // Configure thread count using CLI @@ -33,9 +33,9 @@ object HelloWorldAdvanced extends App { // Create a new server server.make - .use(_ => + .use(start => // Waiting for the server to start - console.putStrLn(s"Server started on port $PORT") + console.putStrLn(s"Server started on port ${start.port}") // Ensures the server doesn't die after printing *> ZIO.never, @@ -44,4 +44,5 @@ object HelloWorldAdvanced extends App { .exitCode } } + ``` \ No newline at end of file diff --git a/docs/website/docs/examples/advanced-examples/sticky-threads.md b/docs/website/docs/examples/advanced-examples/sticky-threads.md deleted file mode 100644 index ee90b90049..0000000000 --- a/docs/website/docs/examples/advanced-examples/sticky-threads.md +++ /dev/null @@ -1,48 +0,0 @@ -# Sticky Threads - -```scala -import zhttp.http._ -import zhttp.service.Server -import zio._ -import zio.duration._ - -/** - * The following example depicts thread stickiness. The way it works is — once a - * request is received on the server, a thread is associated with it permanently. - * Any ZIO execution within the context of that request is guaranteed to be done - * on the same thread. This level of thread stickiness improves the performance - * characteristics of the server dramatically. - */ -object StickyThread extends App { - - /** - * A simple utility function that prints the fiber with the current thread. - */ - private def printThread(tag: String): ZIO[Any, Nothing, Unit] = { - for { - id <- ZIO.fiberId - _ <- UIO(println(s"${tag.padTo(6, ' ')}: - Fiber(${id.seqNumber}) Thread(${Thread.currentThread().getName})")) - } yield () - } - - /** - * The expected behaviour is that all the `printThread` output different fiber ids - * with the same thread name. - */ - val app = Http.collectM[Request] { case Method.GET -> !! / "text" => - for { - - _ <- printThread("Start") - f1 <- ZIO.sleep(1 second).zipLeft(printThread("First")).fork - f2 <- ZIO.sleep(1 second).zipLeft(printThread("Second")).fork - _ <- f1.join <*> f2.join - } yield Response.text("Hello World!") - } - - // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode -} - -``` \ No newline at end of file diff --git a/docs/website/docs/examples/advanced-examples/stream-file.md b/docs/website/docs/examples/advanced-examples/stream-file.md index 15099c96b3..feb935df35 100644 --- a/docs/website/docs/examples/advanced-examples/stream-file.md +++ b/docs/website/docs/examples/advanced-examples/stream-file.md @@ -1,22 +1,28 @@ # Streaming File ```scala import zhttp.http._ -import zhttp.service._ +import zhttp.service.Server +import zio.stream.ZStream import zio._ -import zio.stream._ +import java.io.File import java.nio.file.Paths object FileStreaming extends App { - // Read the file as ZStream - val content = HttpData.fromStream { - ZStream.fromFile(Paths.get("README.md")) - } // Create HTTP route - val app = Http.collect[Request] { - case Method.GET -> !! / "health" => Response.ok - case Method.GET -> !! / "file" => Response.http(content = content) + val app = Http.collectHttp[Request] { + case Method.GET -> !! / "health" => Http.ok + + // Read the file as ZStream + // Uses the blocking version of ZStream.fromFile + case Method.GET -> !! / "blocking" => Http.fromStream(ZStream.fromFile(Paths.get("README.md"))) + + // Uses netty's capability to write file content to the Channel + // Content-type response headers are automatically identified and added + // Does not use Chunked transfer encoding + case Method.GET -> !! / "video" => Http.fromFile(new File("src/main/resources/TestVideoFile.mp4")) + case Method.GET -> !! / "text" => Http.fromFile(new File("src/main/resources/TestFile.txt")) } // Run it like any simple app diff --git a/docs/website/docs/examples/advanced-examples/stream-response.md b/docs/website/docs/examples/advanced-examples/stream-response.md index ec4f519cbd..fd9a61919f 100644 --- a/docs/website/docs/examples/advanced-examples/stream-response.md +++ b/docs/website/docs/examples/advanced-examples/stream-response.md @@ -3,16 +3,21 @@ ```scala import zhttp.http._ import zhttp.service.Server -import zio._ import zio.stream.ZStream +import zio._ /** * Example to encode content using a ZStream */ object StreamingResponse extends App { - // Create a message as a Chunk[Byte] - val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + + // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) + Server.start(8090, app.silent).exitCode + } + // Create a message as a Chunk[Byte] + val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) // Use `Http.collect` to match on route val app: HttpApp[Any, Nothing] = Http.collect[Request] { @@ -21,20 +26,11 @@ object StreamingResponse extends App { // ZStream powered response case Method.GET -> !! / "stream" => - Response.http( + Response( status = Status.OK, - headers = List(Header.contentLength(message.length.toLong)), - content = HttpData.fromStream(ZStream.fromChunk(message)), - // Encoding content using a ZStream + headers = Headers.contentLength(message.length.toLong), + data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream ) - - } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { - - // Starting the server (for more advanced startup - // configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app.silent).exitCode } } - ``` \ No newline at end of file diff --git a/docs/website/docs/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/examples/advanced-examples/web-socket-advanced.md index 41fd4babaa..004161a107 100644 --- a/docs/website/docs/examples/advanced-examples/web-socket-advanced.md +++ b/docs/website/docs/examples/advanced-examples/web-socket-advanced.md @@ -1,7 +1,7 @@ # Web Socket Server ```scala import zhttp.http._ -import zhttp.service._ +import zhttp.service.Server import zhttp.socket._ import zio._ import zio.duration._ @@ -27,20 +27,30 @@ object WebSocketAdvanced extends App { private val decoder = SocketDecoder.allowExtensions // Combine all channel handlers together - private val socketApp = - SocketApp.open(open) ++ // Called after the request is successfully upgraded to websocket - SocketApp.message(echo merge fooBar) ++ // Called after each message being received on the channel - SocketApp.close(_ => console.putStrLn("Closed!").ignore) ++ // Called after the connection is closed - SocketApp.error(_ => - console.putStrLn("Error!").ignore, - ) ++ // Called whenever there is an error on the socket channel - SocketApp.decoder(decoder) ++ - SocketApp.protocol(protocol) + private val socketApp = { + + SocketApp(echo merge fooBar) // Called after each message being received on the channel + + // Called after the request is successfully upgraded to websocket + .onOpen(open) + + // Called after the connection is closed + .onClose(_ => console.putStrLn("Closed!").ignore) + + // Called whenever there is an error on the socket channel + .onError(_ => console.putStrLn("Error!").ignore) + + // Setup websocket decoder config + .withDecoder(decoder) + + // Setup websocket protocol config + .withProtocol(protocol) + } private val app = - Http.collect[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings ${name}!") - case Method.GET -> !! / "subscriptions" => socketApp + Http.collectZIO[Request] { + case Method.GET -> !! / "greet" / name => Response.text(s"Greetings ${name}!").wrapZIO + case Method.GET -> !! / "subscriptions" => socketApp.toResponse } override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = From fa4779186a911c8ecfcfdac650f54fac0c49cf4a Mon Sep 17 00:00:00 2001 From: Shubham Girdhar Date: Fri, 14 Jan 2022 16:41:53 +0530 Subject: [PATCH 10/95] maintenance: semanticdb revision usage (#832) --- project/BuildHelper.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/BuildHelper.scala b/project/BuildHelper.scala index d2bf8554f4..bee6ba1b0f 100644 --- a/project/BuildHelper.scala +++ b/project/BuildHelper.scala @@ -82,7 +82,7 @@ object BuildHelper extends ScalaSettings { ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, ScalaDotty), ThisBuild / scalaVersion := Scala213, scalacOptions := stdOptions ++ extraOptions(scalaVersion.value, optimize = !isSnapshot.value), - semanticdbVersion := scalafixSemanticdb.withRevision("4.4.30").revision, // use Scalafix compatible version + semanticdbVersion := scalafixSemanticdb.revision, // use Scalafix compatible version ThisBuild / scalafixScalaBinaryVersion := CrossVersion.binaryScalaVersion(scalaVersion.value), ThisBuild / scalafixDependencies ++= List( From 10df2c69afd11f29ee7d18977a1cccffcbf6455e Mon Sep 17 00:00:00 2001 From: Shubham Girdhar Date: Fri, 14 Jan 2022 17:51:11 +0530 Subject: [PATCH 11/95] maintenance: workflow scala version (#833) --- .github/workflows/ci.yml | 4 ++-- project/BenchmarkWorkFlow.scala | 2 ++ project/ScoverageWorkFlow.scala | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9d303fffa..a3490d1761 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -201,7 +201,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13.6] + scala: [2.13.7] java: [temurin@11] runs-on: ${{ matrix.os }} steps: @@ -234,7 +234,7 @@ jobs: strategy: matrix: os: [centos] - scala: [2.13.6] + scala: [2.13.7] java: [temurin@11] runs-on: [ "${{ matrix.os }}", zio-http ] steps: diff --git a/project/BenchmarkWorkFlow.scala b/project/BenchmarkWorkFlow.scala index acfd278b00..a2757abda1 100644 --- a/project/BenchmarkWorkFlow.scala +++ b/project/BenchmarkWorkFlow.scala @@ -1,3 +1,4 @@ +import BuildHelper.Scala213 import sbtghactions.GenerativePlugin.autoImport.{UseRef, WorkflowJob, WorkflowStep} object BenchmarkWorkFlow { @@ -10,6 +11,7 @@ object BenchmarkWorkFlow { cond = Some( "${{ github.event_name == 'pull_request'}}", ), + scalas = List(Scala213), steps = List( WorkflowStep.Run( env = Map("GITHUB_TOKEN" -> "${{secrets.ACTIONS_PAT}}"), diff --git a/project/ScoverageWorkFlow.scala b/project/ScoverageWorkFlow.scala index 61dd8f5210..13fbf07f39 100644 --- a/project/ScoverageWorkFlow.scala +++ b/project/ScoverageWorkFlow.scala @@ -1,5 +1,6 @@ +import BuildHelper.{Scala213, ScoverageVersion} import sbtghactions.GenerativePlugin.autoImport.{WorkflowJob, WorkflowStep} -import BuildHelper.{ScoverageVersion, Scala213} + object ScoverageWorkFlow { // TODO move plugins to plugins.sbt after scoverage's support for Scala 3 val scoveragePlugin = s"""addSbtPlugin("org.scoverage" % "sbt-scoverage" % "${ScoverageVersion}")""" @@ -12,6 +13,7 @@ object ScoverageWorkFlow { WorkflowJob( id = "unsafeRunScoverage", name = "Unsafe Scoverage", + scalas = List(Scala213), steps = List( WorkflowStep.CheckoutFull, WorkflowStep.Run( From 9c77c03e2eab8c38affc0c2a54a2af37b463cd5d Mon Sep 17 00:00:00 2001 From: Gabriel Ciuloaica <95849448+gciuloaica@users.noreply.github.com> Date: Sat, 15 Jan 2022 15:04:40 +0200 Subject: [PATCH 12/95] Fix: HasHeader bug (#835) * #834 - fix and test for the bug. * applied suggested change --- .../src/main/scala/zhttp/http/headers/HeaderChecks.scala | 2 +- zio-http/src/test/scala/zhttp/http/HeaderSpec.scala | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala index 139d821a4e..bee353ed92 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala @@ -18,7 +18,7 @@ trait HeaderChecks[+A] { self: HeaderExtension[A] with A => final def hasHeader(name: CharSequence, value: CharSequence): Boolean = getHeaderValue(name) match { - case Some(v1) => v1 == value + case Some(v1) => v1.contentEquals(value) case None => false } diff --git a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala index 8352e6f539..87731c4375 100644 --- a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala @@ -61,6 +61,12 @@ object HeaderSpec extends DefaultRunnableSpec { assert(actual)(isNone) }, ) + + suite("hasHeader")( + test("should return true if content-type is application/json") { + val actual = contentTypeJson.hasHeader(HeaderNames.contentType, HeaderValues.applicationJson) + assert(actual)(isTrue) + }, + ) + suite("hasJsonContentType")( test("should return true if content-type is application/json") { val actual = contentTypeJson.hasJsonContentType From 9ee2048f933f795dc35ea7c36e64fcaf40155551 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Sat, 15 Jan 2022 19:04:14 +0530 Subject: [PATCH 13/95] refactor: fix naming for Http operators (#839) --- .../zhttp.benchmarks/HttpRouteTextPerf.scala | 2 +- .../src/main/scala/zhttp/test/test.scala | 2 +- .../scala/zhttp/endpoint/CanConstruct.scala | 2 +- .../src/main/scala/zhttp/http/HExit.scala | 12 +-- zio-http/src/main/scala/zhttp/http/Http.scala | 99 +++++++++---------- .../src/main/scala/zhttp/socket/Socket.scala | 8 +- .../src/test/scala/zhttp/http/HExitSpec.scala | 8 +- .../src/test/scala/zhttp/http/HttpSpec.scala | 38 +++---- .../zhttp/service/WebSocketServerSpec.scala | 2 +- 9 files changed, 82 insertions(+), 91 deletions(-) diff --git a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala index 9746d8ee4d..042d470df8 100644 --- a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala +++ b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala @@ -16,7 +16,7 @@ class HttpRouteTextPerf { private val res = Response.text("HELLO WORLD") private val app = Http.succeed(res) private val req: Request = Request(Method.GET, URL(!!)) - private val httpProgram = ZIO.foreach_(0 to 1000) { _ => app.execute(req).toEffect } + private val httpProgram = ZIO.foreach_(0 to 1000) { _ => app.execute(req).toZIO } private val UIOProgram = ZIO.foreach_(0 to 1000) { _ => UIO(res) } @Benchmark diff --git a/zio-http-test/src/main/scala/zhttp/test/test.scala b/zio-http-test/src/main/scala/zhttp/test/test.scala index e32ecd7d7c..94b25c6d79 100644 --- a/zio-http-test/src/main/scala/zhttp/test/test.scala +++ b/zio-http-test/src/main/scala/zhttp/test/test.scala @@ -5,6 +5,6 @@ import zio.ZIO package object test { implicit class HttpWithTest[R, E, A, B](http: Http[R, E, A, B]) { - def apply(req: A): ZIO[R, Option[E], B] = http.execute(req).toEffect + def apply(req: A): ZIO[R, Option[E], B] = http.execute(req).toZIO } } diff --git a/zio-http/src/main/scala/zhttp/endpoint/CanConstruct.scala b/zio-http/src/main/scala/zhttp/endpoint/CanConstruct.scala index 81d148ff29..c3e276b826 100644 --- a/zio-http/src/main/scala/zhttp/endpoint/CanConstruct.scala +++ b/zio-http/src/main/scala/zhttp/endpoint/CanConstruct.scala @@ -44,7 +44,7 @@ object CanConstruct { Http .collectHttp[Request] { case req => route.extract(req) match { - case Some(value) => Http.fromEffect(f(Request.ParameterizedRequest(req, value))) + case Some(value) => Http.fromZIO(f(Request.ParameterizedRequest(req, value))) case None => Http.empty } } diff --git a/zio-http/src/main/scala/zhttp/http/HExit.scala b/zio-http/src/main/scala/zhttp/http/HExit.scala index 2cf0a87eee..aad51d8264 100644 --- a/zio-http/src/main/scala/zhttp/http/HExit.scala +++ b/zio-http/src/main/scala/zhttp/http/HExit.scala @@ -45,10 +45,10 @@ private[zhttp] sealed trait HExit[-R, +E, +A] { self => Effect( zio.foldM( { - case Some(error) => ee(error).toEffect - case None => dd.toEffect + case Some(error) => ee(error).toZIO + case None => dd.toZIO }, - a => aa(a).toEffect, + a => aa(a).toZIO, ), ) case HExit.Empty => dd @@ -59,7 +59,7 @@ private[zhttp] sealed trait HExit[-R, +E, +A] { self => def orElse[R1 <: R, E1, A1 >: A](other: HExit[R1, E1, A1]): HExit[R1, E1, A1] = self.foldExit(_ => other, HExit.succeed, HExit.empty) - def toEffect: ZIO[R, Option[E], A] = self match { + def toZIO: ZIO[R, Option[E], A] = self match { case HExit.Success(a) => ZIO.succeed(a) case HExit.Failure(e) => ZIO.fail(Option(e)) case HExit.Empty => ZIO.fail(None) @@ -68,12 +68,12 @@ private[zhttp] sealed trait HExit[-R, +E, +A] { self => } object HExit { - def effect[R, E, A](z: ZIO[R, E, A]): HExit[R, E, A] = Effect(z.mapError(Option(_))) - def empty: HExit[Any, Nothing, Nothing] = Empty def fail[E](e: E): HExit[Any, E, Nothing] = Failure(e) + def fromZIO[R, E, A](z: ZIO[R, E, A]): HExit[R, E, A] = Effect(z.mapError(Option(_))) + def succeed[A](a: A): HExit[Any, Nothing, A] = Success(a) def unit: HExit[Any, Nothing, Unit] = HExit.succeed(()) diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 1906e52095..03dded42f3 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -64,7 +64,7 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Consumes the input and executes the Http. */ - final def apply(a: A): ZIO[R, Option[E], B] = execute(a).toEffect + final def apply(a: A): ZIO[R, Option[E], B] = execute(a).toZIO /** * Makes the app resolve with a constant value @@ -103,7 +103,7 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Transforms the input of the http before passing it on to the current Http */ - final def contraFlatMap[X]: MkContraFlatMap[R, E, A, B, X] = MkContraFlatMap[R, E, A, B, X](self) + final def contraFlatMap[X]: PartialContraFlatMap[R, E, A, B, X] = PartialContraFlatMap[R, E, A, B, X](self) /** * Transforms the input of the http before passing it on to the current Http @@ -114,7 +114,7 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => * Transforms the input of the http before giving it effectfully */ final def contramapZIO[R1 <: R, E1 >: E, X](xa: X => ZIO[R1, E1, A]): Http[R1, E1, X, B] = - Http.fromEffectFunction[X](xa) >>> self + Http.fromFunctionZIO[X](xa) >>> self /** * Named alias for `++` @@ -178,7 +178,7 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => * Transforms the output of the http effectfully */ final def mapZIO[R1 <: R, E1 >: E, C](bFc: B => ZIO[R1, E1, C]): Http[R1, E1, A, C] = - self >>> Http.fromEffectFunction(bFc) + self >>> Http.fromFunctionZIO(bFc) /** * Named alias for `<>` @@ -263,9 +263,9 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => h: ZIO[R1, E1, Any], ): Http[R1, E1, A, B] = tapAll( - e => Http.fromEffect(f(e)), - x => Http.fromEffect(g(x)), - Http.fromEffect(h), + e => Http.fromZIO(f(e)), + x => Http.fromZIO(g(x)), + Http.fromZIO(h), ) /** @@ -282,19 +282,19 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => * Returns an Http that effectfully peeks at the failure of this Http. */ final def tapErrorZIO[R1 <: R, E1 >: E](f: E => ZIO[R1, E1, Any]): Http[R1, E1, A, B] = - self.tapError(e => Http.fromEffect(f(e))) + self.tapError(e => Http.fromZIO(f(e))) /** * Returns an Http that effectfully peeks at the success of this Http. */ final def tapZIO[R1 <: R, E1 >: E](f: B => ZIO[R1, E1, Any]): Http[R1, E1, A, B] = - self.tap(v => Http.fromEffect(f(v))) + self.tap(v => Http.fromZIO(f(v))) /** * Unwraps an Http that returns a ZIO of Http */ final def unwrap[R1 <: R, E1 >: E, C](implicit ev: B <:< ZIO[R1, E1, C]): Http[R1, E1, A, C] = - self.flatMap(Http.fromEffect(_)) + self.flatMap(Http.fromZIO(_)) /** * Widens the type of the output @@ -317,14 +317,14 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => */ final private[zhttp] def execute(a: A): HExit[R, E, B] = self match { - case Http.Empty => HExit.empty - case Http.Identity => HExit.succeed(a.asInstanceOf[B]) - case Succeed(b) => HExit.succeed(b) - case Fail(e) => HExit.fail(e) - case FromEffectFunction(f) => HExit.effect(f(a)) - case Collect(pf) => if (pf.isDefinedAt(a)) HExit.succeed(pf(a)) else HExit.empty - case Chain(self, other) => self.execute(a).flatMap(b => other.execute(b)) - case Race(self, other) => + case Http.Empty => HExit.empty + case Http.Identity => HExit.succeed(a.asInstanceOf[B]) + case Succeed(b) => HExit.succeed(b) + case Fail(e) => HExit.fail(e) + case FromFunctionZIO(f) => HExit.fromZIO(f(a)) + case Collect(pf) => if (pf.isDefinedAt(a)) HExit.succeed(pf(a)) else HExit.empty + case Chain(self, other) => self.execute(a).flatMap(b => other.execute(b)) + case Race(self, other) => (self.execute(a), other.execute(a)) match { case (HExit.Effect(self), HExit.Effect(other)) => Http.fromOptionFunction[Any](_ => self.raceFirst(other)).execute(a) @@ -406,14 +406,14 @@ object Http { /** * Creates an HTTP app which accepts a request and produces response. */ - def collect[A]: Http.MakeCollect[A] = Http.MakeCollect(()) + def collect[A]: Http.PartialCollect[A] = Http.PartialCollect(()) - def collectHttp[A]: Http.MakeCollectHttp[A] = Http.MakeCollectHttp(()) + def collectHttp[A]: Http.PartialCollectHttp[A] = Http.PartialCollectHttp(()) /** * Creates an HTTP app which accepts a request and produces response effectfully. */ - def collectZIO[A]: Http.MakeCollectZIO[A] = Http.MakeCollectZIO(()) + def collectZIO[A]: Http.PartialCollectZIO[A] = Http.PartialCollectZIO(()) /** * Combines multiple Http apps into one @@ -451,7 +451,7 @@ object Http { * Flattens an Http app of an that returns an effectful response */ def flattenZIO[R, E, A, B](http: Http[R, E, A, ZIO[R, E, B]]): Http[R, E, A, B] = - http.flatMap(Http.fromEffect) + http.flatMap(Http.fromZIO) /** * Creates an Http app that responds with 403 - Forbidden status code @@ -463,16 +463,6 @@ object Http { */ def fromData(data: HttpData): HttpApp[Any, Nothing] = response(Response(data = data)) - /** - * Converts a ZIO to an Http type - */ - def fromEffect[R, E, B](effect: ZIO[R, E, B]): Http[R, E, Any, B] = Http.fromEffectFunction(_ => effect) - - /** - * Creates an Http app from a function that returns a ZIO - */ - def fromEffectFunction[A]: Http.MakeFromEffectFunction[A] = Http.MakeFromEffectFunction(()) - /* * Creates an Http app from the contents of a file */ @@ -481,30 +471,35 @@ object Http { /** * Creates a Http from a pure function */ - def fromFunction[A]: FromFunction[A] = new FromFunction[A](()) + def fromFunction[A]: PartialFromFunction[A] = new PartialFromFunction[A](()) /** * Creates a Http from an effectful pure function */ - def fromFunctionZIO[A]: FromFunctionZIO[A] = new FromFunctionZIO[A](()) + def fromFunctionZIO[A]: PartialFromFunctionZIO[A] = new PartialFromFunctionZIO[A](()) /** * Creates an `Http` from a function that takes a value of type `A` and returns with a `ZIO[R, Option[E], B]`. The * returned effect can fail with a `None` to signal "not found" to the backend. */ - def fromOptionFunction[A]: FromOptionFunction[A] = new FromOptionFunction(()) + def fromOptionFunction[A]: PartialFromOptionFunction[A] = new PartialFromOptionFunction(()) /** * Creates a Http that always succeeds with a 200 status code and the provided ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, String], charset: Charset = HTTP_CHARSET): HttpApp[R, Nothing] = - Http.fromEffect(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r), charset)))).flatten + Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r), charset)))).flatten /** * Creates a Http that always succeeds with a 200 status code and the provided ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, Byte]): HttpApp[R, Nothing] = - Http.fromEffect(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r))))).flatten + Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r))))).flatten + + /** + * Converts a ZIO to an Http type + */ + def fromZIO[R, E, B](effect: ZIO[R, E, B]): Http[R, E, Any, B] = Http.fromFunctionZIO(_ => effect) /** * Creates an HTTP app which always responds with the provided Html page. @@ -535,12 +530,12 @@ object Http { /** * Converts a ZIO to an Http app type */ - def responseZIO[R, E](res: ZIO[R, E, Response]): HttpApp[R, E] = Http.fromEffect(res) + def responseZIO[R, E](res: ZIO[R, E, Response]): HttpApp[R, E] = Http.fromZIO(res) /** * Creates an Http that delegates to other Https. */ - def route[A]: Http.MakeRoute[A] = Http.MakeRoute(()) + def route[A]: Http.PartialRoute[A] = Http.PartialRoute(()) /** * Creates an HTTP app which always responds with the same status code and empty data. @@ -569,35 +564,31 @@ object Http { def tooLarge: HttpApp[Any, Nothing] = Http.status(Status.REQUEST_ENTITY_TOO_LARGE) // Ctor Help - final case class MakeCollectZIO[A](unit: Unit) extends AnyVal { + final case class PartialCollectZIO[A](unit: Unit) extends AnyVal { def apply[R, E, B](pf: PartialFunction[A, ZIO[R, E, B]]): Http[R, E, A, B] = - Http.collect[A] { case a if pf.isDefinedAt(a) => Http.fromEffect(pf(a)) }.flatten + Http.collect[A] { case a if pf.isDefinedAt(a) => Http.fromZIO(pf(a)) }.flatten } - final case class MakeCollect[A](unit: Unit) extends AnyVal { + final case class PartialCollect[A](unit: Unit) extends AnyVal { def apply[B](pf: PartialFunction[A, B]): Http[Any, Nothing, A, B] = Collect(pf) } - final case class MakeCollectHttp[A](unit: Unit) extends AnyVal { + final case class PartialCollectHttp[A](unit: Unit) extends AnyVal { def apply[R, E, B](pf: PartialFunction[A, Http[R, E, A, B]]): Http[R, E, A, B] = Http.collect[A](pf).flatten } - final case class MakeFromEffectFunction[A](unit: Unit) extends AnyVal { - def apply[R, E, B](f: A => ZIO[R, E, B]): Http[R, E, A, B] = Http.FromEffectFunction(f) - } - - final case class MakeRoute[A](unit: Unit) extends AnyVal { + final case class PartialRoute[A](unit: Unit) extends AnyVal { def apply[R, E, B](pf: PartialFunction[A, Http[R, E, A, B]]): Http[R, E, A, B] = Http.collect[A] { case r if pf.isDefinedAt(r) => pf(r) }.flatten } - final case class MkContraFlatMap[-R, +E, -A, +B, X](self: Http[R, E, A, B]) extends AnyVal { + final case class PartialContraFlatMap[-R, +E, -A, +B, X](self: Http[R, E, A, B]) extends AnyVal { def apply[R1 <: R, E1 >: E](xa: X => Http[R1, E1, Any, A]): Http[R1, E1, X, B] = Http.identity[X].flatMap(xa) >>> self } - final class FromOptionFunction[A](val unit: Unit) extends AnyVal { + final class PartialFromOptionFunction[A](val unit: Unit) extends AnyVal { def apply[R, E, B](f: A => ZIO[R, Option[E], B]): Http[R, E, A, B] = Http .collectZIO[A] { case a => f(a).map(Http.succeed(_)).catchAll { @@ -608,12 +599,12 @@ object Http { .flatten } - final class FromFunction[A](val unit: Unit) extends AnyVal { + final class PartialFromFunction[A](val unit: Unit) extends AnyVal { def apply[B](f: A => B): Http[Any, Nothing, A, B] = Http.identity[A].map(f) } - final class FromFunctionZIO[A](val unit: Unit) extends AnyVal { - def apply[R, E, B](f: A => ZIO[R, E, B]): Http[R, E, A, B] = Http.identity[A].mapZIO(f) + final class PartialFromFunctionZIO[A](val unit: Unit) extends AnyVal { + def apply[R, E, B](f: A => ZIO[R, E, B]): Http[R, E, A, B] = FromFunctionZIO(f) } private final case class Succeed[B](b: B) extends Http[Any, Nothing, Any, B] @@ -622,7 +613,7 @@ object Http { private final case class Fail[E](e: E) extends Http[Any, E, Any, Nothing] - private final case class FromEffectFunction[R, E, A, B](f: A => ZIO[R, E, B]) extends Http[R, E, A, B] + private final case class FromFunctionZIO[R, E, A, B](f: A => ZIO[R, E, B]) extends Http[R, E, A, B] private final case class Collect[R, E, A, B](ab: PartialFunction[A, B]) extends Http[R, E, A, B] diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 205a077fa8..54190c52eb 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -57,21 +57,21 @@ sealed trait Socket[-R, +E, -A, +B] { self => } object Socket { - def collect[A]: MkCollect[A] = new MkCollect[A](()) + def collect[A]: PartialCollect[A] = new PartialCollect[A](()) def end: ZStream[Any, Nothing, Nothing] = ZStream.halt(Cause.empty) - def fromFunction[A]: MkFromFunction[A] = new MkFromFunction[A](()) + def fromFunction[A]: PartialFromFunction[A] = new PartialFromFunction[A](()) def fromStream[R, E, B](stream: ZStream[R, E, B]): Socket[R, E, Any, B] = FromStream(stream) def succeed[A](a: A): Socket[Any, Nothing, Any, A] = Succeed(a) - final class MkFromFunction[A](val unit: Unit) extends AnyVal { + final class PartialFromFunction[A](val unit: Unit) extends AnyVal { def apply[R, E, B](f: A => ZStream[R, E, B]): Socket[R, E, A, B] = FromStreamingFunction(f) } - final class MkCollect[A](val unit: Unit) extends AnyVal { + final class PartialCollect[A](val unit: Unit) extends AnyVal { def apply[R, E, B](pf: PartialFunction[A, ZStream[R, E, B]]): Socket[R, E, A, B] = Socket.FromStreamingFunction { a => if (pf.isDefinedAt(a)) pf(a) else ZStream.empty diff --git a/zio-http/src/test/scala/zhttp/http/HExitSpec.scala b/zio-http/src/test/scala/zhttp/http/HExitSpec.scala index a15f024035..b4aa6502bb 100644 --- a/zio-http/src/test/scala/zhttp/http/HExitSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HExitSpec.scala @@ -14,7 +14,7 @@ object HExitSpec extends DefaultRunnableSpec with HExitAssertion { empty === isEmpty && succeed(1) === isSuccess(equalTo(1)) && fail(1) === isFailure(equalTo(1)) && - effect(UIO(1)) === isEffect + fromZIO(UIO(1)) === isEffect } + test("flatMapError") { succeed(0) *> fail(1) <> fail(2) === isFailure(equalTo(2)) && @@ -38,9 +38,9 @@ object HExitSpec extends DefaultRunnableSpec with HExitAssertion { empty <+> empty === isEmpty } + test("effect") { - effect(UIO(1)) <+> empty === isEffect && - empty <+> effect(UIO(1)) === isEffect && - empty *> effect(UIO(1)) *> effect(UIO(1)) === isEmpty + fromZIO(UIO(1)) <+> empty === isEffect && + empty <+> fromZIO(UIO(1)) === isEffect && + empty *> fromZIO(UIO(1)) *> fromZIO(UIO(1)) === isEmpty } + test("nested succeed") { empty <+> succeed(1) <+> succeed(2) === isSuccess(equalTo(1)) && diff --git a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala index ada9329322..944656f5f0 100644 --- a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala @@ -94,12 +94,12 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { suite("asEffect")( testM("should resolve") { val a = Http.collect[Int] { case 1 => "A" } - val actual = a.execute(1).toEffect + val actual = a.execute(1).toZIO assertM(actual)(equalTo("A")) } + testM("should complete") { val a = Http.collect[Int] { case 1 => "A" } - val actual = a.execute(2).toEffect.either + val actual = a.execute(2).toZIO.either assertM(actual)(isLeft(isNone)) }, ) + @@ -140,8 +140,8 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { testM("taps the successs") { for { r <- Ref.make(0) - app = Http.succeed(1).tap(v => Http.fromEffect(r.set(v))) - _ <- app.execute(()).toEffect + app = Http.succeed(1).tap(v => Http.fromZIO(r.set(v))) + _ <- app.execute(()).toZIO res <- r.get } yield assert(res)(equalTo(1)) }, @@ -151,7 +151,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = Http.succeed(1).tapZIO(r.set) - _ <- app.execute(()).toEffect + _ <- app.execute(()).toZIO res <- r.get } yield assert(res)(equalTo(1)) }, @@ -160,8 +160,8 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { testM("taps the error") { for { r <- Ref.make(0) - app = Http.fail(1).tapError(v => Http.fromEffect(r.set(v))) - _ <- app.execute(()).toEffect.ignore + app = Http.fail(1).tapError(v => Http.fromZIO(r.set(v))) + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) }, @@ -171,7 +171,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = Http.fail(1).tapErrorZIO(r.set) - _ <- app.execute(()).toEffect.ignore + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) }, @@ -181,8 +181,8 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = (Http.succeed(1): Http[Any, Any, Any, Int]) - .tapAll(_ => Http.empty, v => Http.fromEffect(r.set(v)), Http.empty) - _ <- app.execute(()).toEffect + .tapAll(_ => Http.empty, v => Http.fromZIO(r.set(v)), Http.empty) + _ <- app.execute(()).toZIO res <- r.get } yield assert(res)(equalTo(1)) } + @@ -190,8 +190,8 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = (Http.fail(1): Http[Any, Int, Any, Any]) - .tapAll(v => Http.fromEffect(r.set(v)), _ => Http.empty, Http.empty) - _ <- app.execute(()).toEffect.ignore + .tapAll(v => Http.fromZIO(r.set(v)), _ => Http.empty, Http.empty) + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) } + @@ -199,8 +199,8 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = (Http.empty: Http[Any, Any, Any, Any]) - .tapAll(_ => Http.empty, _ => Http.empty, Http.fromEffect(r.set(1))) - _ <- app.execute(()).toEffect.ignore + .tapAll(_ => Http.empty, _ => Http.empty, Http.fromZIO(r.set(1))) + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) }, @@ -210,7 +210,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = (Http.succeed(1): Http[Any, Any, Any, Int]).tapAllZIO(_ => ZIO.unit, r.set, ZIO.unit) - _ <- app.execute(()).toEffect + _ <- app.execute(()).toZIO res <- r.get } yield assert(res)(equalTo(1)) } + @@ -218,7 +218,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { for { r <- Ref.make(0) app = (Http.fail(1): Http[Any, Int, Any, Any]).tapAllZIO(r.set, _ => ZIO.unit, ZIO.unit) - _ <- app.execute(()).toEffect.ignore + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) } + @@ -227,7 +227,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { r <- Ref.make(0) app = (Http.empty: Http[Any, Any, Any, Any]) .tapAllZIO(_ => ZIO.unit, _ => ZIO.unit, r.set(1)) - _ <- app.execute(()).toEffect.ignore + _ <- app.execute(()).toZIO.ignore res <- r.get } yield assert(res)(equalTo(1)) }, @@ -238,11 +238,11 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { assertM(http(()))(equalTo(1)) } + testM("sync right wins") { - val http = Http.fromEffect(UIO(1)) race Http.succeed(2) + val http = Http.fromZIO(UIO(1)) race Http.succeed(2) assertM(http(()))(equalTo(2)) } + testM("sync left wins") { - val http = Http.succeed(1) race Http.fromEffect(UIO(2)) + val http = Http.succeed(1) race Http.fromZIO(UIO(2)) assertM(http(()))(equalTo(1)) } + testM("async fast wins") { diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index 916a964fc2..c09313e03c 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -20,7 +20,7 @@ object WebSocketServerSpec extends HttpRunnableSpec { suite("connections") { testM("Multiple websocket upgrades") { val response = Socket.succeed(WebSocketFrame.text("BAR")).toResponse - val app = Http.fromEffect(response) + val app = Http.fromZIO(response) assertM(app.webSocketStatusCode(!! / "subscriptions").repeatN(1024))(equalTo(101)) } } From 3c56a909972ce9384a959e0a73cd59ffddb58abd Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sat, 15 Jan 2022 19:05:02 +0530 Subject: [PATCH 14/95] Update sbt-bloop to 1.4.12 (#810) * Update sbt-bloop to 1.4.12 * Update sbt-bloop to 1.4.12 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a3a4d503f6..440aa80ac0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.11") +addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.12") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.34") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") From da7c4594f8e716de416041b1a5ca99896ea1e7bb Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sat, 15 Jan 2022 19:05:10 +0530 Subject: [PATCH 15/95] Update scala-library to 2.13.8 (#801) * Update scala-library to 2.13.8 * Regenerate workflow with sbt-github-actions --- .github/workflows/ci.yml | 22 +++++++++++----------- project/BuildHelper.scala | 4 ++-- project/ScoverageWorkFlow.scala | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3490d1761..d1cecb357a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.12.15, 2.13.7, 3.1.0] + scala: [2.12.15, 2.13.8, 3.1.0] java: [graal_21.1.0@11, temurin@8] runs-on: ${{ matrix.os }} steps: @@ -60,7 +60,7 @@ jobs: key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - name: Check formatting - run: sbt ++2.13.7 fmtCheck + run: sbt ++2.13.8 fmtCheck - name: Check that workflows are up to date run: sbt ++${{ matrix.scala }} githubWorkflowCheck @@ -70,7 +70,7 @@ jobs: - name: Check doc generation if: ${{ github.event_name == 'pull_request' }} - run: sbt ++2.13.7 doc + run: sbt ++2.13.8 doc - name: Compress target directories run: tar cf targets.tar target zio-http-test/target zio-http/target zio-http-benchmarks/target example/target project/target @@ -88,7 +88,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13.7] + scala: [2.13.8] java: [graal_21.1.0@11] runs-on: ${{ matrix.os }} steps: @@ -133,12 +133,12 @@ jobs: tar xf targets.tar rm targets.tar - - name: Download target directories (2.13.7) + - name: Download target directories (2.13.8) uses: actions/download-artifact@v2 with: - name: target-${{ matrix.os }}-2.13.7-${{ matrix.java }} + name: target-${{ matrix.os }}-2.13.8-${{ matrix.java }} - - name: Inflate target directories (2.13.7) + - name: Inflate target directories (2.13.8) run: | tar xf targets.tar rm targets.tar @@ -201,7 +201,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13.7] + scala: [2.13.8] java: [temurin@11] runs-on: ${{ matrix.os }} steps: @@ -212,7 +212,7 @@ jobs: - name: Add Scoverage id: add_plugin - run: sed -i -e '$aaddSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.2")' project/plugins.sbt + run: sed -i -e '$aaddSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3")' project/plugins.sbt - name: Update Build Definition id: update_build_definition @@ -222,7 +222,7 @@ jobs: - name: Run Coverage id: run_coverage - run: sbt ++2.13.7 coverage 'project zhttp;test' coverageReport + run: sbt ++${{ matrix.scala }} 'coverage; project zhttp; test; coverageReport' - name: Push Codecov id: push_codecov @@ -234,7 +234,7 @@ jobs: strategy: matrix: os: [centos] - scala: [2.13.7] + scala: [2.13.8] java: [temurin@11] runs-on: [ "${{ matrix.os }}", zio-http ] steps: diff --git a/project/BuildHelper.scala b/project/BuildHelper.scala index bee6ba1b0f..01153b0415 100644 --- a/project/BuildHelper.scala +++ b/project/BuildHelper.scala @@ -5,9 +5,9 @@ import xerial.sbt.Sonatype.autoImport._ object BuildHelper extends ScalaSettings { val Scala212 = "2.12.15" - val Scala213 = "2.13.7" + val Scala213 = "2.13.8" val ScalaDotty = "3.1.0" - val ScoverageVersion = "1.9.2" + val ScoverageVersion = "1.9.3" private val stdOptions = Seq( "-deprecation", diff --git a/project/ScoverageWorkFlow.scala b/project/ScoverageWorkFlow.scala index 13fbf07f39..d88efbde86 100644 --- a/project/ScoverageWorkFlow.scala +++ b/project/ScoverageWorkFlow.scala @@ -28,8 +28,8 @@ object ScoverageWorkFlow { id = Some("update_build_definition"), name = Some("Update Build Definition"), ), - WorkflowStep.Run( - commands = List(s"sbt ++${Scala213} coverage 'project zhttp;test' coverageReport"), + WorkflowStep.Sbt( + commands = List(s"coverage; project zhttp; test; coverageReport"), id = Some("run_coverage"), name = Some("Run Coverage"), ), From dfd11acb853e6f5daf068d191193cde7dd8d146e Mon Sep 17 00:00:00 2001 From: Javier Goday Date: Sat, 15 Jan 2022 15:48:12 +0100 Subject: [PATCH 16/95] Add configuration builder methods to zhttp.service.Server (#768) * Add configuration builder methods to zhttp.service.Server * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Change some server with* builder methods (enable parameter) * Server withAcceptContinue(enabled) Co-authored-by: Tushar Mathur --- .../src/main/scala/zhttp/service/Server.scala | 132 +++++++++++++++--- 1 file changed, 110 insertions(+), 22 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 0823b8617b..d0800224f3 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -19,17 +19,17 @@ sealed trait Server[-R, +E] { self => Concat(self, other) private def settings[R1 <: R, E1 >: E](s: Config[R1, E1] = Config()): Config[R1, E1] = self match { - case Concat(self, other) => other.settings(self.settings(s)) - case LeakDetection(level) => s.copy(leakDetectionLevel = level) - case MaxRequestSize(size) => s.copy(maxRequestSize = size) - case Error(errorHandler) => s.copy(error = Some(errorHandler)) - case Ssl(sslOption) => s.copy(sslOption = sslOption) - case App(app) => s.copy(app = app) - case Address(address) => s.copy(address = address) - case AcceptContinue => s.copy(acceptContinue = true) - case KeepAlive => s.copy(keepAlive = true) - case FlowControl => s.copy(flowControl = false) - case ConsolidateFlush => s.copy(consolidateFlush = true) + case Concat(self, other) => other.settings(self.settings(s)) + case LeakDetection(level) => s.copy(leakDetectionLevel = level) + case MaxRequestSize(size) => s.copy(maxRequestSize = size) + case Error(errorHandler) => s.copy(error = Some(errorHandler)) + case Ssl(sslOption) => s.copy(sslOption = sslOption) + case App(app) => s.copy(app = app) + case Address(address) => s.copy(address = address) + case AcceptContinue(enabled) => s.copy(acceptContinue = enabled) + case KeepAlive(enabled) => s.copy(keepAlive = enabled) + case FlowControl(enabled) => s.copy(flowControl = enabled) + case ConsolidateFlush(enabled) => s.copy(consolidateFlush = enabled) } def make(implicit @@ -39,6 +39,81 @@ sealed trait Server[-R, +E] { self => def start(implicit ev: E <:< Throwable): ZIO[R with EventLoopGroup with ServerChannelFactory, Throwable, Nothing] = make.useForever + + /** + * Launches the app with current settings: default EventLoopGroup (nThreads = 0) and ServerChannelFactory.auto. + */ + def startDefault[R1 <: Has[_] with R](implicit ev: E <:< Throwable): ZIO[R1, Throwable, Nothing] = + start.provideSomeLayer[R1](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) + + /** + * Creates a new server with the maximum size of the request specified in bytes. + */ + def withMaxRequestSize(size: Int): Server[R, E] = Concat(self, Server.MaxRequestSize(size)) + + /** + * Creates a new server listening on the provided port. + */ + def withPort(port: Int): Server[R, E] = Concat(self, Server.Address(new InetSocketAddress(port))) + + /** + * Creates a new server listening on the provided hostname and port. + */ + def withBinding(hostname: String, port: Int): Server[R, E] = + Concat(self, Server.Address(new InetSocketAddress(hostname, port))) + + /** + * Creates a new server listening on the provided InetAddress and port. + */ + def withBinding(address: InetAddress, port: Int): Server[R, E] = + Concat(self, Server.Address(new InetSocketAddress(address, port))) + + /** + * Creates a new server listening on the provided InetSocketAddress. + */ + def withBinding(inetSocketAddress: InetSocketAddress): Server[R, E] = Concat(self, Server.Address(inetSocketAddress)) + + /** + * Creates a new server with the errorHandler provided. + */ + def withError[R1](errorHandler: Throwable => ZIO[R1, Nothing, Unit]): Server[R with R1, E] = + Concat(self, Server.Error(errorHandler)) + + /** + * Creates a new server with the following ssl options. + */ + def withSsl(sslOptions: ServerSSLOptions): Server[R, E] = Concat(self, Server.Ssl(sslOptions)) + + /** + * Creates a new server using a HttpServerExpectContinueHandler to send a 100 HttpResponse if necessary. + */ + def withAcceptContinue(enable: Boolean): Server[R, E] = Concat(self, Server.AcceptContinue(enable)) + + /** + * Creates a new server using netty FlowControlHandler if enable (@see FlowControlHandler). + */ + def withFlowControl(enable: Boolean): Server[R, E] = Concat(self, Server.FlowControl(enable)) + + /** + * Creates a new server with the leak detection level provided (@see ResourceLeakDetector.Level). + */ + def withLeakDetection(level: LeakDetectionLevel): Server[R, E] = Concat(self, LeakDetection(level)) + + /** + * Creates a new server with netty's HttpServerKeepAliveHandler to close persistent connections when enable is true + * (@see HttpServerKeepAliveHandler). + */ + def withKeepAlive(enable: Boolean): Server[R, E] = Concat(self, KeepAlive(enable)) + + /** + * Creates a new server with FlushConsolidationHandler to control the flush operations in a more efficient way if + * enabled (@see FlushConsolidationHandler). + */ + def withConsolidateFlush(enable: Boolean): Server[R, E] = Concat(self, ConsolidateFlush(enable)) } object Server { @@ -69,10 +144,10 @@ object Server { private final case class Ssl(sslOptions: ServerSSLOptions) extends UServer private final case class Address(address: InetSocketAddress) extends UServer private final case class App[R, E](app: HttpApp[R, E]) extends Server[R, E] - private case object KeepAlive extends Server[Any, Nothing] - private case object ConsolidateFlush extends Server[Any, Nothing] - private case object AcceptContinue extends UServer - private case object FlowControl extends UServer + private final case class KeepAlive(enabled: Boolean) extends Server[Any, Nothing] + private final case class ConsolidateFlush(enabled: Boolean) extends Server[Any, Nothing] + private final case class AcceptContinue(enabled: Boolean) extends UServer + private final case class FlowControl(enabled: Boolean) extends UServer def app[R, E](http: HttpApp[R, E]): Server[R, E] = Server.App(http) def maxRequestSize(size: Int): UServer = Server.MaxRequestSize(size) @@ -83,14 +158,19 @@ object Server { def bind(inetSocketAddress: InetSocketAddress): UServer = Server.Address(inetSocketAddress) def error[R](errorHandler: Throwable => ZIO[R, Nothing, Unit]): Server[R, Nothing] = Server.Error(errorHandler) def ssl(sslOptions: ServerSSLOptions): UServer = Server.Ssl(sslOptions) - def acceptContinue: UServer = Server.AcceptContinue - def disableFlowControl: UServer = Server.FlowControl + def acceptContinue: UServer = Server.AcceptContinue(true) + def disableFlowControl: UServer = Server.FlowControl(false) val disableLeakDetection: UServer = LeakDetection(LeakDetectionLevel.DISABLED) val simpleLeakDetection: UServer = LeakDetection(LeakDetectionLevel.SIMPLE) val advancedLeakDetection: UServer = LeakDetection(LeakDetectionLevel.ADVANCED) val paranoidLeakDetection: UServer = LeakDetection(LeakDetectionLevel.PARANOID) - val keepAlive: UServer = KeepAlive - val consolidateFlush: UServer = ConsolidateFlush + val keepAlive: UServer = KeepAlive(true) + val consolidateFlush: UServer = ConsolidateFlush(true) + + /** + * Creates a server from a http app. + */ + def apply[R, E](http: HttpApp[R, E]): Server[R, E] = Server.App(http) /** * Launches the app on the provided port. @@ -99,7 +179,9 @@ object Server { port: Int, http: HttpApp[R, Throwable], ): ZIO[R, Throwable, Nothing] = { - (Server.bind(port) ++ Server.app(http)).make + (Server(http) + .withPort(port)) + .make .flatMap(start => ZManaged.succeed(println(s"Server started on port: ${start.port}"))) .useForever .provideSomeLayer[R](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) @@ -110,14 +192,20 @@ object Server { port: Int, http: HttpApp[R, Throwable], ): ZIO[R, Throwable, Nothing] = - (Server.app(http) ++ Server.bind(address, port)).make.useForever + (Server(http) + .withBinding(address, port)) + .make + .useForever .provideSomeLayer[R](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) def start[R <: Has[_]]( socketAddress: InetSocketAddress, http: HttpApp[R, Throwable], ): ZIO[R, Throwable, Nothing] = - (Server.app(http) ++ Server.bind(socketAddress)).make.useForever + (Server(http) + .withBinding(socketAddress)) + .make + .useForever .provideSomeLayer[R](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) def make[R]( From 134a9b5eacb6a426aa1235ba0d906612572f1fa5 Mon Sep 17 00:00:00 2001 From: Shubham Girdhar Date: Tue, 18 Jan 2022 13:26:14 +0530 Subject: [PATCH 17/95] maintenance: html template for internal server error string (#851) Closes #842 --- zio-http/src/main/scala/zhttp/core/Util.scala | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/core/Util.scala b/zio-http/src/main/scala/zhttp/core/Util.scala index ce62f6d5b6..b507578e83 100644 --- a/zio-http/src/main/scala/zhttp/core/Util.scala +++ b/zio-http/src/main/scala/zhttp/core/Util.scala @@ -1,5 +1,7 @@ package zhttp.core +import zhttp.html._ + import java.io.{PrintWriter, StringWriter} object Util { @@ -10,15 +12,12 @@ object Util { } def prettyPrintHtml(throwable: Throwable): String = { - s""" - | - | - | - | - |

Internal Server Error

- |
${prettyPrint(throwable).split("\n").map(str => s"
${str}
").mkString("")}
- | - | - |""".stripMargin + html( + head(), + body( + h1("Internal Server Error"), + pre(div(prettyPrint(throwable).split("\n").mkString("\n"))), + ), + ).encode } } From 13c7d2b7e9e8164234e6759da47212ae0c695631 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 18 Jan 2022 17:03:53 +0530 Subject: [PATCH 18/95] Performance: Improve benchmarking code (#731) * wip: try server codec without validation * wip: remove flush consolidator * wip: use wrapped buffer * wip: add flush consolidator * perf: make response encoding checks faster * use encoder and decoder (#733) * wip: remove Request creation * use encoder and decoder Co-authored-by: Tushar Mathur * disable object aggregator * disable object aggregator * revert disable object aggregator * doc: update scala doc * perf: freeze the HttpResponse Co-authored-by: Amit Kumar Singh Co-authored-by: amitsingh --- .../src/main/scala/zhttp/http/Response.scala | 2 +- .../src/main/scala/zhttp/service/Server.scala | 2 +- .../server/ServerChannelInitializer.scala | 24 ++++++++++++------- .../service/server/WebSocketUpgrade.scala | 2 +- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index e7a9f4dc38..b59d13b08a 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -76,7 +76,7 @@ final case class Response private ( val jHeaders = self.getHeaders.encode val jContent = self.data match { - case HttpData.Text(text, charset) => Unpooled.copiedBuffer(text, charset) + case HttpData.Text(text, charset) => Unpooled.wrappedBuffer(text.getBytes(charset)) case HttpData.BinaryChunk(data) => Unpooled.copiedBuffer(data.toArray) case HttpData.BinaryByteBuf(data) => data case HttpData.BinaryStream(_) => null diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index d0800224f3..cc2137a754 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -159,7 +159,7 @@ object Server { def error[R](errorHandler: Throwable => ZIO[R, Nothing, Unit]): Server[R, Nothing] = Server.Error(errorHandler) def ssl(sslOptions: ServerSSLOptions): UServer = Server.Ssl(sslOptions) def acceptContinue: UServer = Server.AcceptContinue(true) - def disableFlowControl: UServer = Server.FlowControl(false) + val disableFlowControl: UServer = Server.FlowControl(false) val disableLeakDetection: UServer = LeakDetection(LeakDetectionLevel.DISABLED) val simpleLeakDetection: UServer = LeakDetection(LeakDetectionLevel.SIMPLE) val advancedLeakDetection: UServer = LeakDetection(LeakDetectionLevel.ADVANCED) diff --git a/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala b/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala index 055bf7aacf..e66f840e20 100644 --- a/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala +++ b/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala @@ -2,12 +2,12 @@ package zhttp.service.server import io.netty.channel.ChannelHandler.Sharable import io.netty.channel.{Channel, ChannelHandler, ChannelInitializer} -import io.netty.handler.codec.http.{ - HttpObjectAggregator, - HttpServerCodec, - HttpServerExpectContinueHandler, - HttpServerKeepAliveHandler, +import io.netty.handler.codec.http.HttpObjectDecoder.{ + DEFAULT_MAX_CHUNK_SIZE, + DEFAULT_MAX_HEADER_SIZE, + DEFAULT_MAX_INITIAL_LINE_LENGTH, } +import io.netty.handler.codec.http._ import io.netty.handler.flow.FlowControlHandler import io.netty.handler.flush.FlushConsolidationHandler import zhttp.service.Server.Config @@ -31,11 +31,19 @@ final case class ServerChannelInitializer[R]( // SSL // Add SSL Handler if CTX is available val sslctx = if (cfg.sslOption == null) null else cfg.sslOption.sslContext - if (sslctx != null) pipeline.addFirst(SSL_HANDLER, new OptionalSSLHandler(sslctx, cfg.sslOption.httpBehaviour, cfg)) + if (sslctx != null) + pipeline + .addFirst(SSL_HANDLER, new OptionalSSLHandler(sslctx, cfg.sslOption.httpBehaviour, cfg)) // ServerCodec - // Always add ServerCodec - pipeline.addLast(HTTP_SERVER_CODEC, new HttpServerCodec()) // TODO: See if server codec is really required + // Instead of ServerCodec, we should use Decoder and Encoder separately to have more granular control over performance. + pipeline.addLast( + "decoder", + new HttpRequestDecoder(DEFAULT_MAX_INITIAL_LINE_LENGTH, DEFAULT_MAX_HEADER_SIZE, DEFAULT_MAX_CHUNK_SIZE, false), + ) + pipeline.addLast("encoder", new HttpResponseEncoder()) + + // TODO: See if server codec is really required // ObjectAggregator // Always add ObjectAggregator diff --git a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala index 573acb34f7..5ca7cac28d 100644 --- a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala +++ b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala @@ -11,7 +11,7 @@ import zhttp.service.{HttpRuntime, WEB_SOCKET_HANDLER} */ trait WebSocketUpgrade[R] { self: ChannelHandler => final def isWebSocket(res: Response): Boolean = - res.status == Status.SWITCHING_PROTOCOLS && res.attribute.socketApp.nonEmpty + res.status.asJava.code() == Status.SWITCHING_PROTOCOLS.asJava.code() && res.attribute.socketApp.nonEmpty /** * Checks if the response requires to switch protocol to websocket. Returns true if it can, otherwise returns false From e9abd9f4a362cf83f871bbcf55ed3100b9c140f9 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 18 Jan 2022 18:20:22 +0530 Subject: [PATCH 19/95] Refactor: Support middlewares on Http (#773) * refactor: remove type-params from Response * chore: self review * refactor: rename Middleware to HttpMiddleware * refactor: add `@@@` to Http as an alternative to `@@`. * feature: add new Middleware API * feature: add `flatten` and `ifThenElse` * feature: add `ifThenElseZIO` * refactor: fix type params for `identity` * feature: add `when` * feature: add `make` constructor * refactor: make middleware methods final * refactor: git remains * refactor: implement HttpMiddleware as Middleware * scala3 fix * Refactor CORS middleware (#788) * Refactor/merge middleware and http middleware (#790) * Refactor move cors and timeout * move some httpMiddlewares to Middleware * move some AuthMiddleware to Middleware * move remaining AuthMiddleware to Middleware * move Middlewares to middleware package * scaladoc * codec example * move Middleware to http package * named alias for `@@` * rename Auth to AuthMiddlewares * rename CORSMiddleware to CorsMiddlewares * rename CSRF to CsrfMiddlewares * make primitives private * rename MiddlewareExtensions to HttpMiddlewares * rename operators in HttpMiddlewares * scalaDoc * arg rename * doc update and general refactor * simplify cors middleware * rename CorsConfig * renames * Make middlewares package private MiddlewareRequest * Introduce MiddlewareRequest (#798) * Introduce MiddlewareRequest * PR review comments * Refactor move runAfter to Middleware * refactor: add `UMiddleware` * feature: add `contramapZIO` * refactor: move cors config to Cors file * refactor: rename files * refactor: remove AuthSpec from WebSpec * refactor: fix naming for Http operators * refactor: add partial type suport for contraMapZIO * Refactor: Codec (#841) * Add Run Before (#840) * Add Run Before * Add Run Before and After * use renamed operator * refactor: add partial type suport for contraMap * Implement missing operators in Middleware (#807) * Implement missing operators in Middleware * fix as operator * headers Middleware changes * sign cookie * extend with HeaderExtensions * rename suite * PR comments * refactor: use `Request` instead of `MiddlewareRequest` * refactor: rename methods * refactor: resolve fix me issue Co-authored-by: amitsingh Co-authored-by: Amit Kumar Singh --- .../scala/example/HelloWorldWithCORS.scala | 7 +- .../example/HelloWorldWithMiddlewares.scala | 12 +- zio-http/src/main/scala/zhttp/http/CORS.scala | 19 - zio-http/src/main/scala/zhttp/http/Http.scala | 24 +- .../main/scala/zhttp/http/Middleware.scala | 581 +++++++----------- .../scala/zhttp/http/middleware/Auth.scala | 38 ++ .../scala/zhttp/http/middleware/Cors.scala | 76 +++ .../scala/zhttp/http/middleware/Csrf.scala | 44 ++ .../scala/zhttp/http/middleware/Web.scala | 186 ++++++ .../scala/zhttp/http/middleware/package.scala | 5 + .../src/main/scala/zhttp/http/package.scala | 15 +- .../scala/zhttp/http/MiddlewareSpec.scala | 157 +++++ .../zhttp/http/middleware/AuthSpec.scala | 29 + .../zhttp/http/middleware/CorsSpec.scala | 54 ++ .../zhttp/http/middleware/CsrfSpec.scala | 39 ++ .../scala/zhttp/http/middleware/WebSpec.scala | 181 ++++++ .../zhttp/middleware/MiddlewareSpec.scala | 243 -------- 17 files changed, 1079 insertions(+), 631 deletions(-) delete mode 100644 zio-http/src/main/scala/zhttp/http/CORS.scala create mode 100644 zio-http/src/main/scala/zhttp/http/middleware/Auth.scala create mode 100644 zio-http/src/main/scala/zhttp/http/middleware/Cors.scala create mode 100644 zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala create mode 100644 zio-http/src/main/scala/zhttp/http/middleware/Web.scala create mode 100644 zio-http/src/main/scala/zhttp/http/middleware/package.scala create mode 100644 zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala create mode 100644 zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala create mode 100644 zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala create mode 100644 zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala create mode 100644 zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala delete mode 100644 zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala diff --git a/example/src/main/scala/example/HelloWorldWithCORS.scala b/example/src/main/scala/example/HelloWorldWithCORS.scala index 4977102c68..23d54560e8 100644 --- a/example/src/main/scala/example/HelloWorldWithCORS.scala +++ b/example/src/main/scala/example/HelloWorldWithCORS.scala @@ -1,15 +1,16 @@ package example import zhttp.http.Middleware.cors -import zhttp.http.{CORSConfig, HttpApp, Method, Response, _} +import zhttp.http._ +import zhttp.http.middleware.Cors.CorsConfig import zhttp.service.Server import zio.{App, ExitCode, URIO} object HelloWorldWithCORS extends App { // Create CORS configuration - val config: CORSConfig = - CORSConfig(allowedOrigins = _ == "dev", allowedMethods = Some(Set(Method.PUT, Method.DELETE))) + val config: CorsConfig = + CorsConfig(allowedOrigins = _ == "dev", allowedMethods = Some(Set(Method.PUT, Method.DELETE))) // Create HTTP route with CORS enabled val app: HttpApp[Any, Nothing] = diff --git a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala index 914e914227..b9c83d53de 100644 --- a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala +++ b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala @@ -1,7 +1,7 @@ package example -import zhttp.http.Middleware.{addHeader, debug, patchZIO, timeout} import zhttp.http._ +import zhttp.http.middleware.HttpMiddleware import zhttp.service.Server import zio.clock.{Clock, currentTime} import zio.console.Console @@ -20,20 +20,20 @@ object HelloWorldWithMiddlewares extends App { case Method.GET -> !! / "long-running" => ZIO.succeed(Response.text("Hello World!")).delay(5 seconds) } - val serverTime: Middleware[Clock, Nothing] = patchZIO((_, _) => + val serverTime: HttpMiddleware[Clock, Nothing] = Middleware.patchZIO(_ => for { currentMilliseconds <- currentTime(TimeUnit.MILLISECONDS) withHeader = Patch.addHeader("X-Time", currentMilliseconds.toString) } yield withHeader, ) - val middlewares: Middleware[Console with Clock, IOException] = + val middlewares: HttpMiddleware[Console with Clock, IOException] = // print debug info about request and response - debug ++ + Middleware.debug ++ // close connection if request takes more than 3 seconds - timeout(3 seconds) ++ + Middleware.timeout(3 seconds) ++ // add static header - addHeader("X-Environment", "Dev") ++ + Middleware.addHeader("X-Environment", "Dev") ++ // add dynamic header serverTime diff --git a/zio-http/src/main/scala/zhttp/http/CORS.scala b/zio-http/src/main/scala/zhttp/http/CORS.scala deleted file mode 100644 index ff2b80059e..0000000000 --- a/zio-http/src/main/scala/zhttp/http/CORS.scala +++ /dev/null @@ -1,19 +0,0 @@ -package zhttp.http - -import io.netty.handler.codec.http.HttpHeaderNames - -final case class CORSConfig( - anyOrigin: Boolean = false, - anyMethod: Boolean = true, - allowCredentials: Boolean = false, - allowedOrigins: String => Boolean = _ => false, - allowedMethods: Option[Set[Method]] = None, - allowedHeaders: Option[Set[String]] = Some( - Set(HttpHeaderNames.CONTENT_TYPE.toString, HttpHeaderNames.AUTHORIZATION.toString, "*"), - ), - exposedHeaders: Option[Set[String]] = Some(Set("*")), -) - -object CORS { - def DefaultCORSConfig = CORSConfig(anyOrigin = true, allowCredentials = true) -} diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 03dded42f3..b5794b9fbc 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -19,6 +19,13 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => import Http._ + /** + * Attaches the provided middleware to the Http app + */ + final def @@[R1 <: R, E1 >: E, A1 <: A, B1 >: B, A2, B2]( + mid: Middleware[R1, E1, A1, B1, A2, B2], + ): Http[R1, E1, A2, B2] = mid(self) + /** * Alias for flatmap */ @@ -180,6 +187,13 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def mapZIO[R1 <: R, E1 >: E, C](bFc: B => ZIO[R1, E1, C]): Http[R1, E1, A, C] = self >>> Http.fromFunctionZIO(bFc) + /** + * Named alias for @@ + */ + final def middleware[R1 <: R, E1 >: E, A1 <: A, B1 >: B, A2, B2]( + mid: Middleware[R1, E1, A1, B1, A2, B2], + ): Http[R1, E1, A2, B2] = mid(self) + /** * Named alias for `<>` */ @@ -342,16 +356,6 @@ object Http { implicit final class HttpAppSyntax[-R, +E](val http: HttpApp[R, E]) extends HeaderModifier[HttpApp[R, E]] { self => - /** - * Attaches the provided middleware to the HttpApp - */ - def @@[R1 <: R, E1 >: E](mid: Middleware[R1, E1]): HttpApp[R1, E1] = middleware(mid) - - /** - * Attaches the provided middleware to the HttpApp - */ - def middleware[R1 <: R, E1 >: E](mid: Middleware[R1, E1]): HttpApp[R1, E1] = mid(http) - /** * Patches the response produced by the app */ diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index 7b6776b62b..831d1f8afd 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -1,468 +1,363 @@ package zhttp.http -import io.netty.handler.codec.http.HttpHeaderNames -import io.netty.util.AsciiString.contentEqualsIgnoreCase -import zhttp.http.CORS.DefaultCORSConfig -import zhttp.http.Headers.BasicSchemeName -import zhttp.http.Middleware.{Flag, RequestP} +import zhttp.http.middleware.Web import zio.clock.Clock -import zio.console.Console import zio.duration.Duration -import zio.{UIO, ZIO, clock, console} - -import java.io.IOException -import java.util.UUID +import zio.{UIO, ZIO} /** - * Middlewares for Http. + * Middlewares are essentially transformations that one can apply on any Http to produce a new one. They can modify + * requests and responses and also transform them into more concrete domain entities. + * + * You can think of middlewares as a functions — + * + * {{{ + * type Middleware[R, E, AIn, BIn, AOut, BOut] = Http[R, E, AIn, BIn] => Http[R, E, AOut, BOut] + * }}} + * + * The `AIn` and `BIn` type params represent the type params of the input Http. The `AOut` and `BOut` type params + * represent the type params of the output Http. */ -sealed trait Middleware[-R, +E] { self => - final def <>[R1 <: R, E1](other: Middleware[R1, E1]): Middleware[R1, E1] = - self orElse other - - final def ++[R1 <: R, E1 >: E](other: Middleware[R1, E1]): Middleware[R1, E1] = - self combine other - - final def apply[R1 <: R, E1 >: E](app: HttpApp[R1, E1]): HttpApp[R1, E1] = self.execute(app, Middleware.Flag()) - - final def as[R1 <: R, E1 >: E](app: HttpApp[R1, E1]): Middleware[R1, E1] = - Middleware.Constant(app) - - final def combine[R1 <: R, E1 >: E](other: Middleware[R1, E1]): Middleware[R1, E1] = - Middleware.Combine(self, other) - - final def delay(duration: Duration): Middleware[R with Clock, E] = { - self.modifyZIO((_, _, _) => UIO(self).delay(duration)) - } - - final def execute[R1 <: R, E1 >: E](app: HttpApp[R1, E1], flags: Flag): HttpApp[R1, E1] = - Middleware.execute(self, app, flags) - - final def modify[R1 <: R, E1 >: E](f: RequestP[Middleware[R1, E1]]): Middleware[R1, E1] = - Middleware.fromMiddlewareFunction((m, u, h) => f(m, u, h)) - - final def modifyZIO[R1 <: R, E1 >: E]( - f: RequestP[ZIO[R1, Option[E1], Middleware[R1, E1]]], - ): Middleware[R1, E1] = - Middleware.fromMiddlewareFunctionZIO((m, u, h) => f(m, u, h)) - - final def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[R, E] = Middleware.modifyHeaders(f) - - final def orElse[R1 <: R, E1](other: Middleware[R1, E1]): Middleware[R1, E1] = - Middleware.OrElse(self, other) - - final def race[R1 <: R, E1 >: E](other: Middleware[R1, E1]): Middleware[R1, E1] = - Middleware.Race(self, other) - - final def setEmpty(flag: Boolean): Middleware[R, E] = Middleware.EmptyFlag(self, flag) - - final def when(f: RequestP[Boolean]): Middleware[R, E] = - modify((m, u, h) => if (f(m, u, h)) self else Middleware.identity) - - final def withEmpty: Middleware[R, E] = self.setEmpty(true) - - final def withoutEmpty: Middleware[R, E] = self.setEmpty(false) -} - -object Middleware { - - type RequestP[+A] = (Method, URL, Headers) => A +sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => /** - * Sets cookie in response headers + * Creates a new middleware that passes the output Http of the current middleware as the input to the provided + * middleware. */ - def addCookie(cookie: Cookie): Middleware[Any, Nothing] = - Middleware.addHeader(Headers.setCookie(cookie)) + final def >>>[R1 <: R, E1 >: E, AIn1 <: AOut, BIn1 >: BOut, AOut1, BOut1]( + other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], + ): Middleware[R1, E1, AIn, BIn, AOut1, BOut1] = self andThen other /** - * Adds the provided header and value to the response + * Applies self but if it fails, applies other. */ - def addHeader(name: String, value: String): Middleware[Any, Nothing] = - patch((_, _) => Patch.addHeader(name, value)) + final def <>[R1 <: R, E1, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0 >: BOut]( + other: Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], + ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = self orElse other /** - * Adds the provided header to the response + * Combines two middleware that don't modify the input and output types. */ - def addHeader(header: Headers): Middleware[Any, Nothing] = - patch((_, _) => Patch.addHeader(header)) + final def ++[R1 <: R, E1 >: E, A0 >: AIn <: AOut, B0 >: BOut <: BIn]( + other: Middleware[R1, E1, A0, B0, A0, B0], + ): Middleware[R1, E1, A0, B0, A0, B0] = + self combine other /** - * Adds the provided list of headers to the response + * Composes one middleware with another. */ - def addHeaders(headers: Headers): Middleware[Any, Nothing] = - patch((_, _) => Patch.addHeader(headers)) + final def andThen[R1 <: R, E1 >: E, AIn1 <: AOut, BIn1 >: BOut, AOut1, BOut1]( + other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], + ): Middleware[R1, E1, AIn, BIn, AOut1, BOut1] = Middleware.AndThen(self, other) /** - * Modifies the provided list of headers to the updated list of headers + * Applies middleware on Http and returns new Http. */ - def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[Any, Nothing] = - patch((_, _) => Patch.updateHeaders(_.modify(f))) + final def apply[R1 <: R, E1 >: E](http: Http[R1, E1, AIn, BIn]): Http[R1, E1, AOut, BOut] = execute(http) /** - * Creates an authentication middleware that only allows authenticated requests to be passed on to the app. + * Makes the middleware resolve with a constant Middleware */ - def auth(verify: Headers => Boolean, responseHeaders: Headers = Headers.empty): Middleware[Any, Nothing] = - ifThenElse((_, _, h) => verify(h))( - Middleware.identity, - Middleware.Constant(Http.status(Status.FORBIDDEN).addHeaders(responseHeaders)), - ) + final def as[BOut0]( + bout: BOut0, + ): Middleware[R, E, AIn, BIn, AOut, BOut0] = + self.map(_ => bout) /** - * Creates a middleware for basic authentication + * Combines two middleware that operate on the same input and output types, into one. */ - def basicAuth(f: Header => Boolean): Middleware[Any, Nothing] = - auth( - _.getBasicAuthorizationCredentials match { - case Some(header) => f(header) - case None => false - }, - Headers(HttpHeaderNames.WWW_AUTHENTICATE, BasicSchemeName), - ) + final def combine[R1 <: R, E1 >: E, A0 >: AIn <: AOut, B0 >: BOut <: BIn]( + other: Middleware[R1, E1, A0, B0, A0, B0], + ): Middleware[R1, E1, A0, B0, A0, B0] = + self andThen other /** - * Creates a middleware for basic authentication that checks if the credentials are same as the ones given + * Preprocesses the incoming value for the outgoing Http. */ - def basicAuth(u: String, p: String): Middleware[Any, Nothing] = - basicAuth { case (user, password) => (user == u) && (password == p) } - - def addCookieM[R, E](cookie: ZIO[R, E, Cookie]): Middleware[R, E] = - patchZIO((_, _) => cookie.mapBoth(Option(_), c => Patch.addHeader(Headers.setCookie(c)))) + final def contramap[AOut0](f: AOut0 => AOut): Middleware[R, E, AIn, BIn, AOut0, BOut] = + self.contramapZIO[AOut0](a => UIO(f(a))) /** - * CSRF middlewares : To prevent Cross-site request forgery attacks. This middleware is modeled after the double - * submit cookie pattern. - * @see - * [[Middleware#csrfGenerate]] - Sets cookie with CSRF token - * @see - * [[Middleware#csrfValidate]] - Validate token value in request headers against value in cookies - * @see - * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie + * Preprocesses the incoming value using a ZIO, for the outgoing Http. */ - - def csrfGenerate[R, E]( - tokenName: String = "x-csrf-token", - tokenGen: ZIO[R, Nothing, String] = UIO(UUID.randomUUID.toString), - ): Middleware[R, E] = - addCookieM(tokenGen.map(Cookie(tokenName, _))) - - def csrfValidate(tokenName: String = "x-csrf-token"): Middleware[Any, Nothing] = { - whenHeader( - headers => { - (headers.getHeaderValue(tokenName), headers.getCookieValue(tokenName)) match { - case (Some(headerValue), Some(cookieValue)) => headerValue != cookieValue - case _ => true - } - }, - Middleware.Constant(Http.status(Status.FORBIDDEN)), - ) - } + final def contramapZIO[AOut0]: Middleware.PartialContraMapZIO[R, E, AIn, BIn, AOut, BOut, AOut0] = + new Middleware.PartialContraMapZIO(self) /** - * Creates a middleware for Cross-Origin Resource Sharing (CORS). - * @see - * https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS + * Delays the production of Http output for the specified duration */ - def cors[R, E](config: CORSConfig = DefaultCORSConfig): Middleware[R, E] = { - def allowCORS(origin: Header, acrm: Method): Boolean = - (config.anyOrigin, config.anyMethod, origin._2.toString, acrm) match { - case (true, true, _, _) => true - case (true, false, _, acrm) => - config.allowedMethods.exists(_.contains(acrm)) - case (false, true, origin, _) => config.allowedOrigins(origin) - case (false, false, origin, acrm) => - config.allowedMethods.exists(_.contains(acrm)) && - config.allowedOrigins(origin) - } - def corsHeaders(origin: Header, method: Method, isPreflight: Boolean): Headers = { - Headers.ifThenElse(isPreflight)( - onTrue = config.allowedHeaders.fold(Headers.empty) { h => - Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString(), h.mkString(",")) - }, - onFalse = config.exposedHeaders.fold(Headers.empty) { h => - Headers(HttpHeaderNames.ACCESS_CONTROL_EXPOSE_HEADERS.toString(), h.mkString(",")) - }, - ) ++ - Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), origin._2) ++ - Headers( - HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString(), - config.allowedMethods.fold(method.toString())(m => m.map(m => m.toString()).mkString(",")), - ) ++ - Headers.when(config.allowCredentials) { - Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS, config.allowCredentials.toString) - } - } - - val existingRoutesWithHeaders = Middleware.make((method, _, headers) => { - ( - method, - headers.getHeader(HttpHeaderNames.ORIGIN), - ) match { - case (_, Some(origin)) if allowCORS(origin, method) => (Some(origin), method) - case _ => (None, method) - } - })((_, _, s) => { - s match { - case (Some(origin), method) => - Patch.addHeader(corsHeaders(origin, method, isPreflight = false)) - case _ => Patch.empty - } - }) - - val optionsHeaders = fromMiddlewareFunction { case (method, _, headers) => - ( - method, - headers.getHeader(HttpHeaderNames.ORIGIN), - headers.getHeader(HttpHeaderNames.ACCESS_CONTROL_REQUEST_METHOD), - ) match { - case (Method.OPTIONS, Some(origin), Some(acrm)) if allowCORS(origin, Method.fromString(acrm._2.toString)) => - fromApp( - ( - Http.succeed( - Response( - Status.NO_CONTENT, - headers = corsHeaders(origin, Method.fromString(acrm._2.toString), isPreflight = true), - ), - ), - ), - ) - case _ => identity - } - } - - existingRoutesWithHeaders orElse optionsHeaders - } + final def delay(duration: Duration): Middleware[R with Clock, E, AIn, BIn, AOut, BOut] = + self.mapZIO(b => UIO(b).delay(duration)) /** - * Add log status, method, url and time taken from req to res + * Creates a new Middleware from another */ - def debug: Middleware[Console with Clock, IOException] = - Middleware.makeZIO((method, url, _) => zio.clock.nanoTime.map(start => (method, url, start))) { - case (status, _, (method, url, start)) => - for { - end <- clock.nanoTime - _ <- console - .putStrLn(s"${status.asJava.code()} ${method} ${url.asString} ${(end - start) / 1000000}ms") - .mapError(Option(_)) - } yield Patch.empty - } + final def flatMap[R1 <: R, E1 >: E, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0]( + f: BOut => Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], + ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = + Middleware.FlatMap(self, f) /** - * Creates a middleware for signing cookies + * Flattens an Middleware of a Middleware */ - def signCookies(secret: String): Middleware[Any, Nothing] = - modifyHeaders { - case h if contentEqualsIgnoreCase(h._1, HeaderNames.setCookie) => - (HeaderNames.setCookie, Cookie.decodeResponseCookie(h._2.toString).get.sign(secret).encode) - } + final def flatten[R1 <: R, E1 >: E, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0](implicit + ev: BOut <:< Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], + ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = + flatMap(identity(_)) /** - * Creates a new constants middleware that always executes the app provided, independent of where the middleware is - * applied + * Transforms the output type of the current middleware. */ - def fromApp[R, E](app: HttpApp[R, E]): Middleware[R, E] = Middleware.Constant(app) + final def map[BOut0](f: BOut => BOut0): Middleware[R, E, AIn, BIn, AOut, BOut0] = + self.flatMap(b => Middleware.succeed(f(b))) /** - * Creates a new middleware using a function from request parameters to a HttpMiddleware + * Transforms the output type of the current middleware using effect function. */ - def fromMiddlewareFunction[R, E](f: RequestP[Middleware[R, E]]): Middleware[R, E] = - fromMiddlewareFunctionZIO((method, url, headers) => UIO(f(method, url, headers))) + final def mapZIO[R1 <: R, E1 >: E, BOut0](f: BOut => ZIO[R1, E1, BOut0]): Middleware[R1, E1, AIn, BIn, AOut, BOut0] = + self.flatMap(b => Middleware.fromHttp(Http.fromZIO(f(b)))) /** - * Creates a new middleware using a function from request parameters to a ZIO of HttpMiddleware + * Applies self but if it fails, applies other. */ - def fromMiddlewareFunctionZIO[R, E](f: RequestP[ZIO[R, Option[E], Middleware[R, E]]]): Middleware[R, E] = - Middleware.FromFunctionZIO(f) + final def orElse[R1 <: R, E1, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0 >: BOut]( + other: Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], + ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = + Middleware.OrElse(self, other) /** - * An empty middleware that doesn't do anything + * Race between current and other, cancels other when execution of one completes */ - def identity: Middleware[Any, Nothing] = Identity + final def race[R1 <: R, E1 >: E, AIn1 >: AIn, BIn1 <: BIn, AOut1 <: AOut, BOut1 >: BOut]( + other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], + ): Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1] = + Middleware.Race(self, other) - /** - * Logical operator to decide which middleware to select based on the header - */ - def ifHeader[R, E](cond: Headers => Boolean)(left: Middleware[R, E], right: Middleware[R, E]): Middleware[R, E] = - ifThenElse((_, _, headers) => cond(headers))(left, right) + final def runAfter[R1 <: R, E1 >: E](effect: ZIO[R1, E1, Any]): Middleware[R1, E1, AIn, BIn, AOut, BOut] = + self.mapZIO(bOut => effect.as(bOut)) + + final def runBefore[R1 <: R, E1 >: E](effect: ZIO[R1, E1, Any]): Middleware[R1, E1, AIn, BIn, AOut, BOut] = + self.contramapZIO(b => effect.as(b)) /** - * Logical operator to decide which middleware to select based on the predicate. + * Applies Middleware based only if the condition function evaluates to true */ - def ifThenElse[R, E]( - cond: RequestP[Boolean], - )(left: Middleware[R, E], right: Middleware[R, E]): Middleware[R, E] = - Middleware.FromFunctionZIO((method, url, headers) => UIO(if (cond(method, url, headers)) left else right)) + final def when[AOut0 <: AOut](cond: AOut0 => Boolean): Middleware[R, E, AIn, BIn, AOut0, BOut] = + whenZIO(a => UIO(cond(a))) /** - * Logical operator to decide which middleware to select based on the predicate. + * Applies Middleware based only if the condition effectful function evaluates to true */ - def ifThenElseZIO[R, E]( - cond: RequestP[ZIO[R, E, Boolean]], - )(left: Middleware[R, E], right: Middleware[R, E]): Middleware[R, E] = - Middleware.FromFunctionZIO((method, url, headers) => - cond(method, url, headers).mapBoth( - Option(_), - { - case true => left - case false => right - }, - ), + final def whenZIO[R1 <: R, E1 >: E, AOut0 <: AOut]( + cond: AOut0 => ZIO[R1, E1, Boolean], + ): Middleware[R1, E1, AIn, BIn, AOut0, BOut] = + Middleware.ifThenElseZIO[AOut0](cond(_))( + isTrue = _ => self, + isFalse = _ => Middleware.identity, ) /** - * Creates a new middleware using transformation functions + * Applies Middleware and returns a transformed Http app */ - def make[S](req: (Method, URL, Headers) => S): PartiallyAppliedMake[S] = PartiallyAppliedMake(req) + private[zhttp] final def execute[R1 <: R, E1 >: E](http: Http[R1, E1, AIn, BIn]): Http[R1, E1, AOut, BOut] = + Middleware.execute(http, self) +} - /** - * Creates a new middleware using effectful transformation functions - */ - def makeZIO[R, E, S](req: (Method, URL, Headers) => ZIO[R, Option[E], S]): PartiallyAppliedMakeZIO[R, E, S] = - PartiallyAppliedMakeZIO(req) +object Middleware extends Web { /** - * Creates a middleware that produces a Patch for the Response + * Creates a middleware using specified encoder and decoder */ - def patch[R, E](f: (Status, Headers) => Patch): Middleware[R, E] = - Middleware.make((_, _, _) => ())((status, headers, _) => f(status, headers)) + def codec[A, B]: PartialCodec[A, B] = new PartialCodec[A, B](()) /** - * Creates a middleware that produces a Patch for the Response effectfully. + * Creates a middleware using specified effectful encoder and decoder */ - def patchZIO[R, E](f: (Status, Headers) => ZIO[R, Option[E], Patch]): Middleware[R, E] = - Middleware.makeZIO((_, _, _) => ZIO.unit)((status, headers, _) => f(status, headers)) + def codecZIO[A, B]: PartialCodecZIO[A, B] = new PartialCodecZIO[A, B](()) /** - * Removes the header by name + * Creates a middleware using specified function */ - def removeHeader(name: String): Middleware[Any, Nothing] = - patch((_, _) => Patch.removeHeaders(List(name))) + def collect[A]: PartialCollect[A] = new PartialCollect[A](()) /** - * Runs the effect after the response is produced + * Creates a middleware using specified effect function */ - def runAfter[R, E](effect: ZIO[R, E, Any]): Middleware[R, E] = - patchZIO((_, _) => effect.mapBoth(Option(_), _ => Patch.empty)) + def collectZIO[A]: PartialCollectZIO[A] = new PartialCollectZIO[A](()) /** - * Runs the effect before the request is passed on to the HttpApp on which the middleware is applied. + * Creates a middleware which always fail with specified error */ - def runBefore[R, E](effect: ZIO[R, E, Any]): Middleware[R, E] = - Middleware.makeZIO((_, _, _) => effect.mapError(Option(_)).unit)((_, _, _) => UIO(Patch.empty)) + def fail[E](e: E): Middleware[Any, E, Nothing, Any, Any, Nothing] = Fail(e) /** - * Creates a new middleware that always sets the response status to the provided value + * Creates a middleware with specified http App */ - def status(status: Status): Middleware[Any, Nothing] = Middleware.patch((_, _) => Patch.setStatus(status)) + def fromHttp[R, E, A, B](http: Http[R, E, A, B]): Middleware[R, E, Nothing, Any, A, B] = Constant(http) /** - * Times out the application with a 408 status code. + * An empty middleware that doesn't do anything */ - def timeout(duration: Duration): Middleware[Clock, Nothing] = - Middleware.identity.race(Middleware.fromApp(Http.status(Status.REQUEST_TIMEOUT).delayAfter(duration))) + def identity: Middleware[Any, Nothing, Nothing, Any, Any, Nothing] = Middleware.Identity /** - * Applies the middleware only if the condition function evaluates to true + * Logical operator to decide which middleware to select based on the predicate. */ - def when[R, E](cond: RequestP[Boolean])(middleware: Middleware[R, E]): Middleware[R, E] = - ifThenElse(cond)(middleware, Middleware.identity) + def ifThenElse[A]: PartialIfThenElse[A] = new PartialIfThenElse(()) /** - * Applies the middleware only when the condition for the headers are true + * Logical operator to decide which middleware to select based on the predicate effect. */ - def whenHeader[R, E](cond: Headers => Boolean, other: Middleware[R, E]): Middleware[R, E] = - when((_, _, headers) => cond(headers))(other) + def ifThenElseZIO[A]: PartialIfThenElseZIO[A] = new PartialIfThenElseZIO(()) /** - * Switches control to the app only when the condition for the headers are true + * Creates a new middleware using transformation functions */ - def whenHeader[R, E](cond: Headers => Boolean, other: HttpApp[R, E]): Middleware[R, E] = - when((_, _, headers) => cond(headers))(Middleware.fromApp(other)) + def intercept[A, B]: PartialIntercept[A, B] = new PartialIntercept[A, B](()) /** - * Applies the middleware only if the condition function effectfully evaluates to true + * Creates a new middleware using effectful transformation functions */ - def whenZIO[R, E](cond: RequestP[ZIO[R, E, Boolean]])(middleware: Middleware[R, E]): Middleware[R, E] = - ifThenElseZIO(cond)(middleware, Middleware.identity) + def interceptZIO[A, B]: PartialInterceptZIO[A, B] = new PartialInterceptZIO[A, B](()) /** - * Applies the middleware on an HttpApp + * Creates a middleware which always succeed with specified value */ - private[zhttp] def execute[R, E](mid: Middleware[R, E], app: HttpApp[R, E], flag: Flag): HttpApp[R, E] = - mid match { - case Identity => app + def succeed[B](b: B): Middleware[Any, Nothing, Nothing, Any, Any, B] = fromHttp(Http.succeed(b)) - case EmptyFlag(mid, status) => - execute(mid, app, flag.copy(withEmpty = status)) - - case TransformZIO(reqF, resF) => - Http.fromOptionFunction { req => + private[zhttp] def execute[R, E, AIn, BIn, AOut, BOut]( + http: Http[R, E, AIn, BIn], + self: Middleware[R, E, AIn, BIn, AOut, BOut], + ): Http[R, E, AOut, BOut] = + self match { + case Identity => http.asInstanceOf[Http[R, E, AOut, BOut]] + case Constant(http) => http + case OrElse(self, other) => self.execute(http).orElse(other.execute(http)) + case Fail(error) => Http.fail(error) + case AndThen(self, other) => other.execute(self.execute(http)) + case FlatMap(self, f) => self.execute(http).flatMap(f(_).execute(http)) + case ContraMapZIO(self, f) => self.execute(http).contramapZIO(a => f(a)) + case Race(self, other) => self.execute(http) race other.execute(http) + case Intercept(incoming, outgoing) => + Http.fromOptionFunction[AOut] { a => for { - s <- reqF(req.method, req.url, req.getHeaders) - res <- - if (flag.withEmpty) app(req).catchSome { case None => UIO(Response.status(Status.NOT_FOUND)) } - else app(req) - patch <- resF(res.status, res.getHeaders, s) - } yield patch(res) + s <- incoming(a) + b <- http(a.asInstanceOf[AIn]) + c <- outgoing(b, s) + } yield c.asInstanceOf[BOut] } + } - case Combine(self, other) => other.execute(self.execute(app, flag), flag) + final class PartialCollect[AOut](val unit: Unit) extends AnyVal { + def apply[R, E, AIn, BIn, BOut]( + f: PartialFunction[AOut, Middleware[R, E, AIn, BIn, AOut, BOut]], + ): Middleware[R, E, AIn, BIn, AOut, BOut] = + Middleware.fromHttp(Http.collect[AOut] { case aout if f.isDefinedAt(aout) => f(aout) }).flatten + } - case FromFunctionZIO(reqF) => - Http.fromOptionFunction { req => - for { - output <- reqF(req.method, req.url, req.getHeaders) - res <- output.execute(app, flag)(req) - } yield res - } + final class PartialCollectZIO[AOut](val unit: Unit) extends AnyVal { + def apply[R, E, AIn, BIn, BOut]( + f: PartialFunction[AOut, ZIO[R, E, Middleware[R, E, AIn, BIn, AOut, BOut]]], + ): Middleware[R, E, AIn, BIn, AOut, BOut] = + Middleware.fromHttp(Http.collectZIO[AOut] { case aout if f.isDefinedAt(aout) => f(aout) }).flatten + } - case Race(self, other) => - Http.fromOptionFunction { req => - self.execute(app, flag)(req) raceFirst other.execute(app, flag)(req) - } + final class PartialIntercept[A, B](val unit: Unit) extends AnyVal { + def apply[S, BOut](incoming: A => S)(outgoing: (B, S) => BOut): Middleware[Any, Nothing, A, B, A, BOut] = + interceptZIO[A, B](a => UIO(incoming(a)))((b, s) => UIO(outgoing(b, s))) + } + + final class PartialInterceptZIO[A, B](val unit: Unit) extends AnyVal { + def apply[R, E, S, BOut]( + incoming: A => ZIO[R, Option[E], S], + ): PartialInterceptOutgoingZIO[R, E, A, S, B] = + new PartialInterceptOutgoingZIO(incoming) + } - case Constant(self) => self + final class PartialInterceptOutgoingZIO[-R, +E, A, +S, B](val incoming: A => ZIO[R, Option[E], S]) extends AnyVal { + def apply[R1 <: R, E1 >: E, BOut]( + outgoing: (B, S) => ZIO[R1, Option[E1], BOut], + ): Middleware[R1, E1, A, B, A, BOut] = + Intercept(incoming, outgoing) + } - case OrElse(self, other) => - Http.fromOptionFunction { req => - (self.execute(app, flag)(req) orElse other.execute(app, flag)(req)) - .asInstanceOf[ZIO[R, Option[E], Response]] - } - } + final class PartialCodec[AOut, BIn](val unit: Unit) extends AnyVal { + def apply[E, AIn, BOut]( + decoder: AOut => Either[E, AIn], + encoder: BIn => Either[E, BOut], + ): Middleware[Any, E, AIn, BIn, AOut, BOut] = + Middleware.identity.mapZIO((b: BIn) => ZIO.fromEither(encoder(b))).contramapZIO(a => ZIO.fromEither(decoder(a))) + } - final case class Flag(withEmpty: Boolean = false) + final class PartialIfThenElse[AOut](val unit: Unit) extends AnyVal { + def apply[R, E, AIn, BIn, BOut](cond: AOut => Boolean)( + isTrue: AOut => Middleware[R, E, AIn, BIn, AOut, BOut], + isFalse: AOut => Middleware[R, E, AIn, BIn, AOut, BOut], + ): Middleware[R, E, AIn, BIn, AOut, BOut] = + Middleware + .fromHttp(Http.fromFunction[AOut] { a => if (cond(a)) isTrue(a) else isFalse(a) }) + .flatten + } + + final class PartialIfThenElseZIO[AOut](val unit: Unit) extends AnyVal { + def apply[R, E, AIn, BIn, BOut](cond: AOut => ZIO[R, E, Boolean])( + isTrue: AOut => Middleware[R, E, AIn, BIn, AOut, BOut], + isFalse: AOut => Middleware[R, E, AIn, BIn, AOut, BOut], + ): Middleware[R, E, AIn, BIn, AOut, BOut] = + Middleware + .fromHttp(Http.fromFunctionZIO[AOut] { a => cond(a).map(b => if (b) isTrue(a) else isFalse(a)) }) + .flatten + } - final case class PartiallyAppliedMake[S](req: (Method, URL, Headers) => S) extends AnyVal { - def apply(res: (Status, Headers, S) => Patch): Middleware[Any, Nothing] = - TransformZIO[Any, Nothing, S]( - (method, url, headers) => UIO(req(method, url, headers)), - (status, headers, state) => UIO(res(status, headers, state)), - ) + final class PartialCodecZIO[AOut, BIn](val unit: Unit) extends AnyVal { + def apply[R, E, AIn, BOut]( + decoder: AOut => ZIO[R, E, AIn], + encoder: BIn => ZIO[R, E, BOut], + ): Middleware[R, E, AIn, BIn, AOut, BOut] = + Middleware.identity.mapZIO(encoder).contramapZIO(decoder) } - final case class PartiallyAppliedMakeZIO[R, E, S](req: (Method, URL, Headers) => ZIO[R, Option[E], S]) - extends AnyVal { - def apply[R1 <: R, E1 >: E](res: (Status, Headers, S) => ZIO[R1, Option[E1], Patch]): Middleware[R1, E1] = - TransformZIO(req, res) + final class PartialContraMapZIO[-R, +E, +AIn, -BIn, -AOut, +BOut, AOut0]( + val self: Middleware[R, E, AIn, BIn, AOut, BOut], + ) extends AnyVal { + def apply[R1 <: R, E1 >: E](f: AOut0 => ZIO[R1, E1, AOut]): Middleware[R1, E1, AIn, BIn, AOut0, BOut] = + ContraMapZIO[R1, E1, AIn, BIn, AOut, BOut, AOut0](self, f) } - private final case class EmptyFlag[R, E](mid: Middleware[R, E], status: Boolean) extends Middleware[R, E] + private final case class Fail[E](error: E) extends Middleware[Any, E, Nothing, Any, Any, Nothing] + + private final case class OrElse[R, E0, E1, AIn, BIn, AOut, BOut]( + self: Middleware[R, E0, AIn, BIn, AOut, BOut], + other: Middleware[R, E1, AIn, BIn, AOut, BOut], + ) extends Middleware[R, E1, AIn, BIn, AOut, BOut] - private final case class TransformZIO[R, E, S]( - req: (Method, URL, Headers) => ZIO[R, Option[E], S], - res: (Status, Headers, S) => ZIO[R, Option[E], Patch], - ) extends Middleware[R, E] + private final case class Constant[R, E, AOut, BOut](http: Http[R, E, AOut, BOut]) + extends Middleware[R, E, Nothing, Any, AOut, BOut] - private final case class Combine[R, E](self: Middleware[R, E], other: Middleware[R, E]) extends Middleware[R, E] + private final case class Intercept[R, E, A, B, S, BOut]( + incoming: A => ZIO[R, Option[E], S], + outgoing: (B, S) => ZIO[R, Option[E], BOut], + ) extends Middleware[R, E, A, B, A, BOut] - private final case class FromFunctionZIO[R, E]( - f: (Method, URL, Headers) => ZIO[R, Option[E], Middleware[R, E]], - ) extends Middleware[R, E] + private final case class AndThen[R, E, A0, B0, A1, B1, A2, B2]( + self: Middleware[R, E, A0, B0, A1, B1], + other: Middleware[R, E, A1, B1, A2, B2], + ) extends Middleware[R, E, A0, B0, A2, B2] - private final case class Race[R, E](self: Middleware[R, E], other: Middleware[R, E]) extends Middleware[R, E] + private final case class FlatMap[R, E, AIn, BIn, AOut, BOut, BOut0]( + self: Middleware[R, E, AIn, BIn, AOut, BOut0], + f: BOut0 => Middleware[R, E, AIn, BIn, AOut, BOut], + ) extends Middleware[R, E, AIn, BIn, AOut, BOut] - private final case class Constant[R, E](app: HttpApp[R, E]) extends Middleware[R, E] + private final case class ContraMapZIO[R, E, AIn, BIn, AOut, BOut, AOut0]( + self: Middleware[R, E, AIn, BIn, AOut, BOut], + f: AOut0 => ZIO[R, E, AOut], + ) extends Middleware[R, E, AIn, BIn, AOut0, BOut] - private final case class OrElse[R, E](self: Middleware[R, Any], other: Middleware[R, E]) extends Middleware[R, E] + private final case class Race[R, E, AIn, BIn, AOut, BOut]( + self: Middleware[R, E, AIn, BIn, AOut, BOut], + other: Middleware[R, E, AIn, BIn, AOut, BOut], + ) extends Middleware[R, E, AIn, BIn, AOut, BOut] - private case object Identity extends Middleware[Any, Nothing] + private case object Identity extends Middleware[Any, Nothing, Nothing, Any, Any, Nothing] } diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala new file mode 100644 index 0000000000..1cd9bc5551 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala @@ -0,0 +1,38 @@ +package zhttp.http.middleware + +import io.netty.handler.codec.http.HttpHeaderNames +import zhttp.http.Headers.BasicSchemeName +import zhttp.http._ + +private[zhttp] trait Auth { + + /** + * Creates a middleware for basic authentication + */ + final def basicAuth(f: Header => Boolean): HttpMiddleware[Any, Nothing] = + customAuth( + _.getBasicAuthorizationCredentials match { + case Some(header) => f(header) + case None => false + }, + Headers(HttpHeaderNames.WWW_AUTHENTICATE, BasicSchemeName), + ) + + /** + * Creates a middleware for basic authentication that checks if the credentials are same as the ones given + */ + final def basicAuth(u: String, p: String): HttpMiddleware[Any, Nothing] = + basicAuth { case (user, password) => (user == u) && (password == p) } + + /** + * Creates an authentication middleware that only allows authenticated requests to be passed on to the app. + */ + final def customAuth( + verify: Headers => Boolean, + responseHeaders: Headers = Headers.empty, + ): HttpMiddleware[Any, Nothing] = + Middleware.ifThenElse[Request](req => verify(req.getHeaders))( + _ => Middleware.identity, + _ => Middleware.fromHttp(Http.status(Status.FORBIDDEN).addHeaders(responseHeaders)), + ) +} diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala b/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala new file mode 100644 index 0000000000..22ced6ab15 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala @@ -0,0 +1,76 @@ +package zhttp.http.middleware + +import io.netty.handler.codec.http.HttpHeaderNames +import zhttp.http._ +import zhttp.http.middleware.Cors.CorsConfig + +private[zhttp] trait Cors { + + /** + * Creates a middleware for Cross-Origin Resource Sharing (CORS). + * @see + * https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS + */ + final def cors[R, E](config: CorsConfig = CorsConfig()): HttpMiddleware[R, E] = { + def allowCORS(origin: Header, acrm: Method): Boolean = + (config.anyOrigin, config.anyMethod, origin._2.toString, acrm) match { + case (true, true, _, _) => true + case (true, false, _, acrm) => + config.allowedMethods.exists(_.contains(acrm)) + case (false, true, origin, _) => config.allowedOrigins(origin) + case (false, false, origin, acrm) => + config.allowedMethods.exists(_.contains(acrm)) && + config.allowedOrigins(origin) + } + def corsHeaders(origin: Header, method: Method, isPreflight: Boolean): Headers = { + Headers.ifThenElse(isPreflight)( + onTrue = config.allowedHeaders.fold(Headers.empty) { h => + Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_HEADERS.toString(), h.mkString(",")) + }, + onFalse = config.exposedHeaders.fold(Headers.empty) { h => + Headers(HttpHeaderNames.ACCESS_CONTROL_EXPOSE_HEADERS.toString(), h.mkString(",")) + }, + ) ++ + Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN.toString(), origin._2) ++ + Headers( + HttpHeaderNames.ACCESS_CONTROL_ALLOW_METHODS.toString(), + config.allowedMethods.fold(method.toString())(m => m.map(m => m.toString()).mkString(",")), + ) ++ + Headers.when(config.allowCredentials) { + Headers(HttpHeaderNames.ACCESS_CONTROL_ALLOW_CREDENTIALS, config.allowCredentials.toString) + } + } + Middleware.collect[Request] { case req => + ( + req.method, + req.getHeaders.getHeader(HttpHeaderNames.ORIGIN), + req.getHeaders.getHeader(HttpHeaderNames.ACCESS_CONTROL_REQUEST_METHOD), + ) match { + case (Method.OPTIONS, Some(origin), Some(acrm)) if allowCORS(origin, Method.fromString(acrm._2.toString)) => + Middleware.succeed( + Response( + Status.NO_CONTENT, + headers = corsHeaders(origin, Method.fromString(acrm._2.toString), isPreflight = true), + ), + ) + case (_, Some(origin), _) if allowCORS(origin, req.method) => + Middleware.addHeaders(corsHeaders(origin, req.method, isPreflight = false)) + case _ => Middleware.identity + } + } + } +} + +object Cors { + final case class CorsConfig( + anyOrigin: Boolean = true, + anyMethod: Boolean = true, + allowCredentials: Boolean = true, + allowedOrigins: String => Boolean = _ => false, + allowedMethods: Option[Set[Method]] = None, + allowedHeaders: Option[Set[String]] = Some( + Set(HttpHeaderNames.CONTENT_TYPE.toString, HttpHeaderNames.AUTHORIZATION.toString, "*"), + ), + exposedHeaders: Option[Set[String]] = Some(Set("*")), + ) +} diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala new file mode 100644 index 0000000000..6935699780 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala @@ -0,0 +1,44 @@ +package zhttp.http.middleware + +import zhttp.http._ +import zio.{UIO, ZIO} + +import java.util.UUID + +private[zhttp] trait Csrf { + + /** + * Generates a new CSRF token that can be validated using the csrfValidate middleware. + * + * CSRF middlewares: To prevent Cross-site request forgery attacks. This middleware is modeled after the double submit + * cookie pattern. Used in conjunction with [[#csrfValidate]] middleware. + * + * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie + */ + final def csrfGenerate[R, E]( + tokenName: String = "x-csrf-token", + tokenGen: ZIO[R, Nothing, String] = UIO(UUID.randomUUID.toString), + ): HttpMiddleware[R, E] = + Middleware.addCookieZIO(tokenGen.map(Cookie(tokenName, _))) + + /** + * Validates the CSRF token appearing in the request headers. Typically the token should be set using the + * `csrfGenerate` middleware. + * + * CSRF middlewares : To prevent Cross-site request forgery attacks. This middleware is modeled after the double + * submit cookie pattern. Used in conjunction with [[#csrfGenerate]] middleware + * + * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie + */ + def csrfValidate(tokenName: String = "x-csrf-token"): HttpMiddleware[Any, Nothing] = { + Middleware.whenHeader( + headers => { + (headers.getHeaderValue(tokenName), headers.getCookieValue(tokenName)) match { + case (Some(headerValue), Some(cookieValue)) => headerValue != cookieValue + case _ => true + } + }, + Middleware.succeed(Response.status(Status.FORBIDDEN)), + ) + } +} diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala new file mode 100644 index 0000000000..9dee5307c7 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala @@ -0,0 +1,186 @@ +package zhttp.http.middleware + +import zhttp.http._ +import zhttp.http.headers.HeaderModifier +import zhttp.http.middleware.Web.{PartialInterceptPatch, PartialInterceptZIOPatch} +import zio.clock.Clock +import zio.console.Console +import zio.duration.Duration +import zio.{UIO, ZIO, clock, console} + +import java.io.IOException + +/** + * Middlewares on an HttpApp + */ +private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[HttpMiddleware[Any, Nothing]] { + self => + + /** + * Updates the provided list of headers to the response + */ + final override def updateHeaders(update: Headers => Headers): HttpMiddleware[Any, Nothing] = + Middleware.updateResponse(_.updateHeaders(update)) + + /** + * Sets cookie in response headers + */ + final def addCookie(cookie: Cookie): HttpMiddleware[Any, Nothing] = + self.withSetCookie(cookie) + + final def addCookieZIO[R, E](cookie: ZIO[R, E, Cookie]): HttpMiddleware[R, E] = + patchZIO(_ => cookie.mapBoth(Option(_), c => Patch.addHeader(Headers.setCookie(c)))) + + /** + * Add log status, method, url and time taken from req to res + */ + final def debug: HttpMiddleware[Console with Clock, IOException] = + interceptZIOPatch(req => zio.clock.nanoTime.map(start => (req.method, req.url, start))) { + case (response, (method, url, start)) => + for { + end <- clock.nanoTime + _ <- console + .putStrLn(s"${response.status.asJava.code()} ${method} ${url.asString} ${(end - start) / 1000000}ms") + .mapError(Option(_)) + } yield Patch.empty + } + + /** + * Logical operator to decide which middleware to select based on the header + */ + final def ifHeaderThenElse[R, E]( + cond: Headers => Boolean, + )(left: HttpMiddleware[R, E], right: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + Middleware.ifThenElse[Request](req => cond(req.getHeaders))(_ => left, _ => right) + + /** + * Logical operator to decide which middleware to select based on the method. + */ + final def ifMethodThenElse[R, E]( + cond: Method => Boolean, + )(left: HttpMiddleware[R, E], right: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + Middleware.ifThenElse[Request](req => cond(req.method))(_ => left, _ => right) + + /** + * Logical operator to decide which middleware to select based on the predicate. + */ + final def ifRequestThenElse[R, E]( + cond: Request => Boolean, + )(left: HttpMiddleware[R, E], right: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + Middleware.ifThenElse[Request](cond)(_ => left, _ => right) + + /** + * Logical operator to decide which middleware to select based on the predicate. + */ + final def ifRequestThenElseZIO[R, E]( + cond: Request => ZIO[R, E, Boolean], + )(left: HttpMiddleware[R, E], right: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + Middleware.ifThenElseZIO[Request](cond)(_ => left, _ => right) + + /** + * Creates a new middleware using transformation functions + */ + final def interceptPatch[S](req: Request => S): PartialInterceptPatch[S] = PartialInterceptPatch(req) + + /** + * Creates a new middleware using effectful transformation functions + */ + final def interceptZIOPatch[R, E, S](req: Request => ZIO[R, Option[E], S]): PartialInterceptZIOPatch[R, E, S] = + PartialInterceptZIOPatch(req) + + /** + * Creates a middleware that produces a Patch for the Response + */ + final def patch[R, E](f: Response => Patch): HttpMiddleware[R, E] = + Middleware.interceptPatch(_ => ())((res, _) => f(res)) + + /** + * Creates a middleware that produces a Patch for the Response effectfully. + */ + final def patchZIO[R, E](f: Response => ZIO[R, Option[E], Patch]): HttpMiddleware[R, E] = + Middleware.interceptZIOPatch(_ => ZIO.unit)((res, _) => f(res)) + + /** + * Runs the effect after the middleware is applied + */ + final def runAfter[R, E](effect: ZIO[R, E, Any]): HttpMiddleware[R, E] = + Middleware.interceptZIO[Request, Response](_ => ZIO.unit)((res, _) => effect.mapBoth(Option(_), _ => res)) + + /** + * Runs the effect before the request is passed on to the HttpApp on which the middleware is applied. + */ + final def runBefore[R, E](effect: ZIO[R, E, Any]): HttpMiddleware[R, E] = + Middleware.interceptZIOPatch(_ => effect.mapError(Option(_)).unit)((_, _) => UIO(Patch.empty)) + + /** + * Creates a new middleware that always sets the response status to the provided value + */ + final def setStatus(status: Status): HttpMiddleware[Any, Nothing] = patch(_ => Patch.setStatus(status)) + + /** + * Creates a middleware for signing cookies + */ + final def signCookies(secret: String): HttpMiddleware[Any, Nothing] = + updateHeaders { + case h if h.getHeader(HeaderNames.setCookie).isDefined => + Headers( + HeaderNames.setCookie, + Cookie.decodeResponseCookie(h.getHeader(HeaderNames.setCookie).get._2.toString).get.sign(secret).encode, + ) + case h => h + } + + /** + * Times out the application with a 408 status code. + */ + final def timeout(duration: Duration): HttpMiddleware[Clock, Nothing] = + Middleware.identity.race(Middleware.fromHttp(Http.status(Status.REQUEST_TIMEOUT).delayAfter(duration))) + + /** + * Creates a middleware that updates the response produced + */ + final def updateResponse[R, E](f: Response => Response): HttpMiddleware[R, E] = + Middleware.intercept[Request, Response](_ => ())((res, _) => f(res)) + + /** + * Applies the middleware only when the condition for the headers are true + */ + final def whenHeader[R, E](cond: Headers => Boolean, middleware: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + middleware.when[Request](req => cond(req.getHeaders)) + + /** + * Applies the middleware only if the condition function evaluates to true + */ + final def whenRequest[R, E](cond: Request => Boolean)( + middleware: HttpMiddleware[R, E], + ): HttpMiddleware[R, E] = + middleware.when[Request](cond) + + /** + * Applies the middleware only if the condition function effectfully evaluates to true + */ + final def whenRequestZIO[R, E]( + cond: Request => ZIO[R, E, Boolean], + )(middleware: HttpMiddleware[R, E]): HttpMiddleware[R, E] = + Middleware.ifThenElseZIO[Request](cond)( + _ => middleware, + _ => Middleware.identity, + ) +} + +object Web { + + final case class PartialInterceptPatch[S](req: Request => S) extends AnyVal { + def apply(res: (Response, S) => Patch): HttpMiddleware[Any, Nothing] = { + Middleware.intercept[Request, Response](req(_))((response, state) => res(response, state)(response)) + } + } + + final case class PartialInterceptZIOPatch[R, E, S](req: Request => ZIO[R, Option[E], S]) extends AnyVal { + def apply[R1 <: R, E1 >: E](res: (Response, S) => ZIO[R1, Option[E1], Patch]): HttpMiddleware[R1, E1] = + Middleware + .interceptZIO[Request, Response](req(_))((response, state) => + res(response, state).map(patch => patch(response)), + ) + } +} diff --git a/zio-http/src/main/scala/zhttp/http/middleware/package.scala b/zio-http/src/main/scala/zhttp/http/middleware/package.scala new file mode 100644 index 0000000000..3baa3d9fc4 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/middleware/package.scala @@ -0,0 +1,5 @@ +package zhttp.http + +package object middleware { + type HttpMiddleware[-R, +E] = Middleware[R, E, Request, Response, Request, Response] +} diff --git a/zio-http/src/main/scala/zhttp/http/package.scala b/zio-http/src/main/scala/zhttp/http/package.scala index 7c6adc1c2d..a3673941c6 100644 --- a/zio-http/src/main/scala/zhttp/http/package.scala +++ b/zio-http/src/main/scala/zhttp/http/package.scala @@ -6,13 +6,14 @@ import zio.ZIO import java.nio.charset.Charset package object http extends PathModule with RequestSyntax with RouteDecoderModule { - type HttpApp[-R, +E] = Http[R, E, Request, Response] - type UHttpApp = HttpApp[Any, Nothing] - type RHttpApp[-R] = HttpApp[R, Throwable] - type UHttp[-A, +B] = Http[Any, Nothing, A, B] - type SilentResponse[-E] = CanBeSilenced[E, Response] - type ResponseZIO[-R, +E] = ZIO[R, E, Response] - type Header = (CharSequence, CharSequence) + type HttpApp[-R, +E] = Http[R, E, Request, Response] + type UHttpApp = HttpApp[Any, Nothing] + type RHttpApp[-R] = HttpApp[R, Throwable] + type UHttp[-A, +B] = Http[Any, Nothing, A, B] + type SilentResponse[-E] = CanBeSilenced[E, Response] + type ResponseZIO[-R, +E] = ZIO[R, E, Response] + type Header = (CharSequence, CharSequence) + type UMiddleware[+AIn, -BIn, -AOut, +BOut] = Middleware[Any, Nothing, AIn, BIn, AOut, BOut] /** * Default HTTP Charset diff --git a/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala new file mode 100644 index 0000000000..fb6a500bd0 --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala @@ -0,0 +1,157 @@ +package zhttp.http + +import zio.duration._ +import zio.test.Assertion._ +import zio.test.environment.{TestClock, TestConsole} +import zio.test.{DefaultRunnableSpec, assert, assertM} +import zio.{Ref, UIO, console} + +object MiddlewareSpec extends DefaultRunnableSpec with HExitAssertion { + def spec = suite("Middleware") { + val increment = Middleware.codec[Int, Int](decoder = a => Right(a + 1), encoder = b => Right(b + 1)) + testM("empty") { + val http = Http.empty + val app = Middleware.identity(http) + assertM(app(()).either)(isLeft(isNone)) + } + + testM("constant") { + val mid = Middleware.fromHttp(Http.succeed("OK")) + val app = Http.succeed(1) @@ mid + assertM(app(()))(equalTo("OK")) + } + + testM("as") { + val mid = Middleware.fromHttp(Http.succeed("Not OK")).as("OK") + val app = Http.succeed(1) @@ mid + assertM(app(()))(equalTo("OK")) + } + + testM("interceptZIO") { + for { + ref <- Ref.make(0) + mid = Middleware.interceptZIO[Int, Int](i => UIO(i * 10))((i, j) => ref.set(i + j)) + app = Http.identity[Int] @@ mid + _ <- app(1) + i <- ref.get + } yield assert(i)(equalTo(11)) + } + + testM("orElse") { + val mid = Middleware.fail("left") <> Middleware.fail("right") + val app = Http.empty @@ mid + assertM(app(()).flip)(isSome(equalTo("right"))) + } + + testM("combine") { + val mid1 = increment + val mid2 = increment + val mid = mid1 andThen mid2 + val app = Http.identity[Int] @@ mid + assertM(app(0))(equalTo(4)) + } + + testM("flatMap") { + val mid = increment.flatMap(i => Middleware.succeed(i + 1)) + val app = Http.identity[Int] @@ mid + assertM(app(0))(equalTo(3)) + } + + testM("mapZIO") { + val mid = increment.mapZIO(i => UIO(i + 1)) + val app = Http.identity[Int] @@ mid + assertM(app(0))(equalTo(3)) + } + + testM("runBefore") { + val mid = Middleware.identity.runBefore(console.putStrLn("A")) + val app = Http.fromZIO(console.putStrLn("B")) @@ mid + assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n"))) + } + + testM("runAfter") { + val mid = Middleware.identity.runAfter(console.putStrLn("B")) + val app = Http.fromZIO(console.putStrLn("A")) @@ mid + assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n"))) + } + + testM("runBefore and runAfter") { + val mid = Middleware.identity.runBefore(console.putStrLn("A")).runAfter(console.putStrLn("C")) + val app = Http.fromZIO(console.putStrLn("B")) @@ mid + assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n", "C\n"))) + } + + testM("race") { + val mid = Middleware.succeed('A').delay(2 second) race Middleware.succeed("B").delay(1 second) + val app = Http.succeed(1) @@ mid + assertM(app(()) <& TestClock.adjust(3 second))(equalTo("B")) + } + + suite("ifThenElse") { + val mid = Middleware.ifThenElse[Int](_ > 5)( + isTrue = i => Middleware.succeed(i + 1), + isFalse = i => Middleware.succeed(i - 1), + ) + testM("isTrue") { + val app = Http.identity[Int] @@ mid + assertM(app(10))(equalTo(11)) + } + + testM("isFalse") { + val app = Http.identity[Int] @@ mid + assertM(app(1))(equalTo(0)) + } + } + + suite("ifThenElseZIO") { + val mid = Middleware.ifThenElseZIO[Int](i => UIO(i > 5))( + isTrue = i => Middleware.succeed(i + 1), + isFalse = i => Middleware.succeed(i - 1), + ) + testM("isTrue") { + val app = Http.identity[Int] @@ mid + assertM(app(10))(equalTo(11)) + } + + testM("isFalse") { + val app = Http.identity[Int] @@ mid + assertM(app(1))(equalTo(0)) + } + } + + suite("contramap") { + val mid = Middleware.intercept[String, String](a => a + "Bar")((b, s) => b + s) + testM("contramap") { + val app = Http.identity[String] @@ mid.contramap[Int] { i => s"${i}Foo" } + assertM(app(0))(equalTo("0Foo0FooBar")) + } + + testM("contramapZIO") { + val app = Http.identity[String] @@ mid.contramapZIO[Int] { i => UIO(s"${i}Foo") } + assertM(app(0))(equalTo("0Foo0FooBar")) + } + } + + suite("when") { + val mid = Middleware.succeed(0) + testM("condition is true") { + val app = Http.identity[Int] @@ mid.when[Int](_ => true) + assertM(app(10))(equalTo(0)) + } + + testM("condition is false") { + val app = Http.identity[Int] @@ mid.when[Int](_ => false) + assertM(app(1))(equalTo(1)) + } + } + + suite("whenZIO") { + val mid = Middleware.succeed(0) + testM("condition is true") { + val app = Http.identity[Int] @@ mid.whenZIO[Any, Nothing, Int](_ => UIO(true)) + assertM(app(10))(equalTo(0)) + } + + testM("condition is false") { + val app = Http.identity[Int] @@ mid.whenZIO[Any, Nothing, Int](_ => UIO(false)) + assertM(app(1))(equalTo(1)) + } + } + + suite("codec") { + testM("codec success") { + val mid = Middleware.codec[String, Int](a => Right(a.toInt), b => Right(b.toString)) + val app = Http.identity[Int] @@ mid + assertM(app("1"))(equalTo("1")) + } + + testM("decoder failure") { + val mid = Middleware.codec[String, Int](a => Left(a), b => Right(b.toString)) + val app = Http.identity[Int] @@ mid + assertM(app("a").run)(fails(anything)) + } + + testM("encoder failure") { + val mid = Middleware.codec[String, Int](a => Right(a.toInt), b => Left(b.toString)) + val app = Http.identity[Int] @@ mid + assertM(app("1").run)(fails(anything)) + } + } + } +} diff --git a/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala new file mode 100644 index 0000000000..eb61885a9e --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala @@ -0,0 +1,29 @@ +package zhttp.http.middleware + +import zhttp.http._ +import zhttp.internal.HttpAppTestExtensions +import zio.test.Assertion._ +import zio.test._ + +object AuthSpec extends DefaultRunnableSpec with HttpAppTestExtensions { + private val basicHS = Headers.basicAuthorizationHeader("user", "resu") + private val basicHF = Headers.basicAuthorizationHeader("user", "user") + private val basicAuthM = Middleware.basicAuth { case (u, p) => p.toString.reverse == u } + + def spec = suite("AuthSpec") { + suite("basicAuth") { + testM("HttpApp is accepted if the basic authentication succeeds") { + val app = (Http.ok @@ basicAuthM).getStatus + assertM(app(Request().addHeaders(basicHS)))(equalTo(Status.OK)) + } + + testM("Uses forbidden app if the basic authentication fails") { + val app = (Http.ok @@ basicAuthM).getStatus + assertM(app(Request().addHeaders(basicHF)))(equalTo(Status.FORBIDDEN)) + } + + testM("Responses should have WWW-Authentication header if Basic Auth failed") { + val app = Http.ok @@ basicAuthM getHeader "WWW-AUTHENTICATE" + assertM(app(Request().addHeaders(basicHF)))(isSome) + } + } + } +} diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala new file mode 100644 index 0000000000..b15d2ea34e --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala @@ -0,0 +1,54 @@ +package zhttp.http.middleware + +import zhttp.http.Middleware.cors +import zhttp.http._ +import zhttp.http.middleware.Cors.CorsConfig +import zhttp.internal.HttpAppTestExtensions +import zio.test.Assertion.hasSubset +import zio.test._ + +object CorsSpec extends DefaultRunnableSpec with HttpAppTestExtensions { + override def spec = suite("CorsMiddlewares") { + val app = Http.ok @@ cors() + testM("OPTIONS request") { + val request = Request( + method = Method.OPTIONS, + url = URL(!! / "success"), + headers = Headers.accessControlRequestMethod(Method.GET) ++ Headers.origin("test-env"), + ) + + val expected = Headers + .accessControlAllowCredentials(true) + .withAccessControlAllowMethods(Method.GET) + .withAccessControlAllowOrigin("test-env") + .withAccessControlAllowHeaders( + CorsConfig().allowedHeaders.getOrElse(Set.empty).mkString(","), + ) + .toList + + for { + res <- app(request) + } yield assert(res.getHeadersAsList)(hasSubset(expected)) && + assertTrue(res.status == Status.NO_CONTENT) + } + + testM("GET request") { + val request = + Request( + method = Method.GET, + url = URL(!! / "success"), + headers = Headers.accessControlRequestMethod(Method.GET) ++ Headers.origin("test-env"), + ) + + val expected = Headers + .accessControlExposeHeaders("*") + .withAccessControlAllowOrigin("test-env") + .withAccessControlAllowMethods(Method.GET) + .withAccessControlAllowCredentials(true) + .toList + + for { + res <- app(request) + } yield assert(res.getHeadersAsList)(hasSubset(expected)) + } + } +} diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala new file mode 100644 index 0000000000..dbdb078e37 --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala @@ -0,0 +1,39 @@ +package zhttp.http.middleware + +import zhttp.http.Middleware.csrfValidate +import zhttp.http._ +import zhttp.internal.HttpAppTestExtensions +import zio.Ref +import zio.test.Assertion.equalTo +import zio.test._ + +object CsrfSpec extends DefaultRunnableSpec with HttpAppTestExtensions { + override def spec = suite("CSRF Middlewares") { + val app = (Http.ok @@ csrfValidate("x-token")).getStatus + val setCookie = Headers.cookie(Cookie("x-token", "secret")) + val invalidXToken = Headers("x-token", "secret1") + val validXToken = Headers("x-token", "secret") + testM("x-token not present") { + assertM(app(Request(headers = setCookie)))(equalTo(Status.FORBIDDEN)) + } + + testM("x-token mismatch") { + assertM(app(Request(headers = setCookie ++ invalidXToken)))( + equalTo(Status.FORBIDDEN), + ) + } + + testM("x-token match") { + assertM(app(Request(headers = setCookie ++ validXToken)))( + equalTo(Status.OK), + ) + } + + testM("app execution skipped") { + for { + r <- Ref.make(false) + app = Http.ok.tapZIO(_ => r.set(true)) @@ csrfValidate("x-token") + _ <- app(Request(headers = setCookie ++ invalidXToken)) + res <- r.get + } yield assert(res)(equalTo(false)) + } + } + +} diff --git a/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala new file mode 100644 index 0000000000..02c995bc59 --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala @@ -0,0 +1,181 @@ +package zhttp.http.middleware + +import zhttp.http.Middleware._ +import zhttp.http._ +import zhttp.internal.HttpAppTestExtensions +import zio._ +import zio.duration._ +import zio.test.Assertion._ +import zio.test._ +import zio.test.environment.{TestClock, TestConsole} + +object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { + private val app = Http.collectZIO[Request] { case Method.GET -> !! / "health" => + UIO(Response.ok).delay(1 second) + } + private val midA = Middleware.addHeader("X-Custom", "A") + private val midB = Middleware.addHeader("X-Custom", "B") + + def spec = suite("HttpMiddleware") { + suite("headers suite") { + testM("addHeaders") { + val middleware = addHeaders(Headers("KeyA", "ValueA") ++ Headers("KeyB", "ValueB")) + val headers = (Http.ok @@ middleware).getHeaderValues + assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) + } + + testM("addHeader") { + val middleware = addHeader("KeyA", "ValueA") + val headers = (Http.ok @@ middleware).getHeaderValues + assertM(headers(Request()))(contains("ValueA")) + } + + testM("updateHeaders") { + val middleware = updateHeaders(_ => Headers("KeyA", "ValueA")) + val headers = (Http.ok @@ middleware).getHeaderValues + assertM(headers(Request()))(contains("ValueA")) + } + + testM("removeHeader") { + val middleware = removeHeader("KeyA") + val headers = (Http.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware) getHeader "KeyA" + assertM(headers(Request()))(isNone) + } + } + + suite("debug") { + testM("log status method url and time") { + val program = run(app @@ debug) *> TestConsole.output + assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) + } + + testM("log 404 status method url and time") { + val program = run(Http.empty ++ Http.notFound @@ debug) *> TestConsole.output + assertM(program)(equalTo(Vector("404 GET /health 0ms\n"))) + } + } + + suite("when") { + testM("condition is true") { + val program = run(app @@ debug.when(_ => true)) *> TestConsole.output + assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) + } + + testM("condition is false") { + val log = run(app @@ debug.when(_ => false)) *> TestConsole.output + assertM(log)(equalTo(Vector())) + } + } + + suite("whenZIO") { + testM("condition is true") { + val program = run(app @@ debug.whenZIO(_ => UIO(true))) *> TestConsole.output + assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) + } + + testM("condition is false") { + val log = run(app @@ debug.whenZIO(_ => UIO(false))) *> TestConsole.output + assertM(log)(equalTo(Vector())) + } + } + + suite("race") { + testM("achieved") { + val program = run(app @@ timeout(5 seconds)).map(_.status) + assertM(program)(equalTo(Status.OK)) + } + + testM("un-achieved") { + val program = run(app @@ timeout(500 millis)).map(_.status) + assertM(program)(equalTo(Status.REQUEST_TIMEOUT)) + } + } + + suite("combine") { + testM("before and after") { + val middleware = runBefore(console.putStrLn("A")) + val program = run(app @@ middleware) *> TestConsole.output + assertM(program)(equalTo(Vector("A\n"))) + } + + testM("add headers twice") { + val middleware = addHeader("KeyA", "ValueA") ++ addHeader("KeyB", "ValueB") + val headers = (Http.ok @@ middleware).getHeaderValues + assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) + } + + testM("add and remove header") { + val middleware = addHeader("KeyA", "ValueA") ++ removeHeader("KeyA") + val program = (Http.ok @@ middleware) getHeader "KeyA" + assertM(program(Request()))(isNone) + } + } + + suite("ifRequestThenElseZIO") { + testM("if the condition is true take first") { + val app = (Http.ok @@ ifRequestThenElseZIO(condM(true))(midA, midB)) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("A"))) + } + + testM("if the condition is false take 2nd") { + val app = + (Http.ok @@ ifRequestThenElseZIO(condM(false))(midA, midB)) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("B"))) + } + } + + suite("ifRequestThenElse") { + testM("if the condition is true take first") { + val app = Http.ok @@ ifRequestThenElse(cond(true))(midA, midB) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("A"))) + } + + testM("if the condition is false take 2nd") { + val app = Http.ok @@ ifRequestThenElse(cond(false))(midA, midB) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("B"))) + } + } + + suite("whenRequestZIO") { + testM("if the condition is true apply middleware") { + val app = (Http.ok @@ whenRequestZIO(condM(true))(midA)) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("A"))) + } + + testM("if the condition is false don't apply any middleware") { + val app = (Http.ok @@ whenRequestZIO(condM(false))(midA)) getHeader "X-Custom" + assertM(app(Request()))(isNone) + } + } + + suite("whenRequest") { + testM("if the condition is true apple middleware") { + val app = Http.ok @@ Middleware.whenRequest(cond(true))(midA) getHeader "X-Custom" + assertM(app(Request()))(isSome(equalTo("A"))) + } + + testM("if the condition is false don't apply the middleware") { + val app = Http.ok @@ Middleware.whenRequest(cond(false))(midA) getHeader "X-Custom" + assertM(app(Request()))(isNone) + } + } + + suite("cookie") { + testM("addCookie") { + val cookie = Cookie("test", "testValue") + val app = (Http.ok @@ addCookie(cookie)).getHeader("set-cookie") + assertM(app(Request()))( + equalTo(Some(cookie.encode)), + ) + } + + testM("addCookieM") { + val cookie = Cookie("test", "testValue") + val app = + (Http.ok @@ addCookieZIO(UIO(cookie))).getHeader("set-cookie") + assertM(app(Request()))( + equalTo(Some(cookie.encode)), + ) + } + } + + suite("signCookies") { + testM("should sign cookies") { + val cookie = Cookie("key", "value").withHttpOnly + val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") getHeader "set-cookie" + assertM(app(Request()))(isSome(equalTo(cookie.sign("secret").encode))) + } + + testM("sign cookies no cookie header") { + val app = (Http.ok.addHeader("keyA", "ValueA") @@ signCookies("secret")).getHeaderValues + assertM(app(Request()))(contains("ValueA")) + } + } + } + + private def cond(flg: Boolean) = (_: Any) => flg + + private def condM(flg: Boolean) = (_: Any) => UIO(flg) + + private def run[R, E](app: HttpApp[R, E]): ZIO[TestClock with R, Option[E], Response] = { + for { + fib <- app { Request(url = URL(!! / "health")) }.fork + _ <- TestClock.adjust(10 seconds) + res <- fib.join + } yield res + } +} diff --git a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala deleted file mode 100644 index cfd82efdf3..0000000000 --- a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala +++ /dev/null @@ -1,243 +0,0 @@ -package zhttp.middleware - -import zhttp.http._ -import zhttp.internal.HttpAppTestExtensions -import zio._ -import zio.clock.Clock -import zio.duration._ -import zio.test.Assertion._ -import zio.test.environment.{TestClock, TestConsole} -import zio.test.{DefaultRunnableSpec, assert, assertM} - -object MiddlewareSpec extends DefaultRunnableSpec with HttpAppTestExtensions { - def spec = suite("HttpMiddleware") { - import Middleware._ - - suite("debug") { - testM("log status method url and time") { - val program = run(app @@ debug) *> TestConsole.output - assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) - } + - testM("log 404 status method url and time") { - val program = run(Http.empty @@ debug.withEmpty) *> TestConsole.output - assertM(program)(equalTo(Vector("404 GET /health 0ms\n"))) - } - } + - suite("withEmpty") { - testM("log 404 status method url and time") { - val program = run(Http.empty @@ debug.withEmpty) *> TestConsole.output - assertM(program)(equalTo(Vector("404 GET /health 0ms\n"))) - } - } + - suite("when") { - testM("condition is true") { - val program = run(app @@ debug.when((_, _, _) => true)) *> TestConsole.output - assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) - } + - testM("condition is false") { - val log = run(app @@ debug.when((_, _, _) => false)) *> TestConsole.output - assertM(log)(equalTo(Vector())) - } - } + - suite("race") { - testM("achieved") { - val program = run(app @@ timeout(5 seconds)).map(_.status) - assertM(program)(equalTo(Status.OK)) - } + - testM("un-achieved") { - val program = run(app @@ timeout(500 millis)).map(_.status) - assertM(program)(equalTo(Status.REQUEST_TIMEOUT)) - } - } + - suite("combine") { - testM("before and after") { - val middleware = runBefore(console.putStrLn("A")) ++ runAfter(console.putStrLn("B")) - val program = run(app @@ middleware) *> TestConsole.output - assertM(program)(equalTo(Vector("A\n", "B\n"))) - } + - testM("add headers twice") { - val middleware = addHeader("KeyA", "ValueA") ++ addHeader("KeyB", "ValueB") - val headers = (Http.ok @@ middleware).getHeaderValues - assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) - } + - testM("add and remove header") { - val middleware = addHeader("KeyA", "ValueA") ++ removeHeader("KeyA") - val program = (Http.ok @@ middleware) getHeader "KeyA" - assertM(program(Request()))(isNone) - } - } + - suite("ifThenElseM") { - testM("if the condition is true take first") { - val app = (Http.ok @@ ifThenElseZIO(condM(true))(midA, midB)) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("A"))) - } + - testM("if the condition is false take 2nd") { - val app = - (Http.ok @@ ifThenElseZIO(condM(false))(midA, midB)) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("B"))) - } - } + - suite("ifThenElse") { - testM("if the condition is true take first") { - val app = Http.ok @@ ifThenElse(cond(true))(midA, midB) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("A"))) - } + - testM("if the condition is false take 2nd") { - val app = Http.ok @@ ifThenElse(cond(false))(midA, midB) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("B"))) - } - } + - suite("whenM") { - testM("if the condition is true apply middleware") { - val app = (Http.ok @@ whenZIO(condM(true))(midA)) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("A"))) - } + - testM("if the condition is false don't apply any middleware") { - val app = (Http.ok @@ whenZIO(condM(false))(midA)) getHeader "X-Custom" - assertM(app(Request()))(isNone) - } - } + - suite("when") { - testM("if the condition is true apple middleware") { - val app = Http.ok @@ when(cond(true))(midA) getHeader "X-Custom" - assertM(app(Request()))(isSome(equalTo("A"))) - } + - testM("if the condition is false don't apply the middleware") { - val app = Http.ok @@ when(cond(false))(midA) getHeader "X-Custom" - assertM(app(Request()))(isNone) - } - } + - suite("Authentication middleware") { - suite("basicAuth") { - testM("HttpApp is accepted if the basic authentication succeeds") { - val app = (Http.ok @@ basicAuthM).getStatus - assertM(app(Request().addHeaders(basicHS)))(equalTo(Status.OK)) - } + - testM("Uses forbidden app if the basic authentication fails") { - val app = (Http.ok @@ basicAuthM).getStatus - assertM(app(Request().addHeaders(basicHF)))(equalTo(Status.FORBIDDEN)) - } + - testM("Responses should have WWW-Authentication header if Basic Auth failed") { - val app = Http.ok @@ basicAuthM getHeader "WWW-AUTHENTICATE" - assertM(app(Request().addHeaders(basicHF)))(isSome) - } - } - } + - suite("cors") { - // FIXME:The test should ideally pass with `Http.ok` also - val app = Http.collect[Request] { case Method.GET -> !! / "success" => Response.ok } @@ cors() - testM("OPTIONS request") { - val request = Request( - method = Method.OPTIONS, - url = URL(!! / "success"), - headers = Headers.accessControlRequestMethod(Method.GET) ++ Headers.origin("test-env"), - ) - - val expected = Headers - .accessControlAllowCredentials(true) - .withAccessControlAllowMethods(Method.GET) - .withAccessControlAllowOrigin("test-env") - .withAccessControlAllowHeaders( - CORS.DefaultCORSConfig.allowedHeaders.getOrElse(Set.empty).mkString(","), - ) - .toList - - for { - res <- app(request) - } yield assert(res.getHeadersAsList)(hasSubset(expected)) && - assert(res.status)(equalTo(Status.NO_CONTENT)) - } + - testM("GET request") { - val request = - Request( - method = Method.GET, - url = URL(!! / "success"), - headers = Headers.accessControlRequestMethod(Method.GET) ++ Headers.origin("test-env"), - ) - - val expected = Headers - .accessControlExposeHeaders("*") - .withAccessControlAllowOrigin("test-env") - .withAccessControlAllowMethods(Method.GET) - .withAccessControlAllowCredentials(true) - .toList - - for { - res <- app(request) - } yield assert(res.getHeadersAsList)(hasSubset(expected)) - } - } + - suite("cookie") { - testM("addCookie") { - val cookie = Cookie("test", "testValue") - val app = (Http.ok @@ addCookie(cookie)).getHeader("set-cookie") - assertM(app(Request()))( - equalTo(Some(cookie.encode)), - ) - } + - testM("addCookieM") { - val cookie = Cookie("test", "testValue") - val app = - (Http.ok @@ addCookieM(UIO(cookie))).getHeader("set-cookie") - assertM(app(Request()))( - equalTo(Some(cookie.encode)), - ) - } - } + - suite("csrf") { - val app = (Http.ok @@ csrfValidate("x-token")).getStatus - val setCookie = Headers.cookie(Cookie("x-token", "secret")) - val invalidXToken = Headers("x-token", "secret1") - val validXToken = Headers("x-token", "secret") - testM("x-token not present") { - assertM(app(Request(headers = setCookie)))(equalTo(Status.FORBIDDEN)) - } + - testM("x-token mismatch") { - assertM(app(Request(headers = setCookie ++ invalidXToken)))( - equalTo(Status.FORBIDDEN), - ) - } + - testM("x-token match") { - assertM(app(Request(headers = setCookie ++ validXToken)))( - equalTo(Status.OK), - ) - } + - testM("app execution skipped") { - for { - r <- Ref.make(false) - app = Http.ok.tapZIO(_ => r.set(true)) @@ csrfValidate("x-token") - _ <- app(Request(headers = setCookie ++ invalidXToken)) - res <- r.get - } yield assert(res)(equalTo(false)) - } - } + - suite("signCookies") { - testM("should sign cookies") { - val cookie = Cookie("key", "value").withHttpOnly - val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") getHeader "set-cookie" - assertM(app(Request()))(isSome(equalTo(cookie.sign("secret").encode))) - } - } - } - - private val app: HttpApp[Any with Clock, Nothing] = Http.collectZIO[Request] { case Method.GET -> !! / "health" => - UIO(Response.ok).delay(1 second) - } - private val midA = Middleware.addHeader("X-Custom", "A") - private val midB = Middleware.addHeader("X-Custom", "B") - private val basicHS = Headers.basicAuthorizationHeader("user", "resu") - private val basicHF = Headers.basicAuthorizationHeader("user", "user") - private val basicAuthM = Middleware.basicAuth { case (u, p) => p.toString.reverse == u } - - private def cond(flg: Boolean) = (_: Any, _: Any, _: Any) => flg - - private def condM(flg: Boolean) = (_: Any, _: Any, _: Any) => UIO(flg) - - private def run[R, E](app: HttpApp[R, E]): ZIO[TestClock with R, Option[E], Response] = { - for { - fib <- app { Request(url = URL(!! / "health")) }.fork - _ <- TestClock.adjust(10 seconds) - res <- fib.join - } yield res - } -} From 9fc4f401ea12b1dc6c4bdddcb7cc360db1ca1f0d Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 20 Jan 2022 13:05:29 +0530 Subject: [PATCH 20/95] refactor: rename ClientParams to ClientRequest (#856) --- .../src/main/scala/zhttp/service/Client.scala | 24 +++++++++---------- .../zhttp/service/EncodeClientParams.scala | 2 +- ...ec.scala => EncodeClientRequestSpec.scala} | 6 ++--- .../zhttp/http/GetBodyAsStringSpec.scala | 4 ++-- .../test/scala/zhttp/internal/HttpGen.scala | 6 ++--- .../zhttp/internal/HttpRunnableSpec.scala | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) rename zio-http/src/test/scala/zhttp/http/{EncodeClientParamsSpec.scala => EncodeClientRequestSpec.scala} (88%) diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 7a3b3e0bac..74d074172e 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -13,7 +13,7 @@ import zhttp.http.URL.Location import zhttp.http._ import zhttp.http.headers.HeaderExtension import zhttp.service -import zhttp.service.Client.{ClientParams, ClientResponse} +import zhttp.service.Client.{ClientRequest, ClientResponse} import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.client.{ClientChannelInitializer, ClientInboundHandler} import zio.{Chunk, Promise, Task, ZIO} @@ -23,7 +23,7 @@ import java.net.{InetAddress, InetSocketAddress} final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: JEventLoopGroup) extends HttpMessageCodec { def request( - request: Client.ClientParams, + request: Client.ClientRequest, sslOption: ClientSSLOptions = ClientSSLOptions.DefaultSSL, ): Task[Client.ClientResponse] = for { @@ -33,7 +33,7 @@ final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: } yield res private def asyncRequest( - req: ClientParams, + req: ClientRequest, promise: Promise[Throwable, ClientResponse], sslOption: ClientSSLOptions, ): Unit = { @@ -111,14 +111,14 @@ object Client { method: Method, url: URL, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientParams(method, url)) + request(ClientRequest(method, url)) def request( method: Method, url: URL, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientParams(method, url), sslOptions) + request(ClientRequest(method, url), sslOptions) def request( method: Method, @@ -126,7 +126,7 @@ object Client { headers: Headers, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientParams(method, url, headers), sslOptions) + request(ClientRequest(method, url, headers), sslOptions) def request( method: Method, @@ -134,26 +134,26 @@ object Client { headers: Headers, content: HttpData, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientParams(method, url, headers, content)) + request(ClientRequest(method, url, headers, content)) def request( - req: ClientParams, + req: ClientRequest, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req)) def request( - req: ClientParams, + req: ClientRequest, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req, sslOptions)) - final case class ClientParams( + final case class ClientRequest( method: Method, url: URL, getHeaders: Headers = Headers.empty, data: HttpData = HttpData.empty, private val channelContext: ChannelHandlerContext = null, - ) extends HeaderExtension[ClientParams] { self => + ) extends HeaderExtension[ClientRequest] { self => def getBodyAsString: Option[String] = data match { case HttpData.Text(text, _) => Some(text) @@ -172,7 +172,7 @@ object Client { /** * Updates the headers using the provided function */ - override def updateHeaders(update: Headers => Headers): ClientParams = + override def updateHeaders(update: Headers => Headers): ClientRequest = self.copy(getHeaders = update(self.getHeaders)) } diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index bf6955cdbd..efa935bbce 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -8,7 +8,7 @@ trait EncodeClientParams { /** * Converts client params to JFullHttpRequest */ - def encodeClientParams(jVersion: HttpVersion, req: Client.ClientParams): FullHttpRequest = { + def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { val method = req.method.asHttpMethod val uri = req.url.asString val content = req.getBodyAsString match { diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala similarity index 88% rename from zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala rename to zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index d97b87d458..47e007098c 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -7,15 +7,15 @@ import zio.random.Random import zio.test.Assertion._ import zio.test._ -object EncodeClientParamsSpec extends DefaultRunnableSpec with EncodeClientParams { +object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientParams { - val anyClientParam: Gen[Random with Sized, Client.ClientParams] = HttpGen.clientParams( + val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientParams( HttpGen.httpData( Gen.listOf(Gen.alphaNumericString), ), ) - def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientParams] = HttpGen.clientParams( + def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientParams( for { content <- Gen.alphaNumericStringBounded(size, size) data <- Gen.fromIterable(List(HttpData.fromString(content))) diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index 71dfd8d831..aad22542d1 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -18,7 +18,7 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { check(charsetGen) { charset => val encoded = Client - .ClientParams( + .ClientRequest( Method.GET, URL(Path("/")), getHeaders = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), @@ -33,7 +33,7 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { test("should map bytes to default utf-8 if no charset given") { val data = Chunk.fromArray("abc".getBytes()) val content = HttpData.BinaryChunk(data) - val request = Client.ClientParams(Method.GET, URL(Path("/")), data = content) + val request = Client.ClientRequest(Method.GET, URL(Path("/")), data = content) val encoded = request.getBodyAsString val actual = Option(new String(data.toArray, HTTP_CHARSET)) assert(actual)(equalTo(encoded)) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index d71c0238ca..feefb1182a 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -2,7 +2,7 @@ package zhttp.internal import io.netty.buffer.Unpooled import zhttp.http._ -import zhttp.service.Client.ClientParams +import zhttp.service.Client.ClientRequest import zio.random.Random import zio.stream.ZStream import zio.test.{Gen, Sized} @@ -17,7 +17,7 @@ object HttpGen { url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) data <- dataGen - } yield ClientParams(method, url, headers, data) + } yield ClientRequest(method, url, headers, data) def clientParamsForFileHttpData() = { for { @@ -25,7 +25,7 @@ object HttpGen { method <- HttpGen.method url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) - } yield ClientParams(method, url, headers, HttpData.fromFile(file)) + } yield ClientRequest(method, url, headers, HttpData.fromFile(file)) } def cookies: Gen[Random with Sized, Cookie] = for { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 93de634c9a..5745b2e662 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -37,7 +37,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => port <- DynamicServer.getPort data = HttpData.fromString(content) response <- Client.request( - Client.ClientParams(method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", port)), headers, data), + Client.ClientRequest(method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", port)), headers, data), ClientSSLOptions.DefaultSSL, ) } yield response From 3b9ea3a4b4b725a96d6125b6d6fbec412d367642 Mon Sep 17 00:00:00 2001 From: Brendan McKee Date: Thu, 20 Jan 2022 21:17:12 -0800 Subject: [PATCH 21/95] refactor: use declarative encoding for http.middleware (#869) --- zio-http/src/main/scala/zhttp/http/Http.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index b5794b9fbc..79701369f3 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -192,7 +192,7 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => */ final def middleware[R1 <: R, E1 >: E, A1 <: A, B1 >: B, A2, B2]( mid: Middleware[R1, E1, A1, B1, A2, B2], - ): Http[R1, E1, A2, B2] = mid(self) + ): Http[R1, E1, A2, B2] = Http.RunMiddleware(self, mid) /** * Named alias for `<>` @@ -348,6 +348,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => case FoldHttp(self, ee, bb, dd) => self.execute(a).foldExit(ee(_).execute(a), bb(_).execute(a), dd.execute(a)) + + case RunMiddleware(app, mid) => mid(app).execute(a) } } @@ -634,4 +636,9 @@ object Http { private case object Empty extends Http[Any, Nothing, Any, Nothing] private case object Identity extends Http[Any, Nothing, Any, Nothing] + + private final case class RunMiddleware[R, E, A1, B1, A2, B2]( + http: Http[R, E, A1, B1], + mid: Middleware[R, E, A1, B1, A2, B2], + ) extends Http[R, E, A2, B2] } From ecc3d8a5f542e79fa67152c0f7722926db2d062d Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 21 Jan 2022 13:59:50 +0530 Subject: [PATCH 22/95] Move docs to v1.x directory (#861) --- docs/website/docs/v1.x/_category_.json | 4 ++++ docs/website/docs/{ => v1.x}/client/_category_.json | 0 docs/website/docs/{ => v1.x}/client/index.md | 0 docs/website/docs/{ => v1.x}/dsl/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/cookies/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/cookies/index.md | 0 docs/website/docs/{ => v1.x}/dsl/headers/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/headers/index.md | 0 docs/website/docs/{ => v1.x}/dsl/http-data/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/http-data/index.md | 0 .../website/docs/{ => v1.x}/dsl/http-endpoint/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/http-endpoint/index.md | 0 docs/website/docs/{ => v1.x}/dsl/http/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/http/index.md | 0 docs/website/docs/{ => v1.x}/dsl/middleware/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/middleware/index.md | 0 docs/website/docs/{ => v1.x}/dsl/request/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/request/index.md | 0 docs/website/docs/{ => v1.x}/dsl/response/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/response/index.md | 0 docs/website/docs/{ => v1.x}/dsl/server/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/server/config.md | 0 docs/website/docs/{ => v1.x}/dsl/socket/_category_.json | 0 docs/website/docs/{ => v1.x}/dsl/socket/index.md | 0 docs/website/docs/{ => v1.x}/examples/_category_.json | 0 .../{ => v1.x}/examples/advanced-examples/_category_.json | 0 .../{ => v1.x}/examples/advanced-examples/authentication.md | 0 .../{ => v1.x}/examples/advanced-examples/concrete-entity.md | 0 .../docs/{ => v1.x}/examples/advanced-examples/cors.md | 0 .../examples/advanced-examples/hello-world-advanced.md | 0 .../docs/{ => v1.x}/examples/advanced-examples/stream-file.md | 0 .../{ => v1.x}/examples/advanced-examples/stream-response.md | 0 .../examples/advanced-examples/web-socket-advanced.md | 0 .../examples/zio-http-basic-examples/_category_.json | 0 .../examples/zio-http-basic-examples/hello-world.md | 0 .../examples/zio-http-basic-examples/https-client.md | 0 .../examples/zio-http-basic-examples/https-server.md | 0 .../examples/zio-http-basic-examples/simple-client.md | 0 .../{ => v1.x}/examples/zio-http-basic-examples/web-socket.md | 0 docs/website/docs/{ => v1.x}/getting-started.md | 0 docs/website/docs/{ => v1.x}/index.md | 0 docs/website/docs/{ => v1.x}/integrations/_category_.json | 0 docs/website/docs/{ => v1.x}/integrations/index.md | 0 docs/website/docs/{ => v1.x}/testing/_category_.json | 0 docs/website/docs/{ => v1.x}/testing/index.md | 0 docs/website/docs/v2.x/_category_.json | 4 ++++ docs/website/docusaurus.config.js | 2 +- 47 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 docs/website/docs/v1.x/_category_.json rename docs/website/docs/{ => v1.x}/client/_category_.json (100%) rename docs/website/docs/{ => v1.x}/client/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/cookies/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/cookies/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/headers/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/headers/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/http-data/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/http-data/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/http-endpoint/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/http-endpoint/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/http/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/http/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/middleware/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/middleware/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/request/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/request/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/response/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/response/index.md (100%) rename docs/website/docs/{ => v1.x}/dsl/server/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/server/config.md (100%) rename docs/website/docs/{ => v1.x}/dsl/socket/_category_.json (100%) rename docs/website/docs/{ => v1.x}/dsl/socket/index.md (100%) rename docs/website/docs/{ => v1.x}/examples/_category_.json (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/_category_.json (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/authentication.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/concrete-entity.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/cors.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/hello-world-advanced.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/stream-file.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/stream-response.md (100%) rename docs/website/docs/{ => v1.x}/examples/advanced-examples/web-socket-advanced.md (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/_category_.json (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/hello-world.md (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/https-client.md (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/https-server.md (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/simple-client.md (100%) rename docs/website/docs/{ => v1.x}/examples/zio-http-basic-examples/web-socket.md (100%) rename docs/website/docs/{ => v1.x}/getting-started.md (100%) rename docs/website/docs/{ => v1.x}/index.md (100%) rename docs/website/docs/{ => v1.x}/integrations/_category_.json (100%) rename docs/website/docs/{ => v1.x}/integrations/index.md (100%) rename docs/website/docs/{ => v1.x}/testing/_category_.json (100%) rename docs/website/docs/{ => v1.x}/testing/index.md (100%) create mode 100644 docs/website/docs/v2.x/_category_.json diff --git a/docs/website/docs/v1.x/_category_.json b/docs/website/docs/v1.x/_category_.json new file mode 100644 index 0000000000..9bb7f41bfc --- /dev/null +++ b/docs/website/docs/v1.x/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "v1.x", + "position": 1 +} diff --git a/docs/website/docs/client/_category_.json b/docs/website/docs/v1.x/client/_category_.json similarity index 100% rename from docs/website/docs/client/_category_.json rename to docs/website/docs/v1.x/client/_category_.json diff --git a/docs/website/docs/client/index.md b/docs/website/docs/v1.x/client/index.md similarity index 100% rename from docs/website/docs/client/index.md rename to docs/website/docs/v1.x/client/index.md diff --git a/docs/website/docs/dsl/_category_.json b/docs/website/docs/v1.x/dsl/_category_.json similarity index 100% rename from docs/website/docs/dsl/_category_.json rename to docs/website/docs/v1.x/dsl/_category_.json diff --git a/docs/website/docs/dsl/cookies/_category_.json b/docs/website/docs/v1.x/dsl/cookies/_category_.json similarity index 100% rename from docs/website/docs/dsl/cookies/_category_.json rename to docs/website/docs/v1.x/dsl/cookies/_category_.json diff --git a/docs/website/docs/dsl/cookies/index.md b/docs/website/docs/v1.x/dsl/cookies/index.md similarity index 100% rename from docs/website/docs/dsl/cookies/index.md rename to docs/website/docs/v1.x/dsl/cookies/index.md diff --git a/docs/website/docs/dsl/headers/_category_.json b/docs/website/docs/v1.x/dsl/headers/_category_.json similarity index 100% rename from docs/website/docs/dsl/headers/_category_.json rename to docs/website/docs/v1.x/dsl/headers/_category_.json diff --git a/docs/website/docs/dsl/headers/index.md b/docs/website/docs/v1.x/dsl/headers/index.md similarity index 100% rename from docs/website/docs/dsl/headers/index.md rename to docs/website/docs/v1.x/dsl/headers/index.md diff --git a/docs/website/docs/dsl/http-data/_category_.json b/docs/website/docs/v1.x/dsl/http-data/_category_.json similarity index 100% rename from docs/website/docs/dsl/http-data/_category_.json rename to docs/website/docs/v1.x/dsl/http-data/_category_.json diff --git a/docs/website/docs/dsl/http-data/index.md b/docs/website/docs/v1.x/dsl/http-data/index.md similarity index 100% rename from docs/website/docs/dsl/http-data/index.md rename to docs/website/docs/v1.x/dsl/http-data/index.md diff --git a/docs/website/docs/dsl/http-endpoint/_category_.json b/docs/website/docs/v1.x/dsl/http-endpoint/_category_.json similarity index 100% rename from docs/website/docs/dsl/http-endpoint/_category_.json rename to docs/website/docs/v1.x/dsl/http-endpoint/_category_.json diff --git a/docs/website/docs/dsl/http-endpoint/index.md b/docs/website/docs/v1.x/dsl/http-endpoint/index.md similarity index 100% rename from docs/website/docs/dsl/http-endpoint/index.md rename to docs/website/docs/v1.x/dsl/http-endpoint/index.md diff --git a/docs/website/docs/dsl/http/_category_.json b/docs/website/docs/v1.x/dsl/http/_category_.json similarity index 100% rename from docs/website/docs/dsl/http/_category_.json rename to docs/website/docs/v1.x/dsl/http/_category_.json diff --git a/docs/website/docs/dsl/http/index.md b/docs/website/docs/v1.x/dsl/http/index.md similarity index 100% rename from docs/website/docs/dsl/http/index.md rename to docs/website/docs/v1.x/dsl/http/index.md diff --git a/docs/website/docs/dsl/middleware/_category_.json b/docs/website/docs/v1.x/dsl/middleware/_category_.json similarity index 100% rename from docs/website/docs/dsl/middleware/_category_.json rename to docs/website/docs/v1.x/dsl/middleware/_category_.json diff --git a/docs/website/docs/dsl/middleware/index.md b/docs/website/docs/v1.x/dsl/middleware/index.md similarity index 100% rename from docs/website/docs/dsl/middleware/index.md rename to docs/website/docs/v1.x/dsl/middleware/index.md diff --git a/docs/website/docs/dsl/request/_category_.json b/docs/website/docs/v1.x/dsl/request/_category_.json similarity index 100% rename from docs/website/docs/dsl/request/_category_.json rename to docs/website/docs/v1.x/dsl/request/_category_.json diff --git a/docs/website/docs/dsl/request/index.md b/docs/website/docs/v1.x/dsl/request/index.md similarity index 100% rename from docs/website/docs/dsl/request/index.md rename to docs/website/docs/v1.x/dsl/request/index.md diff --git a/docs/website/docs/dsl/response/_category_.json b/docs/website/docs/v1.x/dsl/response/_category_.json similarity index 100% rename from docs/website/docs/dsl/response/_category_.json rename to docs/website/docs/v1.x/dsl/response/_category_.json diff --git a/docs/website/docs/dsl/response/index.md b/docs/website/docs/v1.x/dsl/response/index.md similarity index 100% rename from docs/website/docs/dsl/response/index.md rename to docs/website/docs/v1.x/dsl/response/index.md diff --git a/docs/website/docs/dsl/server/_category_.json b/docs/website/docs/v1.x/dsl/server/_category_.json similarity index 100% rename from docs/website/docs/dsl/server/_category_.json rename to docs/website/docs/v1.x/dsl/server/_category_.json diff --git a/docs/website/docs/dsl/server/config.md b/docs/website/docs/v1.x/dsl/server/config.md similarity index 100% rename from docs/website/docs/dsl/server/config.md rename to docs/website/docs/v1.x/dsl/server/config.md diff --git a/docs/website/docs/dsl/socket/_category_.json b/docs/website/docs/v1.x/dsl/socket/_category_.json similarity index 100% rename from docs/website/docs/dsl/socket/_category_.json rename to docs/website/docs/v1.x/dsl/socket/_category_.json diff --git a/docs/website/docs/dsl/socket/index.md b/docs/website/docs/v1.x/dsl/socket/index.md similarity index 100% rename from docs/website/docs/dsl/socket/index.md rename to docs/website/docs/v1.x/dsl/socket/index.md diff --git a/docs/website/docs/examples/_category_.json b/docs/website/docs/v1.x/examples/_category_.json similarity index 100% rename from docs/website/docs/examples/_category_.json rename to docs/website/docs/v1.x/examples/_category_.json diff --git a/docs/website/docs/examples/advanced-examples/_category_.json b/docs/website/docs/v1.x/examples/advanced-examples/_category_.json similarity index 100% rename from docs/website/docs/examples/advanced-examples/_category_.json rename to docs/website/docs/v1.x/examples/advanced-examples/_category_.json diff --git a/docs/website/docs/examples/advanced-examples/authentication.md b/docs/website/docs/v1.x/examples/advanced-examples/authentication.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/authentication.md rename to docs/website/docs/v1.x/examples/advanced-examples/authentication.md diff --git a/docs/website/docs/examples/advanced-examples/concrete-entity.md b/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/concrete-entity.md rename to docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md diff --git a/docs/website/docs/examples/advanced-examples/cors.md b/docs/website/docs/v1.x/examples/advanced-examples/cors.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/cors.md rename to docs/website/docs/v1.x/examples/advanced-examples/cors.md diff --git a/docs/website/docs/examples/advanced-examples/hello-world-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/hello-world-advanced.md rename to docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md diff --git a/docs/website/docs/examples/advanced-examples/stream-file.md b/docs/website/docs/v1.x/examples/advanced-examples/stream-file.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/stream-file.md rename to docs/website/docs/v1.x/examples/advanced-examples/stream-file.md diff --git a/docs/website/docs/examples/advanced-examples/stream-response.md b/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/stream-response.md rename to docs/website/docs/v1.x/examples/advanced-examples/stream-response.md diff --git a/docs/website/docs/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md similarity index 100% rename from docs/website/docs/examples/advanced-examples/web-socket-advanced.md rename to docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md diff --git a/docs/website/docs/examples/zio-http-basic-examples/_category_.json b/docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/_category_.json rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json diff --git a/docs/website/docs/examples/zio-http-basic-examples/hello-world.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/hello-world.md rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/https-client.md rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-server.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-server.md similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/https-server.md rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/https-server.md diff --git a/docs/website/docs/examples/zio-http-basic-examples/simple-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/simple-client.md rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md diff --git a/docs/website/docs/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md similarity index 100% rename from docs/website/docs/examples/zio-http-basic-examples/web-socket.md rename to docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md diff --git a/docs/website/docs/getting-started.md b/docs/website/docs/v1.x/getting-started.md similarity index 100% rename from docs/website/docs/getting-started.md rename to docs/website/docs/v1.x/getting-started.md diff --git a/docs/website/docs/index.md b/docs/website/docs/v1.x/index.md similarity index 100% rename from docs/website/docs/index.md rename to docs/website/docs/v1.x/index.md diff --git a/docs/website/docs/integrations/_category_.json b/docs/website/docs/v1.x/integrations/_category_.json similarity index 100% rename from docs/website/docs/integrations/_category_.json rename to docs/website/docs/v1.x/integrations/_category_.json diff --git a/docs/website/docs/integrations/index.md b/docs/website/docs/v1.x/integrations/index.md similarity index 100% rename from docs/website/docs/integrations/index.md rename to docs/website/docs/v1.x/integrations/index.md diff --git a/docs/website/docs/testing/_category_.json b/docs/website/docs/v1.x/testing/_category_.json similarity index 100% rename from docs/website/docs/testing/_category_.json rename to docs/website/docs/v1.x/testing/_category_.json diff --git a/docs/website/docs/testing/index.md b/docs/website/docs/v1.x/testing/index.md similarity index 100% rename from docs/website/docs/testing/index.md rename to docs/website/docs/v1.x/testing/index.md diff --git a/docs/website/docs/v2.x/_category_.json b/docs/website/docs/v2.x/_category_.json new file mode 100644 index 0000000000..870aeb7ca5 --- /dev/null +++ b/docs/website/docs/v2.x/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "v2.x", + "position": 2 +} diff --git a/docs/website/docusaurus.config.js b/docs/website/docusaurus.config.js index 86f3b5fbbc..a6282e072b 100644 --- a/docs/website/docusaurus.config.js +++ b/docs/website/docusaurus.config.js @@ -43,7 +43,7 @@ const config = { items: [ { type: 'doc', - docId: 'index', + docId: 'v1.x/index', position: 'left', label: 'Tutorial', } From b9784ac76f075b72a9a1f4fc9bc7ea69ee9a8e96 Mon Sep 17 00:00:00 2001 From: kaushik143 Date: Fri, 21 Jan 2022 14:03:53 +0530 Subject: [PATCH 23/95] Bug Add host in client from absolute URL (#847) * feat(Client): Add host in client from absolute URL * feat(Client): Refactor and add spec for host value * feat(Client): fmt formatting * feat(Client): fmt formatting * feat(Client): use setHeaders from netty * feat(Client): Add spec for host * feat(Client): Add spec for host * feat(Client): Rename clientParams to clientRequest --- .../src/main/scala/example/SimpleClient.scala | 8 ++-- .../zhttp/service/EncodeClientParams.scala | 16 ++++++-- .../zhttp/http/EncodeClientRequestSpec.scala | 28 +++++++++++++- .../test/scala/zhttp/internal/HttpGen.scala | 37 +++++++++++++------ 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/example/src/main/scala/example/SimpleClient.scala b/example/src/main/scala/example/SimpleClient.scala index 165bd39d81..da885c0a50 100644 --- a/example/src/main/scala/example/SimpleClient.scala +++ b/example/src/main/scala/example/SimpleClient.scala @@ -1,16 +1,14 @@ package example -import zhttp.http.Headers import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio.{App, ExitCode, URIO, console} object SimpleClient extends App { - val env = ChannelFactory.auto ++ EventLoopGroup.auto() - val url = "http://sports.api.decathlon.com/groups/water-aerobics" - val headers = Headers.host("sports.api.decathlon.com") + val env = ChannelFactory.auto ++ EventLoopGroup.auto() + val url = "http://sports.api.decathlon.com/groups/water-aerobics" val program = for { - res <- Client.request(url, headers) + res <- Client.request(url) data <- res.getBodyAsString _ <- console.putStrLn { data } } yield () diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index efa935bbce..b3479fe682 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -9,13 +9,21 @@ trait EncodeClientParams { * Converts client params to JFullHttpRequest */ def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { - val method = req.method.asHttpMethod - val uri = req.url.asString - val content = req.getBodyAsString match { + val method = req.method.asHttpMethod + val url = req.url + val uri = url.asString + val content = req.getBodyAsString match { case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) case None => Unpooled.EMPTY_BUFFER } - val headers = req.getHeaders.encode + + val encodedReqHeaders = req.getHeaders.encode + + val headers = url.host match { + case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) + case None => encodedReqHeaders + } + val writerIndex = content.writerIndex() if (writerIndex != 0) { headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index 47e007098c..fb444de316 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -9,13 +9,20 @@ import zio.test._ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientParams { - val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientParams( + val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( HttpGen.httpData( Gen.listOf(Gen.alphaNumericString), ), ) - def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientParams( + val clientParamWithAbsoluteUrl = HttpGen.clientRequest( + dataGen = HttpGen.httpData( + Gen.listOf(Gen.alphaNumericString), + ), + urlGen = HttpGen.genAbsoluteURL, + ) + + def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( for { content <- Gen.alphaNumericStringBounded(size, size) data <- Gen.fromIterable(List(HttpData.fromString(content))) @@ -52,6 +59,23 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientPara val req = encodeClientParams(HttpVersion.HTTP_1_1, params) assert(req.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong)(equalTo(5L)) } + } + + testM("host header") { + check(anyClientParam) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val hostHeader = HttpHeaderNames.HOST + assert(Option(req.headers().get(hostHeader)))(equalTo(params.url.host)) + } + } + + testM("host header when absolute url") { + check(clientParamWithAbsoluteUrl) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val reqHeaders = req.headers() + val hostHeader = HttpHeaderNames.HOST + + assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && + assert(Option(reqHeaders.get(hostHeader)))(equalTo(params.url.host)) + } } } } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index feefb1182a..996deb4d4a 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -1,6 +1,7 @@ package zhttp.internal import io.netty.buffer.Unpooled +import zhttp.http.URL.Location import zhttp.http._ import zhttp.service.Client.ClientRequest import zio.random.Random @@ -11,11 +12,16 @@ import zio.{Chunk, ZIO} import java.io.File object HttpGen { - def clientParams[R](dataGen: Gen[R, HttpData]) = + def clientRequest[R]( + dataGen: Gen[R, HttpData], + methodGen: Gen[R, Method] = HttpGen.method, + urlGen: Gen[Random with Sized, URL] = HttpGen.url, + headerGen: Gen[Random with Sized, Header] = HttpGen.header, + ) = for { - method <- HttpGen.method - url <- HttpGen.url - headers <- Gen.listOf(HttpGen.header).map(Headers(_)) + method <- methodGen + url <- urlGen + headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen } yield ClientRequest(method, url, headers, data) @@ -61,16 +67,16 @@ object HttpGen { ) } yield cnt - def location: Gen[Random with Sized, URL.Location] = { - def genRelative = Gen.const(URL.Location.Relative) + def genRelativeLocation: Gen[Any, Location.Relative.type] = Gen.const(URL.Location.Relative) - def genAbsolute = for { - scheme <- Gen.fromIterable(List(Scheme.HTTP, Scheme.HTTPS)) - host <- Gen.alphaNumericStringBounded(1, 5) - port <- Gen.int(0, Int.MaxValue) - } yield URL.Location.Absolute(scheme, host, port) + def genAbsoluteLocation: Gen[Random with Sized, Location.Absolute] = for { + scheme <- Gen.fromIterable(List(Scheme.HTTP, Scheme.HTTPS)) + host <- Gen.alphaNumericStringBounded(1, 5) + port <- Gen.int(0, Int.MaxValue) + } yield URL.Location.Absolute(scheme, host, port) - Gen.fromIterable(List(genRelative, genAbsolute)).flatten + def location: Gen[Random with Sized, URL.Location] = { + Gen.fromIterable(List(genRelativeLocation, genAbsoluteLocation)).flatten } def method: Gen[Any, Method] = Gen.fromIterable( @@ -189,4 +195,11 @@ object HttpGen { kind <- HttpGen.location queryParams <- Gen.mapOf(Gen.alphaNumericString, Gen.listOf(Gen.alphaNumericString)) } yield URL(path, kind, queryParams) + + def genAbsoluteURL = for { + path <- HttpGen.path + kind <- HttpGen.genAbsoluteLocation + queryParams <- Gen.mapOf(Gen.alphaNumericString, Gen.listOf(Gen.alphaNumericString)) + } yield URL(path, kind, queryParams) + } From a36afbc11ded675bd97e84fe48641a9e94778834 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 21 Jan 2022 15:05:40 +0530 Subject: [PATCH 24/95] Doc website fix (#871) --- docs/website/docusaurus.config.js | 2 +- docs/website/yarn.lock | 8873 +++++++++++++++++++++++++++++ 2 files changed, 8874 insertions(+), 1 deletion(-) create mode 100644 docs/website/yarn.lock diff --git a/docs/website/docusaurus.config.js b/docs/website/docusaurus.config.js index a6282e072b..59837bb74c 100644 --- a/docs/website/docusaurus.config.js +++ b/docs/website/docusaurus.config.js @@ -57,7 +57,7 @@ const config = { items: [ { label: 'Documents', - to: '/docs/index', + to: '/docs/v1.x/index', }, ], }, diff --git a/docs/website/yarn.lock b/docs/website/yarn.lock new file mode 100644 index 0000000000..bafec47e51 --- /dev/null +++ b/docs/website/yarn.lock @@ -0,0 +1,8873 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@algolia/autocomplete-core@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.5.0.tgz#6c91c9de7748e9c103846828a58dfe92bd4d6689" + integrity sha512-E7+VJwcvwMM8vPeaVn7fNUgix8WHV8A1WUeHDi2KHemCaaGc8lvUnP3QnvhMxiDhTe7OpMEv4o2TBUMyDgThaw== + dependencies: + "@algolia/autocomplete-shared" "1.5.0" + +"@algolia/autocomplete-preset-algolia@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.5.0.tgz#61671f09c0c77133d9baf1356719f8378c48437a" + integrity sha512-iiFxKERGHkvkiupmrFJbvESpP/zv5jSgH714XRiP5LDvUHaYOo4GLAwZCFf2ef/L5tdtPBARvekn6k1Xf33gjA== + dependencies: + "@algolia/autocomplete-shared" "1.5.0" + +"@algolia/autocomplete-shared@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.5.0.tgz#09580bc89408a2ab5f29e312120dad68f58019bd" + integrity sha512-bRSkqHHHSwZYbFY3w9hgMyQRm86Wz27bRaGCbNldLfbk0zUjApmE4ajx+ZCVSLqxvcUEjMqZFJzDsder12eKsg== + +"@algolia/cache-browser-local-storage@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.12.0.tgz#1f873e4f28a39d25b0a589ebe8f826509458e1fb" + integrity sha512-l+G560B6N1k0rIcOjTO1yCzFUbg2Zy2HCii9s03e13jGgqduVQmk79UUCYszjsJ5GPJpUEKcVEtAIpP7tjsXVA== + dependencies: + "@algolia/cache-common" "4.12.0" + +"@algolia/cache-common@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-common/-/cache-common-4.12.0.tgz#c1111a4d3e9ba2d52cadb4523152580db0887293" + integrity sha512-2Z8BV+NX7oN7RmmQbLqmW8lfN9aAjOexX1FJjzB0YfKC9ifpi9Jl4nSxlnbU+iLR6QhHo0IfuyQ7wcnucCGCGQ== + +"@algolia/cache-in-memory@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/cache-in-memory/-/cache-in-memory-4.12.0.tgz#f4bdcbf8a6419f0166cfc7ef5594af871741e29e" + integrity sha512-b6ANkZF6vGAo+sYv6g25W5a0u3o6F549gEAgtTDTVA1aHcdWwe/HG/dTJ7NsnHbuR+A831tIwnNYQjRp3/V/Jw== + dependencies: + "@algolia/cache-common" "4.12.0" + +"@algolia/client-account@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-account/-/client-account-4.12.0.tgz#b28445b47e2abf81dc76982d16ba8458f5c99521" + integrity sha512-gzXN75ZydNheNXUN3epS+aLsKnB/PHFVlGUUjXL8WHs4lJP3B5FtHvaA/NCN5DsM3aamhuY5p0ff1XIA+Lbcrw== + dependencies: + "@algolia/client-common" "4.12.0" + "@algolia/client-search" "4.12.0" + "@algolia/transporter" "4.12.0" + +"@algolia/client-analytics@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-analytics/-/client-analytics-4.12.0.tgz#470f115517256c92a5605ae95762531c7906ec74" + integrity sha512-rO2cZCt00Opk66QBZb7IBGfCq4ZE3EiuGkXssf2Monb5urujy0r8CknK2i7bzaKtPbd2vlvhmLP4CEHQqF6SLQ== + dependencies: + "@algolia/client-common" "4.12.0" + "@algolia/client-search" "4.12.0" + "@algolia/requester-common" "4.12.0" + "@algolia/transporter" "4.12.0" + +"@algolia/client-common@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-common/-/client-common-4.12.0.tgz#402395e2cffad89188d76b83615acffb3e45e658" + integrity sha512-fcrFN7FBmxiSyjeu3sF4OnPkC1l7/8oyQ8RMM8CHpVY8cad6/ay35MrfRfgfqdzdFA8LzcBYO7fykuJv0eOqxw== + dependencies: + "@algolia/requester-common" "4.12.0" + "@algolia/transporter" "4.12.0" + +"@algolia/client-personalization@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-personalization/-/client-personalization-4.12.0.tgz#09c89c1558a91db3bfa60d17f7258ae63861352b" + integrity sha512-wCJfSQEmX6ZOuJBJGjy+sbXiW0iy7tMNAhsVMV9RRaJE4727e5WAqwFWZssD877WQ74+/nF/VyTaB1+wejo33Q== + dependencies: + "@algolia/client-common" "4.12.0" + "@algolia/requester-common" "4.12.0" + "@algolia/transporter" "4.12.0" + +"@algolia/client-search@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/client-search/-/client-search-4.12.0.tgz#ac099ee9f8de85ec204d840bcac734224c7d150c" + integrity sha512-ik6dswcTQtOdZN+8aKntI9X2E6Qpqjtyda/+VANiHThY9GD2PBXuNuuC2HvlF26AbBYp5xaSE/EKxn1DIiIJ4Q== + dependencies: + "@algolia/client-common" "4.12.0" + "@algolia/requester-common" "4.12.0" + "@algolia/transporter" "4.12.0" + +"@algolia/events@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@algolia/events/-/events-4.0.1.tgz#fd39e7477e7bc703d7f893b556f676c032af3950" + integrity sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ== + +"@algolia/logger-common@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-common/-/logger-common-4.12.0.tgz#0f9dbe7ace88194b395a2cb958490eb47ac91f8e" + integrity sha512-V//9rzLdJujA3iZ/tPhmKR/m2kjSZrymxOfUiF3024u2/7UyOpH92OOCrHUf023uMGYHRzyhBz5ESfL1oCdh7g== + +"@algolia/logger-console@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/logger-console/-/logger-console-4.12.0.tgz#a40edeb989bf0d7ff79d989171dad64cd0f01225" + integrity sha512-pHvoGv53KXRIJHLk9uxBwKirwEo12G9+uo0sJLWESThAN3v5M+ycliU1AkUXQN8+9rds2KxfULAb+vfyfBKf8A== + dependencies: + "@algolia/logger-common" "4.12.0" + +"@algolia/requester-browser-xhr@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.12.0.tgz#64e8e4d4f0724e477421454215195400351cfe61" + integrity sha512-rGlHNMM3jIZBwSpz33CVkeXHilzuzHuFXEEW1icP/k3KW7kwBrKFJwBy42RzAJa5BYlLsTCFTS3xkPhYwTQKLg== + dependencies: + "@algolia/requester-common" "4.12.0" + +"@algolia/requester-common@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-common/-/requester-common-4.12.0.tgz#b4d96f3cbd73206b6042e523d414a34cc005c2e2" + integrity sha512-qgfdc73nXqpVyOMr6CMTx3nXvud9dP6GcMGDqPct+fnxogGcJsp24cY2nMqUrAfgmTJe9Nmy7Lddv0FyHjONMg== + +"@algolia/requester-node-http@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/requester-node-http/-/requester-node-http-4.12.0.tgz#8d8e1b67edbaec8e8e8b8c7c606945b969667267" + integrity sha512-mOTRGf/v/dXshBoZKNhMG00ZGxoUH9QdSpuMKYnuWwIgstN24uj3DQx+Ho3c+uq0TYfq7n2v71uoJWuiW32NMQ== + dependencies: + "@algolia/requester-common" "4.12.0" + +"@algolia/transporter@4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@algolia/transporter/-/transporter-4.12.0.tgz#e375e10731df95f1be3593b32e86b5c6452cc213" + integrity sha512-MOQVHZ4BcBpf3LtOY/3fqXHAcvI8MahrXDHk9QrBE/iGensQhDiZby5Dn3o2JN/zd9FMnVbdPQ8gnkiMwZiakQ== + dependencies: + "@algolia/cache-common" "4.12.0" + "@algolia/logger-common" "4.12.0" + "@algolia/requester-common" "4.12.0" + +"@babel/code-frame@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.5.5": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" + integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== + +"@babel/core@7.12.9": + version "7.12.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" + integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.5" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.7" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.9" + "@babel/types" "^7.12.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/core@^7.12.16", "@babel/core@^7.12.3": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.10.tgz#ebd034f8e7ac2b6bfcdaa83a161141a646f74b50" + integrity sha512-pbiIdZbCiMx/MM6toR+OfXarYix3uz0oVsnNtfdAGTcCTu3w/JGF8JhirevXLBJUu0WguSZI12qpKnx7EeMyLA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.10" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.10" + "@babel/types" "^7.16.8" + 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@^7.12.15", "@babel/generator@^7.12.5", "@babel/generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== + dependencies: + "@babel/types" "^7.16.8" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@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@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz#8a6959b9cc818a88815ba3c5474619e9c0f2c21c" + integrity sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg== + 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" + +"@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz#0cb82b9bac358eb73bfbd73985a776bfa6b14d48" + integrity sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" + integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + 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" + +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-plugin-utils@7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + 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" + +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== + dependencies: + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helpers@^7.12.5", "@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.12.16", "@babel/parser@^7.12.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.10.tgz#aba1b1cb9696a24a19f59c41af9cf17d1c716a88" + integrity sha512-Sm/S9Or6nN8uiFsQU1yodyDW3MWXQhFeqzMPM+t8MJjM+pLsnFVxFZzkpXKvUXh+Gz9cbMoYYs484+Jw/NTEFQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + +"@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz#712357570b612106ef5426d13dc433ce0f200c2a" + integrity sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" + integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.12.1" + +"@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz#94593ef1ddf37021a25bdcb5754c4a8d534b01d8" + integrity sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" + integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.10" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz#9d9d357cc818aa7ae7935917c1257f67677a0926" + integrity sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + +"@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-classes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + 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-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-destructuring@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz#ca9588ae2d63978a4c29d3f33282d8603f618e23" + integrity sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + dependencies: + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" + integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" + integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + dependencies: + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + +"@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + +"@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-constant-elements@^7.12.1": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.7.tgz#19e9e4c2df2f6c3e6b3aea11778297d81db8df62" + integrity sha512-lF+cfsyTgwWkcw715J88JhMYJ5GpysYNLhLP1PkvkhTRN7B3e74R/1KsDxFxhRpSn0UUD3IWM4GvdBR2PEbbQQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-display-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" + integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-react-jsx-development@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz#43a00724a3ed2557ed3f276a01a929e6686ac7b8" + integrity sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.16.7" + +"@babel/plugin-transform-react-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4" + integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/plugin-transform-react-pure-annotations@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz#232bfd2f12eb551d6d7d01d13fe3f86b45eb9c67" + integrity sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-runtime@^7.15.0": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz#53d9fd3496daedce1dd99639097fa5d14f4c7c2c" + integrity sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + +"@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.15.6": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" + integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== + dependencies: + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.11" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.8" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.20.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.12.13", "@babel/preset-react@^7.12.5": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.16.7.tgz#4c18150491edc69c183ff818f9f2aecbe5d93852" + integrity sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-react-display-name" "^7.16.7" + "@babel/plugin-transform-react-jsx" "^7.16.7" + "@babel/plugin-transform-react-jsx-development" "^7.16.7" + "@babel/plugin-transform-react-pure-annotations" "^7.16.7" + +"@babel/preset-typescript@^7.12.16": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + +"@babel/runtime-corejs3@^7.15.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.16.8.tgz#ea533d96eda6fdc76b1812248e9fbd0c11d4a1a7" + integrity sha512-3fKhuICS1lMz0plI5ktOE/yEtBRMVxplzRkdn6mJQ197XiY0JnrzYV0+Mxozq3JZ8SBV9Ecurmw1XsGbwOf+Sg== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.12.7", "@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.12.13", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f" + integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== + 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.10" + "@babel/types" "^7.16.8" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.12.6", "@babel/types@^7.12.7", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.4.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@docsearch/css@3.0.0-alpha.42": + version "3.0.0-alpha.42" + resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-3.0.0-alpha.42.tgz#deb6049e999d6ca9451eba4793cb5b6da28c8773" + integrity sha512-AGwI2AXUacYhVOHmYnsXoYDJKO6Ued2W+QO80GERbMLhC7GH5tfvtW5REs/s7jSdcU3vzFoxT8iPDBCh/PkrlQ== + +"@docsearch/react@^3.0.0-alpha.39": + version "3.0.0-alpha.42" + resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-3.0.0-alpha.42.tgz#1d22a2b05779f24d090ff8d7ff2699e4d50dff5c" + integrity sha512-1aOslZJDxwUUcm2QRNmlEePUgL8P5fOAeFdOLDMctHQkV2iTja9/rKVbkP8FZbIUnZxuuCCn8ErLrjD/oXWOag== + dependencies: + "@algolia/autocomplete-core" "1.5.0" + "@algolia/autocomplete-preset-algolia" "1.5.0" + "@docsearch/css" "3.0.0-alpha.42" + algoliasearch "^4.0.0" + +"@docusaurus/core@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.0.0-beta.8.tgz#7e24547a26e34e4d288f19883e08ac29b7946325" + integrity sha512-KVbZoOCxQKvbX1RT8qrHAsPVYPGDnXFevTeJbZW1XQb0OPv7oh5nijXJvzNeGupXP561BByrsdHT7IxM/hT0CQ== + dependencies: + "@babel/core" "^7.12.16" + "@babel/generator" "^7.12.15" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-runtime" "^7.15.0" + "@babel/preset-env" "^7.15.6" + "@babel/preset-react" "^7.12.13" + "@babel/preset-typescript" "^7.12.16" + "@babel/runtime" "^7.15.4" + "@babel/runtime-corejs3" "^7.15.4" + "@babel/traverse" "^7.12.13" + "@docusaurus/cssnano-preset" "2.0.0-beta.8" + "@docusaurus/react-loadable" "5.5.0" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-common" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + "@slorber/static-site-generator-webpack-plugin" "^4.0.0" + "@svgr/webpack" "^5.5.0" + autoprefixer "^10.3.5" + babel-loader "^8.2.2" + babel-plugin-dynamic-import-node "2.3.0" + boxen "^5.0.1" + chalk "^4.1.2" + chokidar "^3.5.2" + clean-css "^5.1.5" + commander "^5.1.0" + copy-webpack-plugin "^9.0.1" + core-js "^3.18.0" + css-loader "^5.1.1" + css-minimizer-webpack-plugin "^3.0.2" + cssnano "^5.0.8" + del "^6.0.0" + detect-port "^1.3.0" + escape-html "^1.0.3" + eta "^1.12.3" + express "^4.17.1" + file-loader "^6.2.0" + fs-extra "^10.0.0" + github-slugger "^1.4.0" + globby "^11.0.2" + html-minifier-terser "^6.0.2" + html-tags "^3.1.0" + html-webpack-plugin "^5.4.0" + import-fresh "^3.3.0" + is-root "^2.1.0" + leven "^3.1.0" + lodash "^4.17.20" + mini-css-extract-plugin "^1.6.0" + module-alias "^2.2.2" + nprogress "^0.2.0" + postcss "^8.3.7" + postcss-loader "^6.1.1" + prompts "^2.4.1" + react-dev-utils "^11.0.1" + react-error-overlay "^6.0.9" + react-helmet "^6.1.0" + react-loadable "^5.5.0" + react-loadable-ssr-addon-v5-slorber "^1.0.1" + react-router "^5.2.0" + react-router-config "^5.1.1" + react-router-dom "^5.2.0" + remark-admonitions "^1.2.1" + resolve-pathname "^3.0.0" + rtl-detect "^1.0.4" + semver "^7.3.4" + serve-handler "^6.1.3" + shelljs "^0.8.4" + std-env "^2.2.1" + strip-ansi "^6.0.0" + terser-webpack-plugin "^5.2.4" + tslib "^2.3.1" + update-notifier "^5.1.0" + url-loader "^4.1.1" + wait-on "^6.0.0" + webpack "^5.40.0" + webpack-bundle-analyzer "^4.4.2" + webpack-dev-server "^3.11.2" + webpack-merge "^5.8.0" + webpackbar "^5.0.0-3" + +"@docusaurus/cssnano-preset@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.0.0-beta.8.tgz#0e83ad9e70e64709c23aa8cc565ec43d135e9abc" + integrity sha512-RXApzIEaTsTSpz4YV86DBXaFvXH3J4SNIWba/AFSoPBviODjxIu+7TRRs9eh8vUAB32nVBtcdHmRb25b662szQ== + dependencies: + cssnano-preset-advanced "^5.1.4" + postcss "^8.3.7" + postcss-sort-media-queries "^4.1.0" + +"@docusaurus/mdx-loader@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.0.0-beta.8.tgz#c64a81988975ea5ed969e8a164136a2aaa035da1" + integrity sha512-unVimkaAGgkt+d/QgQPwm8FaRZVB0jew6Q902KSl1Hx0yWI/x5LKWY/y4kCFUBv7rCsuSqyjoZwggD+evw//bg== + dependencies: + "@babel/parser" "^7.12.16" + "@babel/traverse" "^7.12.13" + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" + chalk "^4.1.2" + escape-html "^1.0.3" + file-loader "^6.2.0" + fs-extra "^10.0.0" + github-slugger "^1.4.0" + gray-matter "^4.0.3" + mdast-util-to-string "^2.0.0" + remark-emoji "^2.1.0" + stringify-object "^3.3.0" + unist-util-visit "^2.0.2" + url-loader "^4.1.1" + webpack "^5.40.0" + +"@docusaurus/plugin-content-blog@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.0.0-beta.8.tgz#f7405b04cbde4cff6ea9aaf281f171f147133cd8" + integrity sha512-sUAk3MZrZL7YMp66h+pIy0rOQYFovB8kh9LbDdTXREDyTViCygfkr/6sFPRWpoFzws/kbXoRCPIPcrzcYj+/Pw== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/mdx-loader" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + chalk "^4.1.2" + escape-string-regexp "^4.0.0" + feed "^4.2.2" + fs-extra "^10.0.0" + globby "^11.0.2" + js-yaml "^4.0.0" + loader-utils "^2.0.0" + lodash "^4.17.20" + reading-time "^1.5.0" + remark-admonitions "^1.2.1" + tslib "^2.3.1" + utility-types "^3.10.0" + webpack "^5.40.0" + +"@docusaurus/plugin-content-docs@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.0.0-beta.8.tgz#b248689ea85201a38c21e285819f400820c1c936" + integrity sha512-uE8mI5zQFcwtxAbycxv6G7ALtqKgNwd4URuJhv4VQ2DhR5uta/yd9IK8BPduwrbYLWZuGf2uO3jVsPbgNBZ0RQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/mdx-loader" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + chalk "^4.1.2" + combine-promises "^1.1.0" + escape-string-regexp "^4.0.0" + execa "^5.0.0" + fs-extra "^10.0.0" + globby "^11.0.2" + import-fresh "^3.2.2" + js-yaml "^4.0.0" + loader-utils "^2.0.0" + lodash "^4.17.20" + remark-admonitions "^1.2.1" + shelljs "^0.8.4" + tslib "^2.3.1" + utility-types "^3.10.0" + webpack "^5.40.0" + +"@docusaurus/plugin-content-pages@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.0.0-beta.8.tgz#fdc6687917091ad5f62b332feb6add9c29b6b169" + integrity sha512-NcYKwwBhOR1eH5FZpktaRtBYDsT8vnwR2mAYqS4Oyl7EeyYNKb1ykMnBn5tDktMuRaLRy1flq5u79Nc5oscHIQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/mdx-loader" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + globby "^11.0.2" + lodash "^4.17.20" + remark-admonitions "^1.2.1" + tslib "^2.3.1" + webpack "^5.40.0" + +"@docusaurus/plugin-debug@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.0.0-beta.8.tgz#314ca63af4bea9ea38b62e89580ff471cfcf9955" + integrity sha512-DCsYnVQ+MTEfGTOEsSCpZDG+xADM3dC5K2BfT4kDUB4De1SKH37NoXXJpGaVEtE4gLjRWoDGfDaQdS/LlVqwiQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + fs-extra "^10.0.0" + react-json-view "^1.21.3" + tslib "^2.3.1" + +"@docusaurus/plugin-google-analytics@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.0.0-beta.8.tgz#d9b7298fe33e3ce1e11cd722ce4ac681e356915c" + integrity sha512-kpk9pXPIfE+5CbcJSbwF6Evfy5kX+4Z0Ph/x/M1N+8omH+StDrR+fa1S3I5GK38lb3/N1fWNgsWE7LembE9xYQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + +"@docusaurus/plugin-google-gtag@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.0.0-beta.8.tgz#ba5b22d0656cf295ccd955e39c7fb5439dadddb8" + integrity sha512-1Wa0yMXZgxp85dGuOD44X+fnZtW8ztmOcGBOgLo9Uwhi+OhxOrW4ZOddhEJA6tmCaRuqkaMK7zN1ss2EUc2g7g== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + +"@docusaurus/plugin-sitemap@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.0.0-beta.8.tgz#731d97ff8e495cd66f8ba1c6b1426c61726d46c5" + integrity sha512-oz2Hu1q34kvsgPb6DWM8cpzKmNy02BYtv+2GTrg016V+beGr8PNcHkxzgGtdN+Se5zJqdtRQvOPQtIZOJQntcA== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-common" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + fs-extra "^10.0.0" + sitemap "^7.0.0" + tslib "^2.3.1" + +"@docusaurus/preset-classic@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.0.0-beta.8.tgz#97e42cb0c5b1858cf644febc7ebd61b1a72c9f16" + integrity sha512-tlc+KuMJFmfXYA/FOCbHvMfRWx2SQtJLf6rkBUzRt0Vlym+pI7CG1px3OKON62jaaLm/Vyvn3+47z3yClJRM1A== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/plugin-content-blog" "2.0.0-beta.8" + "@docusaurus/plugin-content-docs" "2.0.0-beta.8" + "@docusaurus/plugin-content-pages" "2.0.0-beta.8" + "@docusaurus/plugin-debug" "2.0.0-beta.8" + "@docusaurus/plugin-google-analytics" "2.0.0-beta.8" + "@docusaurus/plugin-google-gtag" "2.0.0-beta.8" + "@docusaurus/plugin-sitemap" "2.0.0-beta.8" + "@docusaurus/theme-classic" "2.0.0-beta.8" + "@docusaurus/theme-search-algolia" "2.0.0-beta.8" + +"@docusaurus/react-loadable@5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.0.tgz#6d6f0c8fd9a434b62a1ab1f8645ee7bde5a9ec21" + integrity sha512-Ld/kwUE6yATIOTLq3JCsWiTa/drisajwKqBQ2Rw6IcT+sFsKfYek8F2jSH8f68AT73xX97UehduZeCSlnuCBIg== + dependencies: + prop-types "^15.6.2" + +"@docusaurus/theme-classic@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.0.0-beta.8.tgz#5465c0ea739053ba5ea9f5dca61406e8935f00b2" + integrity sha512-lC0PGxACbNiq98WwF1O3T0YblqSK6yo7KcDcrOnPJd0XCV4xMjWZSeeSIneotfs2uvJzmG3GOg7EfQcLvhdyIQ== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/plugin-content-blog" "2.0.0-beta.8" + "@docusaurus/plugin-content-docs" "2.0.0-beta.8" + "@docusaurus/plugin-content-pages" "2.0.0-beta.8" + "@docusaurus/theme-common" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-common" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + "@mdx-js/mdx" "^1.6.21" + "@mdx-js/react" "^1.6.21" + chalk "^4.1.2" + clsx "^1.1.1" + copy-text-to-clipboard "^3.0.1" + fs-extra "^10.0.0" + globby "^11.0.2" + infima "0.2.0-alpha.34" + lodash "^4.17.20" + parse-numeric-range "^1.3.0" + postcss "^8.3.7" + prism-react-renderer "^1.2.1" + prismjs "^1.23.0" + prop-types "^15.7.2" + react-router-dom "^5.2.0" + rtlcss "^3.3.0" + +"@docusaurus/theme-common@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.0.0-beta.8.tgz#eee6f4a08034477458bbc8869e9ebb1fea76fb6f" + integrity sha512-jrlCgFcg0wAfrtzSwU5F8iVdIBmL325d6jupD3N2CirSG6TxAmHDkeAbFyY6ZjaT27XYWXJUwvqvsbbNXAdNzw== + dependencies: + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/plugin-content-blog" "2.0.0-beta.8" + "@docusaurus/plugin-content-docs" "2.0.0-beta.8" + "@docusaurus/plugin-content-pages" "2.0.0-beta.8" + "@docusaurus/types" "2.0.0-beta.8" + clsx "^1.1.1" + fs-extra "^10.0.0" + tslib "^2.3.1" + utility-types "^3.10.0" + +"@docusaurus/theme-search-algolia@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.0.0-beta.8.tgz#9747f6975719152ac18674c526a90930ef9303fb" + integrity sha512-ryT57Wipems0GbB0WxdrTUJ4q/1DM6xoqJlpGGnTy52FEZi3ZoCp+1yxaBLbKKYevGl1nEF3S0kp1o13UiqKTw== + dependencies: + "@docsearch/react" "^3.0.0-alpha.39" + "@docusaurus/core" "2.0.0-beta.8" + "@docusaurus/theme-common" "2.0.0-beta.8" + "@docusaurus/utils" "2.0.0-beta.8" + "@docusaurus/utils-validation" "2.0.0-beta.8" + algoliasearch "^4.10.5" + algoliasearch-helper "^3.5.5" + clsx "^1.1.1" + eta "^1.12.3" + lodash "^4.17.20" + +"@docusaurus/types@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.0.0-beta.8.tgz#0dd7e51ca403c9567eb18d985bb65c975ce15cbc" + integrity sha512-wEzyQvku2zNNp3ChPk1x5s7SvlFygTyuqL9dpwvzCsJhxqZ0JH+whellh2YtDQQO617npOM8l6MC1Yd6ePws2Q== + dependencies: + commander "^5.1.0" + joi "^17.4.2" + querystring "0.2.0" + utility-types "^3.10.0" + webpack "^5.40.0" + webpack-merge "^5.8.0" + +"@docusaurus/utils-common@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.0.0-beta.8.tgz#962534413af2f95d8562b46f077be3a6a49fee61" + integrity sha512-SWnXd+VHN+YWKJGdaPHLmREaNMKEFQmAN12xA/FufXFDvVZJOA2YShLEAjSJDQTKt9hfGys3JCYF1PBgosB0sA== + dependencies: + "@docusaurus/types" "2.0.0-beta.8" + tslib "^2.3.1" + +"@docusaurus/utils-validation@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.0.0-beta.8.tgz#a2093f8e20c79581bc41d6156e4f3a8e3ce95a9a" + integrity sha512-zcoJw9Bo/WkRLJhD53ck0rA68cnswc9TB84F/hOm92X4QkhjCUtb5XlMUtTtvO9ScnlgsFiQYaySrFRAM+fr5w== + dependencies: + "@docusaurus/utils" "2.0.0-beta.8" + chalk "^4.1.2" + joi "^17.4.2" + tslib "^2.3.1" + +"@docusaurus/utils@2.0.0-beta.8": + version "2.0.0-beta.8" + resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.0.0-beta.8.tgz#f6754c8e767cdfcca324eb8e1ac1ceb455d10deb" + integrity sha512-PMdPg8ft/zdAqhuDvMLzDlwXEp01qAh+eOXciKElDrh1zuQM/Hwjg0G3sKiwKInbpHJcz6lbTJCpEjmvMGlXpg== + dependencies: + "@docusaurus/types" "2.0.0-beta.8" + "@mdx-js/runtime" "^1.6.22" + "@types/github-slugger" "^1.3.0" + chalk "^4.1.2" + escape-string-regexp "^4.0.0" + fs-extra "^10.0.0" + globby "^11.0.4" + gray-matter "^4.0.3" + lodash "^4.17.20" + micromatch "^4.0.4" + remark-mdx-remove-exports "^1.6.22" + remark-mdx-remove-imports "^1.6.22" + resolve-pathname "^3.0.0" + tslib "^2.3.1" + +"@hapi/hoek@^9.0.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" + integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@mdx-js/mdx@1.6.22", "@mdx-js/mdx@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-1.6.22.tgz#8a723157bf90e78f17dc0f27995398e6c731f1ba" + integrity sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA== + dependencies: + "@babel/core" "7.12.9" + "@babel/plugin-syntax-jsx" "7.12.1" + "@babel/plugin-syntax-object-rest-spread" "7.8.3" + "@mdx-js/util" "1.6.22" + babel-plugin-apply-mdx-type-prop "1.6.22" + babel-plugin-extract-import-names "1.6.22" + camelcase-css "2.0.1" + detab "2.0.4" + hast-util-raw "6.0.1" + lodash.uniq "4.5.0" + mdast-util-to-hast "10.0.1" + remark-footnotes "2.0.0" + remark-mdx "1.6.22" + remark-parse "8.0.3" + remark-squeeze-paragraphs "4.0.0" + style-to-object "0.3.0" + unified "9.2.0" + unist-builder "2.0.3" + unist-util-visit "2.0.3" + +"@mdx-js/react@1.6.22", "@mdx-js/react@^1.6.21": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" + integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== + +"@mdx-js/runtime@^1.6.22": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/runtime/-/runtime-1.6.22.tgz#3edd388bf68a519ffa1aaf9c446b548165102345" + integrity sha512-p17spaO2+55VLCuxXA3LVHC4phRx60NR2XMdZ+qgVU1lKvEX4y88dmFNOzGDCPLJ03IZyKrJ/rPWWRiBrd9JrQ== + dependencies: + "@mdx-js/mdx" "1.6.22" + "@mdx-js/react" "1.6.22" + buble-jsx-only "^0.19.8" + +"@mdx-js/util@1.6.22": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.6.22.tgz#219dfd89ae5b97a8801f015323ffa4b62f45718b" + integrity sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" + integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== + +"@sideway/address@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" + integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@slorber/static-site-generator-webpack-plugin@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@slorber/static-site-generator-webpack-plugin/-/static-site-generator-webpack-plugin-4.0.1.tgz#0c8852146441aaa683693deaa5aee2f991d94841" + integrity sha512-PSv4RIVO1Y3kvHxjvqeVisk3E9XFoO04uwYBDWe217MFqKspplYswTuKLiJu0aLORQWzuQjfVsSlLPojwfYsLw== + dependencies: + bluebird "^3.7.1" + cheerio "^0.22.0" + eval "^0.1.4" + url "^0.11.0" + webpack-sources "^1.4.3" + +"@svgr/babel-plugin-add-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" + integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== + +"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" + integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== + +"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" + integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== + +"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" + integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== + +"@svgr/babel-plugin-svg-dynamic-title@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" + integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== + +"@svgr/babel-plugin-svg-em-dimensions@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" + integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== + +"@svgr/babel-plugin-transform-react-native-svg@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" + integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== + +"@svgr/babel-plugin-transform-svg-component@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a" + integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ== + +"@svgr/babel-preset@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327" + integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig== + dependencies: + "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0" + "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1" + "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1" + "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0" + "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0" + "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" + "@svgr/babel-plugin-transform-svg-component" "^5.5.0" + +"@svgr/core@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579" + integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ== + dependencies: + "@svgr/plugin-jsx" "^5.5.0" + camelcase "^6.2.0" + cosmiconfig "^7.0.0" + +"@svgr/hast-util-to-babel-ast@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461" + integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ== + dependencies: + "@babel/types" "^7.12.6" + +"@svgr/plugin-jsx@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000" + integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA== + dependencies: + "@babel/core" "^7.12.3" + "@svgr/babel-preset" "^5.5.0" + "@svgr/hast-util-to-babel-ast" "^5.5.0" + svg-parser "^2.0.2" + +"@svgr/plugin-svgo@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246" + integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ== + dependencies: + cosmiconfig "^7.0.0" + deepmerge "^4.2.2" + svgo "^1.2.2" + +"@svgr/webpack@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640" + integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g== + dependencies: + "@babel/core" "^7.12.3" + "@babel/plugin-transform-react-constant-elements" "^7.12.1" + "@babel/preset-env" "^7.12.1" + "@babel/preset-react" "^7.12.5" + "@svgr/core" "^5.5.0" + "@svgr/plugin-jsx" "^5.5.0" + "@svgr/plugin-svgo" "^5.5.0" + loader-utils "^2.0.0" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/eslint-scope@^3.7.0": + version "3.7.3" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" + integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.0.tgz#95712d5b32fd99a0d9493c31c6197ea7471c3ba6" + integrity sha512-JUYa/5JwoqikCy7O7jKtuNe9Z4ZZt615G+1EKfaDGSNEpzaA2OwbV/G1v08Oa7fd1XzlFoSCvt9ePl9/6FyAug== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + +"@types/github-slugger@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@types/github-slugger/-/github-slugger-1.3.0.tgz#16ab393b30d8ae2a111ac748a015ac05a1fc5524" + integrity sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g== + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/hast@^2.0.0": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" + integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + dependencies: + "@types/unist" "*" + +"@types/html-minifier-terser@^6.0.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" + integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg== + +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*", "@types/node@^17.0.5": + version "17.0.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.10.tgz#616f16e9d3a2a3d618136b1be244315d95bd7cab" + integrity sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/parse5@^5.0.0": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109" + integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== + +"@types/q@^1.5.1": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" + integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + +"@types/sax@^1.2.1": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.4.tgz#8221affa7f4f3cb21abd22f244cfabfa63e6a69e" + integrity sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw== + dependencies: + "@types/node" "*" + +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + +"@webassemblyjs/ast@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" + integrity sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + +"@webassemblyjs/floating-point-hex-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz#f6c61a705f0fd7a6aecaa4e8198f23d9dc179e4f" + integrity sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ== + +"@webassemblyjs/helper-api-error@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz#1a63192d8788e5c012800ba6a7a46c705288fd16" + integrity sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg== + +"@webassemblyjs/helper-buffer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz#832a900eb444884cde9a7cad467f81500f5e5ab5" + integrity sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA== + +"@webassemblyjs/helper-numbers@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz#64d81da219fbbba1e3bd1bfc74f6e8c4e10a62ae" + integrity sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz#f328241e41e7b199d0b20c18e88429c4433295e1" + integrity sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q== + +"@webassemblyjs/helper-wasm-section@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz#21ee065a7b635f319e738f0dd73bfbda281c097a" + integrity sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + +"@webassemblyjs/ieee754@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz#963929e9bbd05709e7e12243a099180812992614" + integrity sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.1.tgz#ce814b45574e93d76bae1fb2644ab9cdd9527aa5" + integrity sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.1.tgz#d1f8b764369e7c6e6bae350e854dec9a59f0a3ff" + integrity sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ== + +"@webassemblyjs/wasm-edit@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz#ad206ebf4bf95a058ce9880a8c092c5dec8193d6" + integrity sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/helper-wasm-section" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-opt" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + "@webassemblyjs/wast-printer" "1.11.1" + +"@webassemblyjs/wasm-gen@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz#86c5ea304849759b7d88c47a32f4f039ae3c8f76" + integrity sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wasm-opt@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz#657b4c2202f4cf3b345f8a4c6461c8c2418985f2" + integrity sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-buffer" "1.11.1" + "@webassemblyjs/wasm-gen" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + +"@webassemblyjs/wasm-parser@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz#86ca734534f417e9bd3c67c7a1c75d8be41fb199" + integrity sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/helper-api-error" "1.11.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.1" + "@webassemblyjs/ieee754" "1.11.1" + "@webassemblyjs/leb128" "1.11.1" + "@webassemblyjs/utf8" "1.11.1" + +"@webassemblyjs/wast-printer@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz#d0c73beda8eec5426f10ae8ef55cee5e7084c2f0" + integrity sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg== + dependencies: + "@webassemblyjs/ast" "1.11.1" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-dynamic-import@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" + integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== + +acorn-import-assertions@^1.7.6: + version "1.8.0" + resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" + integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== + +acorn-jsx@^5.0.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^6.1.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +acorn@^8.0.4, acorn@^8.4.1: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +address@1.1.2, address@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.1.0, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.1.0, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.8.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.9.0.tgz#738019146638824dea25edcf299dcba1b0e7eb18" + integrity sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +algoliasearch-helper@^3.5.5: + version "3.7.0" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.7.0.tgz#c0a0493df84d850360f664ad7a9d4fc78a94fd78" + integrity sha512-XJ3QfERBLfeVCyTVx80gon7r3/rgm/CE8Ha1H7cbablRe/X7SfYQ14g/eO+MhjVKIQp+gy9oC6G5ilmLwS1k6w== + dependencies: + "@algolia/events" "^4.0.1" + +algoliasearch@^4.0.0, algoliasearch@^4.10.5: + version "4.12.0" + resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.12.0.tgz#30f2619b6e3a5b79b6aa0f18ab66fbce88240aba" + integrity sha512-fZOMMm+F3Bi5M/MoFIz7hiuyCitJza0Hu+r8Wzz4LIQClC6YGMRq7kT6NNU1fSSoFDSeJIwMfedbbi5G9dJoVQ== + dependencies: + "@algolia/cache-browser-local-storage" "4.12.0" + "@algolia/cache-common" "4.12.0" + "@algolia/cache-in-memory" "4.12.0" + "@algolia/client-account" "4.12.0" + "@algolia/client-analytics" "4.12.0" + "@algolia/client-common" "4.12.0" + "@algolia/client-personalization" "4.12.0" + "@algolia/client-search" "4.12.0" + "@algolia/logger-common" "4.12.0" + "@algolia/logger-console" "4.12.0" + "@algolia/requester-browser-xhr" "4.12.0" + "@algolia/requester-common" "4.12.0" + "@algolia/requester-node-http" "4.12.0" + "@algolia/transporter" "4.12.0" + +alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-align@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-html-community@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" + integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^10.3.5, autoprefixer@^10.3.7: + version "10.4.2" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" + integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== + 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" + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +babel-loader@^8.2.2: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.3.tgz#8986b40f1a64cacfcb4b8429320085ef68b1342d" + integrity sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^1.4.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-apply-mdx-type-prop@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz#d216e8fd0de91de3f1478ef3231e05446bc8705b" + integrity sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ== + dependencies: + "@babel/helper-plugin-utils" "7.10.4" + "@mdx-js/util" "1.6.22" + +babel-plugin-dynamic-import-node@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-extract-import-names@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" + integrity sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ== + dependencies: + "@babel/helper-plugin-utils" "7.10.4" + +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.1" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.1.tgz#d66183bf10976ea677f4149a7fcc4d8df43d4060" + integrity sha512-TihqEe4sQcb/QcPJvxe94/9RZuLQuF1+To4WqQcRvc+3J3gLCPIPgDKzGLG6zmQLfH3nn25heRuDNkS2KR4I8A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.20.0" + +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base16@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70" + integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bluebird@^3.7.1: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +body-parser@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +boxen@^5.0.0, boxen@^5.0.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@4.14.2: + version "4.14.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.2.tgz#1b3cec458a1ba87588cc5e9be62f19b6d48813ce" + integrity sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw== + dependencies: + caniuse-lite "^1.0.30001125" + electron-to-chromium "^1.3.564" + escalade "^3.0.2" + node-releases "^1.1.61" + +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + 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" + +buble-jsx-only@^0.19.8: + version "0.19.8" + resolved "https://registry.yarnpkg.com/buble-jsx-only/-/buble-jsx-only-0.19.8.tgz#6e3524aa0f1c523de32496ac9aceb9cc2b493867" + integrity sha512-7AW19pf7PrKFnGTEDzs6u9+JZqQwM1VnLS19OlqYDhXomtFFknnoQJAPHeg84RMFWAvOhYrG7harizJNwUKJsA== + dependencies: + acorn "^6.1.1" + acorn-dynamic-import "^4.0.0" + acorn-jsx "^5.0.1" + chalk "^2.4.2" + magic-string "^0.25.3" + minimist "^1.2.0" + regexpu-core "^4.5.4" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase-css@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297: + version "1.0.30001301" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz#ebc9086026534cab0dab99425d9c3b4425e5f450" + integrity sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA== + +ccount@^1.0.0, ccount@^1.0.3: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" + integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + +cheerio@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + 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" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +ci-info@^3.1.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@^5.1.5, clean-css@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.2.2.tgz#d3a7c6ee2511011e051719838bdcf8314dc4548d" + integrity sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-boxes@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" + integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== + +combine-promises@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/combine-promises/-/combine-promises-1.1.0.tgz#72db90743c0ca7aab7d0d8d2052fd7b0f674de71" + integrity sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg== + +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commander@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +consola@^2.15.3: + version "2.15.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550" + integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw== + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-text-to-clipboard@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz#8cbf8f90e0a47f12e4a24743736265d157bce69c" + integrity sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q== + +copy-webpack-plugin@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz#2d2c460c4c4695ec0a58afb2801a1205256c4e6b" + integrity sha512-rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA== + dependencies: + fast-glob "^3.2.7" + glob-parent "^6.0.1" + globby "^11.0.3" + normalize-path "^3.0.0" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + +core-js-compat@^3.20.0, core-js-compat@^3.20.2: + version "3.20.3" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.20.3.tgz#d71f85f94eb5e4bea3407412e549daa083d23bd6" + integrity sha512-c8M5h0IkNZ+I92QhIpuSijOxGAcj3lgpsWdkCqmUTZNwidujF4r3pi6x1DCN+Vcs5qTS2XWWMfWSuCqyupX8gw== + dependencies: + browserslist "^4.19.1" + semver "7.0.0" + +core-js-pure@^3.20.2: + version "3.20.3" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.20.3.tgz#6cc4f36da06c61d95254efc54024fe4797fd5d02" + integrity sha512-Q2H6tQ5MtPtcC7f3HxJ48i4Q7T9ybPKgvWyuH7JXIoNa2pm0KuBnycsET/qw1SLLZYfbsbrZQNMeIOClb+6WIA== + +core-js@^3.18.0: + version "3.20.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.20.3.tgz#c710d0a676e684522f3db4ee84e5e18a9d11d69a" + integrity sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + 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" + +cross-fetch@^3.0.4: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + +cross-spawn@7.0.3, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-declaration-sorter@^6.0.3: + version "6.1.4" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4" + integrity sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw== + dependencies: + timsort "^0.3.0" + +css-loader@^5.1.1: + version "5.2.7" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" + integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== + dependencies: + icss-utils "^5.1.0" + loader-utils "^2.0.0" + postcss "^8.2.15" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + postcss-value-parser "^4.1.0" + schema-utils "^3.0.0" + semver "^7.3.5" + +css-minimizer-webpack-plugin@^3.0.2: + version "3.4.1" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f" + integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q== + dependencies: + cssnano "^5.0.6" + jest-worker "^27.0.2" + postcss "^8.3.5" + schema-utils "^4.0.0" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@^4.1.3: + version "4.2.1" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" + integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== + dependencies: + boolbase "^1.0.0" + css-what "^5.1.0" + domhandler "^4.3.0" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +css-what@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-advanced@^5.1.4: + version "5.1.10" + resolved "https://registry.yarnpkg.com/cssnano-preset-advanced/-/cssnano-preset-advanced-5.1.10.tgz#0540a8902350418314f4f0d9ccfc45028fb62e25" + integrity sha512-6Rc7jbnIBpEUyuTLDBLuvsZE64NY9NRNe4HjOVb0zT0ixiGatKAmUNtTIwLP2F/vE5VJsdlVcixX9y2kb7O+zQ== + dependencies: + autoprefixer "^10.3.7" + cssnano-preset-default "^5.1.10" + postcss-discard-unused "^5.0.1" + postcss-merge-idents "^5.0.2" + postcss-reduce-idents "^5.0.1" + postcss-zindex "^5.0.1" + +cssnano-preset-default@^5.1.10: + version "5.1.10" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.10.tgz#9350765fdf3c49bf78fac7673354fa58fa95daa4" + integrity sha512-BcpSzUVygHMOnp9uG5rfPzTOCb0GAHQkqtUQx8j1oMNF9A1Q8hziOOhiM4bdICpmrBIU85BE64RD5XGYsVQZNA== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^3.0.0" + postcss-calc "^8.2.0" + postcss-colormin "^5.2.3" + postcss-convert-values "^5.0.2" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.2" + postcss-merge-longhand "^5.0.4" + postcss-merge-rules "^5.0.4" + postcss-minify-font-values "^5.0.2" + postcss-minify-gradients "^5.0.4" + postcss-minify-params "^5.0.3" + postcss-minify-selectors "^5.1.1" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.2" + postcss-normalize-positions "^5.0.2" + postcss-normalize-repeat-style "^5.0.2" + postcss-normalize-string "^5.0.2" + postcss-normalize-timing-functions "^5.0.2" + postcss-normalize-unicode "^5.0.2" + postcss-normalize-url "^5.0.4" + postcss-normalize-whitespace "^5.0.2" + postcss-ordered-values "^5.0.3" + postcss-reduce-initial "^5.0.2" + postcss-reduce-transforms "^5.0.2" + postcss-svgo "^5.0.3" + postcss-unique-selectors "^5.0.2" + +cssnano-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.0.0.tgz#c0b9fcd6e4f05c5155b07e9ab11bf94b97163057" + integrity sha512-Pzs7/BZ6OgT+tXXuF12DKR8SmSbzUeVYCtMBbS8lI0uAm3mrYmkyqCXXPsQESI6kmLfEVBppbdVY/el3hg3nAA== + +cssnano@^5.0.6, cssnano@^5.0.8: + version "5.0.15" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.15.tgz#8779eaf60e3665e6a12687c814d375cc9f78db76" + integrity sha512-ppZsS7oPpi2sfiyV5+i+NbB/3GtQ+ab2Vs1azrZaXWujUSN4o+WdTxlCZIMcT9yLW3VO/5yX3vpyDaQ1nIn8CQ== + dependencies: + cssnano-preset-default "^5.1.10" + lilconfig "^2.0.3" + yaml "^1.10.2" + +csso@^4.0.2, csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.1, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +del@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" + integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detab@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detab/-/detab-2.0.4.tgz#b927892069aff405fbb9a186fe97a44a92a94b43" + integrity sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g== + dependencies: + repeat-string "^1.5.4" + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +detect-port-alt@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +detect-port@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.3.0.tgz#d9c40e9accadd4df5cac6a782aefd014d573d1f1" + integrity sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-converter@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" + integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA== + dependencies: + utila "~0.4" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + dependencies: + domelementtype "^2.2.0" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^2.5.2, domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.1, duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.564, electron-to-chromium@^1.4.17: + version "1.4.49" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.49.tgz#5b6a3dc032590beef4be485a4b0b3fe7d0e3dfd7" + integrity sha512-k/0t1TRfonHIp8TJKfjBu2cKj8MqYTiEpOhci+q7CVEE5xnCQnx1pTa+V8b/sdhe4S3PR4p4iceEQWhGrKQORQ== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +emoticon@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-3.2.0.tgz#c008ca7d7620fac742fe1bf4af8ff8fed154ae7f" + integrity sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz#6d552d465cce0423f5b3d718511ea53826a7b2f0" + integrity sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +errno@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.2, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-module-lexer@^0.9.0: + version "0.9.3" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19" + integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ== + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.0.2, escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-html@^1.0.3, escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eta@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/eta/-/eta-1.12.3.tgz#2982d08adfbef39f9fa50e2fbd42d7337e7338b1" + integrity sha512-qHixwbDLtekO/d51Yr4glcaUJCIjGVJyTzuqV4GPlgZo1YpgOKG+avQynErZIYrfM6JIJdtiG2Kox8tbb+DoGg== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eval@^0.1.4: + version "0.1.6" + resolved "https://registry.yarnpkg.com/eval/-/eval-0.1.6.tgz#9620d7d8c85515e97e6b47c5814f46ae381cb3cc" + integrity sha512-o0XUw+5OGkXw4pJZzQoXUk+H87DHuC+7ZE//oSrRGtatTmr12oTnLfg6QOq9DyTt0c/p4TwzgmkKrBzWTSizyQ== + dependencies: + require-like ">= 0.1.1" + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + dependencies: + original "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.17.1: + version "4.17.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" + integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.6" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1, fast-glob@^3.2.7, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + 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" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fbemitter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3" + integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw== + dependencies: + fbjs "^3.0.0" + +fbjs-css-vars@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== + +fbjs@^3.0.0, fbjs@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.2.tgz#dfae08a85c66a58372993ce2caf30863f569ff94" + integrity sha512-qv+boqYndjElAJHNN3NoM8XuwQZ1j2m3kEvTgdle8IDjr6oUbkEpvABWtj/rQl3vq4ew7dnElBxL4YJAwTVqQQ== + dependencies: + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.30" + +feed@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e" + integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ== + dependencies: + xml-js "^1.6.11" + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filesize@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" + integrity sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@4.1.0, find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flux@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7" + integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw== + dependencies: + fbemitter "^3.0.0" + fbjs "^3.0.1" + +follow-redirects@^1.0.0, follow-redirects@^1.14.0: + version "1.14.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fork-ts-checker-webpack-plugin@4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" + integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== + dependencies: + "@babel/code-frame" "^7.5.5" + chalk "^2.4.1" + micromatch "^3.1.10" + minimatch "^3.0.4" + semver "^5.6.0" + tapable "^1.0.0" + worker-rpc "^0.1.0" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fraction.js@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" + integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-own-enumerable-property-symbols@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" + integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== + +get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +github-slugger@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" + integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.3: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +gray-matter@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + +gzip-size@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hast-to-hyperscript@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz#9b67fd188e4c81e8ad66f803855334173920218d" + integrity sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA== + dependencies: + "@types/unist" "^2.0.3" + comma-separated-tokens "^1.0.0" + property-information "^5.3.0" + space-separated-tokens "^1.0.0" + style-to-object "^0.3.0" + unist-util-is "^4.0.0" + web-namespaces "^1.0.0" + +hast-util-from-parse5@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-5.0.3.tgz#3089dc0ee2ccf6ec8bc416919b51a54a589e097c" + integrity sha512-gOc8UB99F6eWVWFtM9jUikjN7QkWxB3nY0df5Z0Zq1/Nkwl5V4hAAsl0tmwlgWl/1shlTF8DnNYLO8X6wRV9pA== + dependencies: + ccount "^1.0.3" + hastscript "^5.0.0" + property-information "^5.0.0" + web-namespaces "^1.1.2" + xtend "^4.0.1" + +hast-util-from-parse5@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a" + integrity sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA== + dependencies: + "@types/parse5" "^5.0.0" + hastscript "^6.0.0" + property-information "^5.0.0" + vfile "^4.0.0" + vfile-location "^3.2.0" + web-namespaces "^1.0.0" + +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + +hast-util-raw@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-6.0.1.tgz#973b15930b7529a7b66984c98148b46526885977" + integrity sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig== + dependencies: + "@types/hast" "^2.0.0" + hast-util-from-parse5 "^6.0.0" + hast-util-to-parse5 "^6.0.0" + html-void-elements "^1.0.0" + parse5 "^6.0.0" + unist-util-position "^3.0.0" + vfile "^4.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.0" + zwitch "^1.0.0" + +hast-util-to-parse5@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz#1ec44650b631d72952066cea9b1445df699f8479" + integrity sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ== + dependencies: + hast-to-hyperscript "^9.0.0" + property-information "^5.0.0" + web-namespaces "^1.0.0" + xtend "^4.0.0" + zwitch "^1.0.0" + +hastscript@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-5.1.2.tgz#bde2c2e56d04c62dd24e8c5df288d050a355fb8a" + integrity sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ== + dependencies: + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + +hoist-non-react-statics@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +html-minifier-terser@^6.0.2: + version "6.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab" + integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw== + dependencies: + camel-case "^4.1.2" + clean-css "^5.2.2" + commander "^8.3.0" + he "^1.2.0" + param-case "^3.0.4" + relateurl "^0.2.7" + terser "^5.10.0" + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +html-void-elements@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-1.0.5.tgz#ce9159494e86d95e45795b166c2021c2cfca4483" + integrity sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w== + +html-webpack-plugin@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" + integrity sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw== + dependencies: + "@types/html-minifier-terser" "^6.0.0" + html-minifier-terser "^6.0.2" + lodash "^4.17.21" + pretty-error "^4.0.0" + tapable "^2.0.0" + +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +htmlparser2@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" + integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.5.2" + entities "^2.0.0" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5" + integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA== + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ignore@^5.1.4, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +immer@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" + integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== + +import-fresh@^3.2.1, import-fresh@^3.2.2, import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +infima@0.2.0-alpha.34: + version "0.2.0-alpha.34" + resolved "https://registry.yarnpkg.com/infima/-/infima-0.2.0-alpha.34.tgz#14a900d79a4de2013e025ac95749a4592f16ef6e" + integrity sha512-Na6A2Tl56i1p9dzu7VOAT1Kmu3f5buz63Wvd+D9ZZWL6siQ47L7wkEZUICVKFgc5gERFZVZ/PoPB57Kl++h37Q== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +ini@^1.3.5, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-alphabetical@1.0.4, is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-installed-globally@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-npm@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" + integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0, is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-root@2.1.0, is-root@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +jest-worker@^27.0.2, jest-worker@^27.4.1: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" + integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +joi@^17.4.0, joi@^17.4.2: + version "17.5.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" + integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json3@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +klona@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc" + integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ== + +latest-version@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lilconfig@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" + integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +loader-runner@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" + integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== + +loader-utils@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.curry@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170" + integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.flow@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" + integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.4.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.uniq@4.5.0, lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.8.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114" + integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.25.3: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + dependencies: + sourcemap-codec "^1.4.4" + +make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + +mdast-squeeze-paragraphs@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz#7c4c114679c3bee27ef10b58e2e015be79f1ef97" + integrity sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ== + dependencies: + unist-util-remove "^2.0.0" + +mdast-util-definitions@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz#c5c1a84db799173b4dcf7643cda999e440c24db2" + integrity sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ== + dependencies: + unist-util-visit "^2.0.0" + +mdast-util-to-hast@10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz#0cfc82089494c52d46eb0e3edb7a4eb2aea021eb" + integrity sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + mdast-util-definitions "^4.0.0" + mdurl "^1.0.0" + unist-builder "^2.0.0" + unist-util-generated "^1.0.0" + unist-util-position "^3.0.0" + unist-util-visit "^2.0.0" + +mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdurl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +microevent.ts@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" + integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.51.0, "mime-db@>= 1.43.0 < 2": + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + +mini-css-extract-plugin@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz#83172b4fd812f8fc4a09d6f6d16f924f53990ca8" + integrity sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +module-alias@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" + integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== + +mrmime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" + integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + +nanoid@^3.1.30: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-emoji@^1.10.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== + dependencies: + lodash "^4.17.21" + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + +node-releases@^1.1.61: + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha1-y480xTIT2JVyP8urkH6UIq28r7E= + +nth-check@^1.0.2, nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +nth-check@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.0.0" + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^7.0.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +opener@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + 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" + +parse-numeric-range@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3" + integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ== + +parse5@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@1.0.2, path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-up@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +portfinder@^1.0.26: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-calc@^8.2.0: + version "8.2.2" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.2.tgz#9706e7399e8ec8b61a47830dcf1f21391af23373" + integrity sha512-B5R0UeB4zLJvxNt1FVCaDZULdzsKLPc6FhjFJ+xwFiq7VG4i9cuaJLxVjNtExNK8ocm3n2o4unXXLiVX1SCqxA== + dependencies: + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-colormin@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.3.tgz#da7fb80e81ad80d2867ea9e38672a892add5df15" + integrity sha512-dra4xoAjub2wha6RUXAgadHEn2lGxbj8drhFcIGLOMn914Eu7DkPUurugDXgstwttCYkJtZ/+PkWRWdp3UHRIA== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" + integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-discard-comments@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" + integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg== + +postcss-discard-duplicates@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" + integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA== + +postcss-discard-empty@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" + integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw== + +postcss-discard-overridden@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.2.tgz#e6f51d83e66feffcf05ed94c4ad20b814d0aab5f" + integrity sha512-+56BLP6NSSUuWUXjRgAQuho1p5xs/hU5Sw7+xt9S3JSg+7R6+WMGnJW7Hre/6tTuZ2xiXMB42ObkiZJ2hy/Pew== + +postcss-discard-unused@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-5.0.1.tgz#63e35a74a154912f93d4e75a1e6ff3cc146f934b" + integrity sha512-tD6xR/xyZTwfhKYRw0ylfCY8wbfhrjpKAMnDKRTLMy2fNW5hl0hoV6ap5vo2JdCkuHkP3CHw72beO4Y8pzFdww== + dependencies: + postcss-selector-parser "^6.0.5" + +postcss-loader@^6.1.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef" + integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q== + dependencies: + cosmiconfig "^7.0.0" + klona "^2.0.5" + semver "^7.3.5" + +postcss-merge-idents@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-5.0.2.tgz#d67d9505857a9546c3f7a305386e4147497322d6" + integrity sha512-V8IlmvQez+/mB06touksO3lUKtzL3ZKfBxfXFK2q136TOyOLXBuoI8kQwZsIOFWUfA8gk/XpFtmMsqURqYPk6Q== + dependencies: + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-merge-longhand@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + +postcss-merge-rules@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.4.tgz#a50640fd832380f322bd2861a9b33fbde4219f9b" + integrity sha512-yOj7bW3NxlQxaERBB0lEY1sH5y+RzevjbdH4DBJurjKERNpknRByFNdNe+V72i5pIZL12woM9uGdS5xbSB+kDQ== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^3.0.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.2.tgz#4603e956d85cd0719156e2b3eb68e3cd2f917092" + integrity sha512-R6MJZryq28Cw0AmnyhXrM7naqJZZLoa1paBltIzh2wM7yb4D45TLur+eubTQ4jCmZU9SGeZdWsc5KcSoqTMeTg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.4.tgz#f13146950513f5a201015306914e3c76d10b591d" + integrity sha512-RVwZA7NC4R4J76u8X0Q0j+J7ItKUWAeBUJ8oEEZWmtv3Xoh19uNJaJwzNpsydQjk6PkuhRrK+YwwMf+c+68EYg== + dependencies: + colord "^2.9.1" + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.3.tgz#9f933d37098ef1dcf007e159a47bb2c1cf06989d" + integrity sha512-NY92FUikE+wralaiVexFd5gwb7oJTIDhgTNeIw89i1Ymsgt4RWiPXfz3bg7hDy4NL6gepcThJwOYNtZO/eNi7Q== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.6" + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.1.tgz#20ae03b411f7fb397451e3d7d85b989f944b871c" + integrity sha512-TOzqOPXt91O2luJInaVPiivh90a2SIK5Nf1Ea7yEIM/5w+XA5BGrZGUSW8aEx9pJ/oNj7ZJBhjvigSiBV+bC1Q== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-normalize-charset@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" + integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg== + +postcss-normalize-display-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.2.tgz#8b5273c6c7d0a445e6ef226b8a5bb3204a55fb99" + integrity sha512-RxXoJPUR0shSjkMMzgEZDjGPrgXUVYyWA/YwQRicb48H15OClPuaDR7tYokLAlGZ2tCSENEN5WxjgxSD5m4cUw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.2.tgz#799fa494b352a5da183be8f050024af6d92fa29c" + integrity sha512-tqghWFVDp2btqFg1gYob1etPNxXLNh3uVeWgZE2AQGh6b2F8AK2Gj36v5Vhyh+APwIzNjmt6jwZ9pTBP+/OM8g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.2.tgz#fd9bddba3e6fd5f5d95c18dfb42a09ecd563adea" + integrity sha512-/rIZn8X9bBzC7KvY4iKUhXUGW3MmbXwfPF23jC9wT9xTi7kAvgj8sEgwxjixBmoL6MVa4WOgxNz2hAR6wTK8tw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.2.tgz#1b2bbf91526f61266f28abf7f773e4136b2c4bd2" + integrity sha512-zaI1yzwL+a/FkIzUWMQoH25YwCYxi917J4pYm1nRXtdgiCdnlTkx5eRzqWEC64HtRa06WCJ9TIutpb6GmW4gFw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.2.tgz#db4f4f49721f47667afd1fdc5edb032f8d9cdb2e" + integrity sha512-Ao0PP6MoYsRU1LxeVUW740ioknvdIUmfr6uAA3xWlQJ9s69/Tupy8qwhuKG3xWfl+KvLMAP9p2WXF9cwuk/7Bg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.2.tgz#c4db89a0116066716b9e9fcb6444ce63178f5ced" + integrity sha512-3y/V+vjZ19HNcTizeqwrbZSUsE69ZMRHfiiyLAJb7C7hJtYmM4Gsbajy7gKagu97E8q5rlS9k8FhojA8cpGhWw== + dependencies: + browserslist "^4.16.6" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz#3b0322c425e31dd275174d0d5db0e466f50810fb" + integrity sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg== + dependencies: + normalize-url "^6.0.1" + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.2.tgz#92c5eaffe5255b5c43fca0baf19227e607c534db" + integrity sha512-CXBx+9fVlzSgbk0IXA/dcZn9lXixnQRndnsPC5ht3HxlQ1bVh77KQDL1GffJx1LTzzfae8ftMulsjYmO2yegxA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-ordered-values@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.3.tgz#d80a8565f2e21efe8a06abacd60629a783bbcf54" + integrity sha512-T9pDS+P9bWeFvqivXd5ACzQmrCmHjv3ZP+djn8E1UZY7iK79pFSm7i3WbKw2VSmFmdbMm8sQ12OPcNpzBo3Z2w== + dependencies: + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-reduce-idents@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-5.0.1.tgz#99b49ce8ee6f9c179447671cc9693e198e877bb7" + integrity sha512-6Rw8iIVFbqtaZExgWK1rpVgP7DPFRPh0DDFZxJ/ADNqPiH10sPCoq5tgo6kLiTyfh9sxjKYjXdc8udLEcPOezg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-reduce-initial@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" + integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.2.tgz#9242758629f9ad4d90312eadbc921259d15bee4d" + integrity sha512-25HeDeFsgiPSUx69jJXZn8I06tMxLQJJNF5h7i9gsUg8iP4KOOJ8EX8fj3seeoLt3SLU2YDD6UPnDYVGUO7DEA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: + version "6.0.9" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" + integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-sort-media-queries@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-sort-media-queries/-/postcss-sort-media-queries-4.2.1.tgz#a99bae69ef1098ee3b64a5fa94d258ec240d0355" + integrity sha512-9VYekQalFZ3sdgcTjXMa0dDjsfBVHXlraYJEMiOJ/2iMmI2JGCMavP16z3kWOaRu8NSaJCTgVpB/IVpH5yT9YQ== + dependencies: + sort-css-media-queries "2.0.4" + +postcss-svgo@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" + integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.7.0" + +postcss-unique-selectors@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" + integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss-zindex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-5.0.1.tgz#c585724beb69d356af8c7e68847b28d6298ece03" + integrity sha512-nwgtJJys+XmmSGoYCcgkf/VczP8Mp/0OfSv3v0+fw0uABY4yxw+eFs0Xp9nAZHIKnS5j+e9ywQ+RD+ONyvl5pA== + +postcss@^8.2.15, postcss@^8.3.11, postcss@^8.3.5, postcss@^8.3.7: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +pretty-error@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6" + integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw== + dependencies: + lodash "^4.17.20" + renderkid "^3.0.0" + +pretty-time@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" + integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA== + +prism-react-renderer@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz#392460acf63540960e5e3caa699d851264e99b89" + integrity sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg== + +prismjs@^1.23.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.26.0.tgz#16881b594828bb6b45296083a8cbab46b0accd47" + integrity sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + +prompts@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prompts@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.5.0, prop-types@^15.6.2, prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +property-information@^5.0.0, property-information@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +pupa@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + +pure-color@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e" + integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4= + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-base16-styling@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" + integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw= + dependencies: + base16 "^1.0.0" + lodash.curry "^4.0.1" + lodash.flow "^3.3.0" + pure-color "^1.2.0" + +react-dev-utils@^11.0.1: + version "11.0.4" + resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a" + integrity sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A== + dependencies: + "@babel/code-frame" "7.10.4" + address "1.1.2" + browserslist "4.14.2" + chalk "2.4.2" + cross-spawn "7.0.3" + detect-port-alt "1.1.6" + escape-string-regexp "2.0.0" + filesize "6.1.0" + find-up "4.1.0" + fork-ts-checker-webpack-plugin "4.1.6" + global-modules "2.0.0" + globby "11.0.1" + gzip-size "5.1.1" + immer "8.0.1" + is-root "2.1.0" + loader-utils "2.0.0" + open "^7.0.2" + pkg-up "3.1.0" + prompts "2.4.0" + react-error-overlay "^6.0.9" + recursive-readdir "2.2.2" + shell-quote "1.7.2" + strip-ansi "6.0.0" + text-table "0.2.0" + +react-dom@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + +react-error-overlay@^6.0.9: + version "6.0.10" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" + integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA== + +react-fast-compare@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" + integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== + +react-helmet@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726" + integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw== + dependencies: + object-assign "^4.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.1.1" + react-side-effect "^2.1.0" + +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-json-view@^1.21.3: + version "1.21.3" + resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475" + integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw== + dependencies: + flux "^4.0.1" + react-base16-styling "^0.6.0" + react-lifecycles-compat "^3.0.4" + react-textarea-autosize "^8.3.2" + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-loadable-ssr-addon-v5-slorber@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz#2cdc91e8a744ffdf9e3556caabeb6e4278689883" + integrity sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A== + dependencies: + "@babel/runtime" "^7.10.3" + +react-loadable@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/react-loadable/-/react-loadable-5.5.0.tgz#582251679d3da86c32aae2c8e689c59f1196d8c4" + integrity sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg== + dependencies: + prop-types "^15.5.0" + +react-router-config@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988" + integrity sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg== + dependencies: + "@babel/runtime" "^7.1.2" + +react-router-dom@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" + integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.1" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.1, react-router@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" + integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-side-effect@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.1.tgz#66c5701c3e7560ab4822a4ee2742dee215d72eb3" + integrity sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ== + +react-textarea-autosize@^8.3.2: + version "8.3.3" + resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8" + integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ== + dependencies: + "@babel/runtime" "^7.10.2" + use-composed-ref "^1.0.0" + use-latest "^1.0.0" + +react@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +readable-stream@^2.0.1, readable-stream@^2.0.2: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +reading-time@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/reading-time/-/reading-time-1.5.0.tgz#d2a7f1b6057cb2e169beaf87113cc3411b5bc5bb" + integrity sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +recursive-readdir@2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + dependencies: + minimatch "3.0.4" + +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpu-core@^4.5.4, regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== + dependencies: + jsesc "~0.5.0" + +rehype-parse@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-6.0.2.tgz#aeb3fdd68085f9f796f1d3137ae2b85a98406964" + integrity sha512-0S3CpvpTAgGmnz8kiCyFLGuW5yA4OQhyNTm/nwPopZ7+PI11WnGl1TTWTGv/2hPEe/g2jRLlhVVSsoDH8waRug== + dependencies: + hast-util-from-parse5 "^5.0.0" + parse5 "^5.0.0" + xtend "^4.0.0" + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remark-admonitions@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/remark-admonitions/-/remark-admonitions-1.2.1.tgz#87caa1a442aa7b4c0cafa04798ed58a342307870" + integrity sha512-Ji6p68VDvD+H1oS95Fdx9Ar5WA2wcDA4kwrrhVU7fGctC6+d3uiMICu7w7/2Xld+lnU7/gi+432+rRbup5S8ow== + dependencies: + rehype-parse "^6.0.2" + unified "^8.4.2" + unist-util-visit "^2.0.1" + +remark-emoji@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/remark-emoji/-/remark-emoji-2.2.0.tgz#1c702090a1525da5b80e15a8f963ef2c8236cac7" + integrity sha512-P3cj9s5ggsUvWw5fS2uzCHJMGuXYRb0NnZqYlNecewXt8QBU9n5vW3DUUKOhepS8F9CwdMx9B8a3i7pqFWAI5w== + dependencies: + emoticon "^3.2.0" + node-emoji "^1.10.0" + unist-util-visit "^2.0.3" + +remark-footnotes@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" + integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== + +remark-mdx-remove-exports@^1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/remark-mdx-remove-exports/-/remark-mdx-remove-exports-1.6.22.tgz#9e34f3d02c9c54b02ca0a1fde946449338d06ecb" + integrity sha512-7g2uiTmTGfz5QyVb+toeX25frbk1Y6yd03RXGPtqx0+DVh86Gb7MkNYbk7H2X27zdZ3CQv1W/JqlFO0Oo8IxVA== + dependencies: + unist-util-remove "2.0.0" + +remark-mdx-remove-imports@^1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/remark-mdx-remove-imports/-/remark-mdx-remove-imports-1.6.22.tgz#79f711c95359cff437a120d1fbdc1326ec455826" + integrity sha512-lmjAXD8Ltw0TsvBzb45S+Dxx7LTJAtDaMneMAv8LAUIPEyYoKkmGbmVsiF0/pY6mhM1Q16swCmu1TN+ie/vn/A== + dependencies: + unist-util-remove "2.0.0" + +remark-mdx@1.6.22: + version "1.6.22" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-1.6.22.tgz#06a8dab07dcfdd57f3373af7f86bd0e992108bbd" + integrity sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ== + dependencies: + "@babel/core" "7.12.9" + "@babel/helper-plugin-utils" "7.10.4" + "@babel/plugin-proposal-object-rest-spread" "7.12.1" + "@babel/plugin-syntax-jsx" "7.12.1" + "@mdx-js/util" "1.6.22" + is-alphabetical "1.0.4" + remark-parse "8.0.3" + unified "9.2.0" + +remark-parse@8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1" + integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q== + dependencies: + ccount "^1.0.0" + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^2.0.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^2.0.0" + vfile-location "^3.0.0" + xtend "^4.0.1" + +remark-squeeze-paragraphs@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz#76eb0e085295131c84748c8e43810159c5653ead" + integrity sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw== + dependencies: + mdast-squeeze-paragraphs "^4.0.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +renderkid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a" + integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg== + dependencies: + css-select "^4.1.3" + dom-converter "^0.2.0" + htmlparser2 "^6.1.0" + lodash "^4.17.21" + strip-ansi "^6.0.1" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.5.4, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +"require-like@>= 0.1.1": + version "0.1.2" + resolved "https://registry.yarnpkg.com/require-like/-/require-like-0.1.2.tgz#ad6f30c13becd797010c468afa775c0c0a6b47fa" + integrity sha1-rW8wwTvs15cBDEaK+ndcDAprR/o= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.6, resolve@^1.14.2, resolve@^1.3.2: + version "1.21.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.1.tgz#1a88c73f5ca8ab0aabc8b888c4170de26c92c4cc" + integrity sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rtl-detect@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/rtl-detect/-/rtl-detect-1.0.4.tgz#40ae0ea7302a150b96bc75af7d749607392ecac6" + integrity sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ== + +rtlcss@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/rtlcss/-/rtlcss-3.5.0.tgz#c9eb91269827a102bac7ae3115dd5d049de636c3" + integrity sha512-wzgMaMFHQTnyi9YOwsx9LjOxYXJPzS8sYnFaKm6R5ysvTkwzHiB0vxnbHwchHQT65PTdBjDG21/kQBWI7q9O7A== + dependencies: + find-up "^5.0.0" + picocolors "^1.0.0" + postcss "^8.3.11" + strip-json-comments "^3.1.1" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.1.0: + version "7.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b" + integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0, schema-utils@^3.1.0, schema-utils@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7" + integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.8.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.0.0" + +section-matter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== + dependencies: + extend-shallow "^2.0.1" + kind-of "^6.0.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.8: + version "1.10.14" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.14.tgz#ee51d84d9dcecc61e07e4aba34f229ab525c1574" + integrity sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA== + dependencies: + node-forge "^0.10.0" + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-handler@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" + integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shelljs@^0.8.4: + version "0.8.5" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +sirv@^1.0.7: + version "1.0.19" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" + integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== + dependencies: + "@polka/url" "^1.0.0-next.20" + mrmime "^1.0.0" + totalist "^1.0.0" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +sitemap@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-7.1.0.tgz#300cd8b3fa9d45fb63f9b56d962785c3cd799362" + integrity sha512-OctwI2RYFj3Lnoutix0Qhow3AvDoUQ7rsSyzrY8wFKHqXYvmCJXFOBZyVU4/DDtsQ2KnEWY4j4j80hBHBOVEWQ== + dependencies: + "@types/node" "^17.0.5" + "@types/sax" "^1.2.1" + arg "^5.0.0" + sax "^1.2.4" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.2.tgz#4bc48c2da9ce4769f19dc723396b50f5c12330a3" + integrity sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ== + dependencies: + debug "^3.2.6" + eventsource "^1.0.7" + faye-websocket "^0.11.3" + inherits "^2.0.4" + json3 "^3.3.3" + url-parse "^1.5.3" + +sockjs@^0.3.21: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +sort-css-media-queries@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.0.4.tgz#b2badfa519cb4a938acbc6d3aaa913d4949dc908" + integrity sha512-PAIsEK/XupCQwitjv7XxoMvYhT7EAfyzI3hsy/MyDgTvc+Ft55ctdkctJLOy6cQejaIC+zjpUL4djFVm2ivOOw== + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +sourcemap-codec@^1.4.4: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +std-env@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-2.3.1.tgz#d42271908819c243f8defc77a140fc1fcee336a1" + integrity sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g== + dependencies: + ci-info "^3.1.1" + +std-env@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.0.1.tgz#bc4cbc0e438610197e34c2d79c3df30b491f5182" + integrity sha512-mC1Ps9l77/97qeOZc+HrOL7TIaOboHqMZ24dGVQrlxFcpPpfCHpH+qfUT7Dz+6mlG8+JPA1KfBQo19iC/+Ngcw== + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +stringify-object@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== + dependencies: + get-own-enumerable-property-symbols "^3.0.0" + is-obj "^1.0.1" + is-regexp "^1.0.0" + +strip-ansi@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +style-to-object@0.3.0, style-to-object@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + +stylehacks@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" + integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA== + dependencies: + browserslist "^4.16.0" + postcss-selector-parser "^6.0.4" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svg-parser@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" + integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== + +svgo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f" + integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ== + dependencies: + jest-worker "^27.4.1" + schema-utils "^3.1.1" + serialize-javascript "^6.0.0" + source-map "^0.6.1" + terser "^5.7.2" + +terser@^5.10.0, terser@^5.7.2: + version "5.10.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc" + integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.20" + +text-table@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tiny-invariant@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + +tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + +trim-trailing-lines@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" + integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +ua-parser-js@^0.7.30: + version "0.7.31" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +unified@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8" + integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +unified@^8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-8.4.2.tgz#13ad58b4a437faa2751a4a4c6a16f680c500fff1" + integrity sha512-JCrmN13jI4+h9UAyKEoGcDZV+i1E7BLFuG7OsaDvTXI5P0qhHX+vZO/kOhz9jn8HGENDKbwSeB0nVOg4gVStGA== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +unist-builder@2.0.3, unist-builder@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" + integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== + +unist-util-generated@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-1.1.6.tgz#5ab51f689e2992a472beb1b35f2ce7ff2f324d4b" + integrity sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg== + +unist-util-is@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" + integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== + +unist-util-position@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-3.1.0.tgz#1c42ee6301f8d52f47d14f62bbdb796571fa2d47" + integrity sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA== + +unist-util-remove-position@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" + integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA== + dependencies: + unist-util-visit "^2.0.0" + +unist-util-remove@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.0.0.tgz#32c2ad5578802f2ca62ab808173d505b2c898488" + integrity sha512-HwwWyNHKkeg/eXRnE11IpzY8JT55JNM1YCwwU9YNCnfzk6s8GhPXrVBBZWiwLeATJbI7euvoGSzcy9M29UeW3g== + dependencies: + unist-util-is "^4.0.0" + +unist-util-remove@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-2.1.0.tgz#b0b4738aa7ee445c402fda9328d604a02d010588" + integrity sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q== + dependencies: + unist-util-is "^4.0.0" + +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + +unist-util-visit-parents@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" + integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + +unist-util-visit@2.0.3, unist-util-visit@^2.0.0, unist-util-visit@^2.0.1, unist-util-visit@^2.0.2, unist-util-visit@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c" + integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + unist-util-visit-parents "^3.0.0" + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +update-notifier@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" + integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== + dependencies: + boxen "^5.0.0" + chalk "^4.1.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.4.0" + is-npm "^5.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.1.0" + pupa "^2.1.1" + semver "^7.3.4" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-loader@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-4.1.1.tgz#28505e905cae158cf07c92ca622d7f237e70a4e2" + integrity sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA== + dependencies: + loader-utils "^2.0.0" + mime-types "^2.1.27" + schema-utils "^3.0.0" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@^1.4.3, url-parse@^1.5.3: + version "1.5.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.4.tgz#e4f645a7e2a0852cc8a66b14b292a3e9a11a97fd" + integrity sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use-composed-ref@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849" + integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw== + +use-isomorphic-layout-effect@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz#7bb6589170cd2987a152042f9084f9effb75c225" + integrity sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ== + +use-latest@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232" + integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw== + dependencies: + use-isomorphic-layout-effect "^1.0.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= + +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vfile-location@^3.0.0, vfile-location@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" + integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA== + +vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" + integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + +wait-on@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" + integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== + dependencies: + axios "^0.21.1" + joi "^17.4.0" + lodash "^4.17.21" + minimist "^1.2.5" + rxjs "^7.1.0" + +watchpack@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" + integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +web-namespaces@^1.0.0, web-namespaces@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" + integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +webpack-bundle-analyzer@^4.4.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5" + integrity sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ== + dependencies: + acorn "^8.0.4" + acorn-walk "^8.0.0" + chalk "^4.1.0" + commander "^7.2.0" + gzip-size "^6.0.0" + lodash "^4.17.20" + opener "^1.5.2" + sirv "^1.0.7" + ws "^7.3.1" + +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.11.2: + version "3.11.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz#8c86b9d2812bf135d3c9bce6f07b718e30f7c3d3" + integrity sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA== + dependencies: + ansi-html-community "0.0.8" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.3.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.8" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.26" + schema-utils "^1.0.0" + selfsigned "^1.10.8" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + sockjs-client "^1.5.0" + spdy "^4.0.2" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "^13.3.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-merge@^5.8.0: + version "5.8.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61" + integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +webpack-sources@^1.1.0, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack-sources@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@^5.40.0: + version "5.66.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.66.0.tgz#789bf36287f407fc92b3e2d6f978ddff1bfc2dbb" + integrity sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg== + dependencies: + "@types/eslint-scope" "^3.7.0" + "@types/estree" "^0.0.50" + "@webassemblyjs/ast" "1.11.1" + "@webassemblyjs/wasm-edit" "1.11.1" + "@webassemblyjs/wasm-parser" "1.11.1" + acorn "^8.4.1" + acorn-import-assertions "^1.7.6" + browserslist "^4.14.5" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.8.3" + es-module-lexer "^0.9.0" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.9" + json-parse-better-errors "^1.0.2" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.1.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.1.3" + watchpack "^2.3.1" + webpack-sources "^3.2.2" + +webpackbar@^5.0.0-3: + version "5.0.2" + resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-5.0.2.tgz#d3dd466211c73852741dfc842b7556dcbc2b0570" + integrity sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ== + dependencies: + chalk "^4.1.0" + consola "^2.15.3" + pretty-time "^1.1.0" + std-env "^3.0.1" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +wildcard@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" + integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== + +worker-rpc@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" + integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== + dependencies: + microevent.ts "~0.1.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +ws@^7.3.1: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml-js@^1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + +xtend@^4.0.0, xtend@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0, yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zwitch@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" + integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== From bcbcdd385cd0bb5675c99856597ef45b44017be3 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 21 Jan 2022 15:10:57 +0530 Subject: [PATCH 25/95] Update scala3-library to 3.1.1 (#873) * Update scala3-library to 3.1.1 * Regenerate workflow with sbt-github-actions --- .github/workflows/ci.yml | 8 ++++---- project/BuildHelper.scala | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1cecb357a..ce5c60b58c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.12.15, 2.13.8, 3.1.0] + scala: [2.12.15, 2.13.8, 3.1.1] java: [graal_21.1.0@11, temurin@8] runs-on: ${{ matrix.os }} steps: @@ -143,12 +143,12 @@ jobs: tar xf targets.tar rm targets.tar - - name: Download target directories (3.1.0) + - name: Download target directories (3.1.1) uses: actions/download-artifact@v2 with: - name: target-${{ matrix.os }}-3.1.0-${{ matrix.java }} + name: target-${{ matrix.os }}-3.1.1-${{ matrix.java }} - - name: Inflate target directories (3.1.0) + - name: Inflate target directories (3.1.1) run: | tar xf targets.tar rm targets.tar diff --git a/project/BuildHelper.scala b/project/BuildHelper.scala index 01153b0415..35550de1bb 100644 --- a/project/BuildHelper.scala +++ b/project/BuildHelper.scala @@ -6,7 +6,7 @@ import xerial.sbt.Sonatype.autoImport._ object BuildHelper extends ScalaSettings { val Scala212 = "2.12.15" val Scala213 = "2.13.8" - val ScalaDotty = "3.1.0" + val ScalaDotty = "3.1.1" val ScoverageVersion = "1.9.3" private val stdOptions = Seq( From 9e8544c15aa07420a8ce1c8d3abb20e7802e7cc2 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 21 Jan 2022 15:38:10 +0530 Subject: [PATCH 26/95] Doc: Fix getting started link (#874) --- docs/website/src/pages/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/website/src/pages/index.js b/docs/website/src/pages/index.js index 21dc98990a..7e70b4995f 100644 --- a/docs/website/src/pages/index.js +++ b/docs/website/src/pages/index.js @@ -16,7 +16,7 @@ function HomepageHeader() {
+ to="/docs/v1.x/index"> Get Started
From a870231000e2067ea9e69bc161d6af7c84ff6894 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Fri, 21 Jan 2022 16:38:00 +0530 Subject: [PATCH 27/95] Update scalafmt-core to 3.3.2 (#864) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 7da3c9de66..91ea583b24 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.3.1 +version = 3.3.2 maxColumn = 120 align.preset = more From bdae5cf75352e36e62bb4144af829abdd3e81bc6 Mon Sep 17 00:00:00 2001 From: Gabriel Ciuloaica <95849448+gciuloaica@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:33:21 +0200 Subject: [PATCH 28/95] Doc: `Headers` documentation (#817) * doc: add categories * refactor: doc structure refactored * fix: package-lock.json removed * refactor: create outline sub-directories * initial draft on Headers documentaiton * refactor: rename test to testing * migrated Headers doc in the right structure * re-organized the section. added more examples on the service, client and middleware side. * updated documentation * updated based on review * more updates * more updates * minor changes * minor changes * Update docs/website/docs/v1.x/dsl/headers/index.md * Update docs/website/docs/v1.x/dsl/headers/index.md Co-authored-by: Shubham Girdhar Co-authored-by: amitsingh Co-authored-by: Amit Kumar Singh --- docs/website/docs/v1.x/dsl/headers/index.md | 227 +++++++++++++++++++- 1 file changed, 226 insertions(+), 1 deletion(-) diff --git a/docs/website/docs/v1.x/dsl/headers/index.md b/docs/website/docs/v1.x/dsl/headers/index.md index acfff8c574..7d41058766 100644 --- a/docs/website/docs/v1.x/dsl/headers/index.md +++ b/docs/website/docs/v1.x/dsl/headers/index.md @@ -1 +1,226 @@ -# Work in progress \ No newline at end of file +# Headers + +**ZIO HTTP** provides support for all HTTP headers (as defined in [RFC2616](https://datatracker.ietf.org/doc/html/rfc2616) ) along with custom headers. + +## Server-side + +### Attaching Headers to `Response` +On the server-side, `ZIO-HTTP` is adding a collection of pre-defined headers to the response, according to the HTTP specification, additionally, users may add other headers, including custom headers. + +There are multiple ways to attach headers to a response: +- Using `addHeaders` helper on response. + ```scala + val res = Response.ok.addHeader("content-length", "0") + ``` + +- Through `Response` constructors. + ```scala + val res = Response( + status = Status.OK, + // Setting response header + headers = Headers.contentLength(0L), + data = HttpData.empty + ``` +- Using `Middlewares`. + ```scala + val app = Http.ok @@ Middleware.addHeader("content-length", "0") + ``` + +### Reading Headers from `Request` + +On the Server-side you can read Request headers as given below + +```scala + case req @ Method.GET -> !! / "streamOrNot" => + req.getHeaders +``` + +
+Detailed examples +

+ +- Example below shows how the Headers could be added to a response by using `Response` constructors and how a custom header is added to `Response` through `addHeader`: + + ```scala + import zhttp.http._ + import zhttp.service.Server + import zio.{App, Chunk, ExitCode, URIO} + import zio.stream.ZStream + + object SimpleResponseDispatcher extends App { + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + + // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) + Server.start(8090, app.silent).exitCode + } + + // Create a message as a Chunk[Byte] + val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) + // Use `Http.collect` to match on route + val app: HttpApp[Any, Nothing] = Http.collect[Request] { + + // Simple (non-stream) based route + case Method.GET -> !! / "health" => Response.ok + + // From Request(req), the headers are accessible. + case req @ Method.GET -> !! / "streamOrNot" => + // Checking if client is able to handle streaming response + val acceptsStreaming: Boolean = req.hasHeader(HeaderNames.accept, HeaderValues.applicationOctetStream) + if (acceptsStreaming) + Response( + status = Status.OK, + // Setting response header + headers = Headers.contentLength(message.length.toLong), // adding CONTENT-LENGTH header + data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream + ) + else { + // Adding a custom header to Response + Response(status = Status.ACCEPTED, data = HttpData.fromChunk(message)).addHeader("X-MY-HEADER", "test") + } + } + } + + ``` + +- The following example shows how Headers could be added to `Response` in the `Middleware` implementation: + + ```scala + + /** + * Creates an authentication middleware that only allows authenticated requests to be passed on to the app. + */ + final def customAuth( + verify: Headers => Boolean, + responseHeaders: Headers = Headers.empty, + ): HttpMiddleware[Any, Nothing] = + Middleware.ifThenElse[Request](req => verify(req.getHeaders))( + _ => Middleware.identity, + _ => Middleware.fromHttp(Http.status(Status.FORBIDDEN).addHeaders(responseHeaders)), + ) + + ``` + +- More examples: + - [BasicAuth](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/BasicAuth.scala) + - [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) +

+
+ +## Client-side + +### Adding headers to `Request` + +ZIO-HTTP provides a simple way to add headers to a client `Request`. + +```scala +val headers = Headers.host("sports.api.decathlon.com").withAccept(HeaderValues.applicationJson) +val response = Client.request(url, headers) +``` + +### Reading headers from `Response` + +```scala +val responseHeaders: Task[Headers] = Client.request(url).map(_.headers) +``` + +
+Detailed examples +

+ +- The sample below shows how a header could be added to a client request: + + ```scala + import zhttp.http._ + import zhttp.service._ + import zio._ + + object SimpleClientJson extends App { + val env = ChannelFactory.auto ++ EventLoopGroup.auto() + val url = "http://sports.api.decathlon.com/groups/water-aerobics" + // Construct headers + val headers = Headers.host("sports.api.decathlon.com").withAccept(HeaderValues.applicationJson) + + val program = for { + // Pass headers to request + res <- Client.request(url, headers) + // List all response headers + _ <- console.putStrLn(res.headers.toList.mkString("\n")) + data <- + // Check if response contains a specified header with a specified value. + if (res.hasHeader(HeaderNames.contentType, HeaderValues.applicationJson)) + res.getBodyAsString + else + res.getBodyAsString + _ <- console.putStrLn { data } + } yield () + + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = program.exitCode.provideCustomLayer(env) + + } + ``` +

+
+ +## Headers DSL + +Headers DSL provides plenty of powerful operators that can be used to add, remove, modify and verify headers. Headers APIs could be used on client, server, and middleware. + +`zhttp.http.Headers` - represents an immutable collection of headers i.e. essentially a `Chunk[(String, String)]`. + +`zhttp.http.HeaderNames` - commonly used header names. + +`zhttp.http.HeaderValues` - commonly used header values + +`Headers` have following type of helpers +- Constructors - Provides a list of helpful methods that can create `Headers`. + + ```scala + import zhttp.http._ + + // create a simple Accept header: + val acceptHeader: Headers = Headers.accept(HeaderValues.applicationJson) + + // create a basic authentication header: + val basicAuthHeader: Headers = Headers.basicAuthorizationHeader("username", "password") + ``` + +- Getters - Provides a list of operators that parse and extract data from the `Headers`. + + ```scala + import zhttp.http._ + + // retrieving the value of Accept header value: + val acceptHeader: Headers = Headers.accept(HeaderValues.applicationJson) + val acceptHeaderValue: Option[CharSequence] = acceptHeader.getAccept + + + // retrieving a bearer token from Authorization header: + val authorizationHeader: Headers = Headers.authorization("Bearer test") + val authorizationHeaderValue: Option[String] = authorizationHeader.getBearerToken + ``` + +- Modifiers - Provides a list of operators that modify the current `Headers`. Once modified, a new instance of the same type is returned. + + ```scala + import zhttp.http._ + + // add Accept header: + val headers = Headers.empty + val updatedHeadersList: Headers = headers.addHeaders(Headers.accept(HeaderValues.applicationJson)) + + // or if you prefer the builder pattern: + + // add Host header: + val moreHeaders: Headers = headers.withHost("zio-http.dream11.com") + + ``` + +- Checks - Provides a list of operators that checks if the `Headers` meet the give constraints. + + ```scala + val contentTypeHeader: Headers = Headers.contentType(HeaderValues.applicationJson) + val isHeaderPresent: Boolean = contentTypeHeader.hasHeader(HeaderNames.contentType) + val isJsonContentType: Boolean = contentTypeHeader.hasJsonContentType + + + ``` From 786f51a86acb60d477755e7a44665e983140da5c Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sat, 22 Jan 2022 09:18:10 +0530 Subject: [PATCH 29/95] Fix collapsible Headers Doc (#876) --- docs/website/docs/v1.x/dsl/headers/index.md | 86 ++++++++++----------- docs/website/yarn.lock | 17 ++-- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/docs/website/docs/v1.x/dsl/headers/index.md b/docs/website/docs/v1.x/dsl/headers/index.md index 7d41058766..0f6b5dc69c 100644 --- a/docs/website/docs/v1.x/dsl/headers/index.md +++ b/docs/website/docs/v1.x/dsl/headers/index.md @@ -37,51 +37,50 @@ On the Server-side you can read Request headers as given below
Detailed examples -

+ - Example below shows how the Headers could be added to a response by using `Response` constructors and how a custom header is added to `Response` through `addHeader`: - ```scala - import zhttp.http._ - import zhttp.service.Server - import zio.{App, Chunk, ExitCode, URIO} - import zio.stream.ZStream - - object SimpleResponseDispatcher extends App { - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { - - // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app.silent).exitCode - } - - // Create a message as a Chunk[Byte] - val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) - // Use `Http.collect` to match on route - val app: HttpApp[Any, Nothing] = Http.collect[Request] { - - // Simple (non-stream) based route - case Method.GET -> !! / "health" => Response.ok - - // From Request(req), the headers are accessible. - case req @ Method.GET -> !! / "streamOrNot" => - // Checking if client is able to handle streaming response - val acceptsStreaming: Boolean = req.hasHeader(HeaderNames.accept, HeaderValues.applicationOctetStream) - if (acceptsStreaming) - Response( - status = Status.OK, - // Setting response header - headers = Headers.contentLength(message.length.toLong), // adding CONTENT-LENGTH header - data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream - ) - else { - // Adding a custom header to Response - Response(status = Status.ACCEPTED, data = HttpData.fromChunk(message)).addHeader("X-MY-HEADER", "test") - } - } + ```scala + import zhttp.http._ + import zhttp.service.Server + import zio.{App, Chunk, ExitCode, URIO} + import zio.stream.ZStream + + object SimpleResponseDispatcher extends App { + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + + // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) + Server.start(8090, app.silent).exitCode } - - ``` - + + // Create a message as a Chunk[Byte] + val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) + // Use `Http.collect` to match on route + val app: HttpApp[Any, Nothing] = Http.collect[Request] { + + // Simple (non-stream) based route + case Method.GET -> !! / "health" => Response.ok + + // From Request(req), the headers are accessible. + case req @ Method.GET -> !! / "streamOrNot" => + // Checking if client is able to handle streaming response + val acceptsStreaming: Boolean = req.hasHeader(HeaderNames.accept, HeaderValues.applicationOctetStream) + if (acceptsStreaming) + Response( + status = Status.OK, + // Setting response header + headers = Headers.contentLength(message.length.toLong), // adding CONTENT-LENGTH header + data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream + ) + else { + // Adding a custom header to Response + Response(status = Status.ACCEPTED, data = HttpData.fromChunk(message)).addHeader("X-MY-HEADER", "test") + } + } + } + + ``` - The following example shows how Headers could be added to `Response` in the `Middleware` implementation: ```scala @@ -103,7 +102,7 @@ On the Server-side you can read Request headers as given below - More examples: - [BasicAuth](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/BasicAuth.scala) - [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) -

+
## Client-side @@ -125,7 +124,6 @@ val responseHeaders: Task[Headers] = Client.request(url).map(_.headers)
Detailed examples -

- The sample below shows how a header could be added to a client request: @@ -158,7 +156,7 @@ val responseHeaders: Task[Headers] = Client.request(url).map(_.headers) } ``` -

+
## Headers DSL diff --git a/docs/website/yarn.lock b/docs/website/yarn.lock index bafec47e51..0931683c9e 100644 --- a/docs/website/yarn.lock +++ b/docs/website/yarn.lock @@ -3543,7 +3543,12 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.564, electron-to-chromium@^1.4.17: +electron-to-chromium@^1.3.564: + version "1.4.51" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.51.tgz#a432f5a5d983ace79278a33057300cf949627e63" + integrity sha512-JNEmcYl3mk1tGQmy0EvL5eik/CKSBuzAyGP0QFdG6LIgxQe3II0BL1m2zKc2MZMf3uGqHWE1TFddJML0RpjSHQ== + +electron-to-chromium@^1.4.17: version "1.4.49" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.49.tgz#5b6a3dc032590beef4be485a4b0b3fe7d0e3dfd7" integrity sha512-k/0t1TRfonHIp8TJKfjBu2cKj8MqYTiEpOhci+q7CVEE5xnCQnx1pTa+V8b/sdhe4S3PR4p4iceEQWhGrKQORQ== @@ -8645,15 +8650,15 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.3: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^3.2.2: +webpack-sources@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.40.0: - version "5.66.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.66.0.tgz#789bf36287f407fc92b3e2d6f978ddff1bfc2dbb" - integrity sha512-NJNtGT7IKpGzdW7Iwpn/09OXz9inIkeIQ/ibY6B+MdV1x6+uReqz/5z1L89ezWnpPDWpXF0TY5PCYKQdWVn8Vg== + version "5.67.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.67.0.tgz#cb43ca2aad5f7cc81c4cd36b626e6b819805dbfd" + integrity sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw== dependencies: "@types/eslint-scope" "^3.7.0" "@types/estree" "^0.0.50" @@ -8678,7 +8683,7 @@ webpack@^5.40.0: tapable "^2.1.1" terser-webpack-plugin "^5.1.3" watchpack "^2.3.1" - webpack-sources "^3.2.2" + webpack-sources "^3.2.3" webpackbar@^5.0.0-3: version "5.0.2" From 9fbabe57e1b0c52afcfd3949951f72ab58f2de26 Mon Sep 17 00:00:00 2001 From: zsfVishnu-d11 <66246684+zsfVishnu-d11@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:29:18 +0530 Subject: [PATCH 30/95] Test: Added Integration tests for `HExit.Success` (#852) * feat: added validation app for HExit without zio * feat: removed type from validationAppSpec * test: Iterating using HttpGen.Method * test: rearranged status method params * test: name fixes --- .../zhttp/internal/HttpRunnableSpec.scala | 4 +- .../test/scala/zhttp/service/ServerSpec.scala | 42 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 5745b2e662..8fac5983fa 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -43,12 +43,12 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => } yield response } - def status(path: Path): HttpIO[Any, Status] = { + def status(method: Method = Method.GET, path: Path): HttpIO[Any, Status] = { for { port <- DynamicServer.getPort status <- Client .request( - Method.GET, + method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", port)), ClientSSLOptions.DefaultSSL, ) diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 44acd921c3..66169ef60c 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -31,7 +31,13 @@ object ServerSpec extends HttpRunnableSpec { case Method.GET -> !! / "get%2Fsuccess" => ZIO.succeed(Response.ok) } - private val app = serve { staticApp ++ DynamicServer.app } + // Use this route to test anything that doesn't require ZIO related computations. + private val nonZIO = Http.collect[Request] { + case _ -> !! / "HExitSuccess" => Response.ok + case _ -> !! / "HExitFailure" => Response.fromHttpError(HttpError.BadRequest()) + } + + private val app = serve { nonZIO ++ staticApp ++ DynamicServer.app } def dynamicAppSpec = suite("DynamicAppSpec") { suite("success") { @@ -222,7 +228,7 @@ object ServerSpec extends HttpRunnableSpec { override def spec = suiteM("Server") { - app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec)).useNow + app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec, nonZIOSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(30 seconds) def serverStartSpec = suite("ServerStartSpec") { @@ -241,25 +247,47 @@ object ServerSpec extends HttpRunnableSpec { def staticAppSpec = suite("StaticAppSpec") { testM("200 response") { - val actual = status(!! / "success") + val actual = status(path = !! / "success") assertM(actual)(equalTo(Status.OK)) } + testM("500 response") { - val actual = status(!! / "failure") + val actual = status(path = !! / "failure") assertM(actual)(equalTo(Status.INTERNAL_SERVER_ERROR)) } + testM("404 response") { - val actual = status(!! / "random") + val actual = status(path = !! / "random") assertM(actual)(equalTo(Status.NOT_FOUND)) } + testM("200 response with encoded path") { - val actual = status(!! / "get%2Fsuccess") + val actual = status(path = !! / "get%2Fsuccess") assertM(actual)(equalTo(Status.OK)) } + testM("Multiple 200 response") { for { - data <- status(!! / "success").repeatN(1024) + data <- status(path = !! / "success").repeatN(1024) } yield assertTrue(data == Status.OK) } } + + def nonZIOSpec = suite("NonZIOSpec") { + testM("200 response") { + checkAllM(HttpGen.method) { method => + val actual = status(method, !! / "HExitSuccess") + assertM(actual)(equalTo(Status.OK)) + } + } + + testM("400 response") { + checkAllM(HttpGen.method) { method => + val actual = status(method, !! / "HExitFailure") + assertM(actual)(equalTo(Status.BAD_REQUEST)) + } + } + + testM("404 response ") { + checkAllM(HttpGen.method) { method => + val actual = status(method, !! / "A") + assertM(actual)(equalTo(Status.NOT_FOUND)) + } + } + + } } From 0d59e4c4e1db8e7530d288a351fd6689687c7f9d Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Mon, 24 Jan 2022 06:08:12 +0100 Subject: [PATCH 31/95] Update scalafmt-core to 3.3.3 (#881) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 91ea583b24..19a16b06f9 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.3.2 +version = 3.3.3 maxColumn = 120 align.preset = more From e4d74248dd1577e2388874ad05844b859224f940 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Mon, 24 Jan 2022 16:07:44 +0530 Subject: [PATCH 32/95] Update scalafmt-core to 3.3.3 (#884) From 0ee6dde49f81405e5055c27c6ba9146c3b906061 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Mon, 24 Jan 2022 16:12:22 +0530 Subject: [PATCH 33/95] Fix: EncodeClientParams (#868) * fix: encodeClientParams * test(client): added test for req url string * test(client): variable name changed * test: added test in encodeClientSpec * simplifies test case * doc: add comment on why relative path needs to be used. Co-authored-by: Tushar Mathur --- .../zhttp/service/EncodeClientParams.scala | 12 ++++++---- .../zhttp/http/EncodeClientRequestSpec.scala | 24 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index b3479fe682..eb9c935b3a 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -9,9 +9,13 @@ trait EncodeClientParams { * Converts client params to JFullHttpRequest */ def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { - val method = req.method.asHttpMethod - val url = req.url - val uri = url.asString + val method = req.method.asHttpMethod + val url = req.url + + // As per the spec, the path should contain only the relative path. + // Host and port information should be in the headers. + val path = url.relative.asString + val content = req.getBodyAsString match { case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) case None => Unpooled.EMPTY_BUFFER @@ -29,7 +33,7 @@ trait EncodeClientParams { headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) } // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. - val jReq = new DefaultFullHttpRequest(jVersion, method, uri, content) + val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) jReq.headers().set(headers) jReq diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index fb444de316..6d2ebc5b24 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -42,17 +42,19 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientPara assert(req.method())(equalTo(params.method.asHttpMethod)) } } + - testM("uri") { - check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.asString)) - } - } + - testM("uri on HttpData.File") { - check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.asString)) - } + suite("uri") { + testM("uri") { + check(anyClientParam) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.uri())(equalTo(params.url.relative.asString)) + } + } + + testM("uri on HttpData.File") { + check(HttpGen.clientParamsForFileHttpData()) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.uri())(equalTo(params.url.relative.asString)) + } + } } + testM("content-length") { check(clientParamWithFiniteData(5)) { params => From dc0d80f84f47a5ac6231b1e4f52179aaa168ef88 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 25 Jan 2022 21:16:54 +0530 Subject: [PATCH 34/95] Refactor: HttpRunnableSpec clean up (#857) * refactor: reduce HttpRunnableSpec boilerplate * refactor: remove all helpers from HttpRunnableSpec and inline the method * doc: update documentation for test module * refactor: add type-constraints to Http for specialized methods * refactor: use IsResponse type constraint * style(*): apply scala fmt * doc: update documentation --- zio-http/src/main/scala/zhttp/http/Http.scala | 56 +++++- .../main/scala/zhttp/http/IsResponse.scala | 25 +++ .../src/main/scala/zhttp/http/Response.scala | 9 +- .../src/main/scala/zhttp/service/Client.scala | 8 +- .../zhttp/internal/HttpRunnableSpec.scala | 183 ++++++++---------- .../test/scala/zhttp/service/ClientSpec.scala | 10 +- .../test/scala/zhttp/service/ServerSpec.scala | 77 ++++---- .../zhttp/service/WebSocketServerSpec.scala | 15 +- 8 files changed, 223 insertions(+), 160 deletions(-) create mode 100644 zio-http/src/main/scala/zhttp/http/IsResponse.scala diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 79701369f3..da986539c8 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -1,5 +1,6 @@ package zhttp.http +import io.netty.buffer.{ByteBuf, ByteBufUtil} import io.netty.channel.ChannelHandler import zhttp.html.Html import zhttp.http.headers.HeaderModifier @@ -170,6 +171,40 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => dd: Http[R1, E1, A1, B1], ): Http[R1, E1, A1, B1] = Http.FoldHttp(self, ee, bb, dd) + /** + * Extracts body + */ + final def getBody(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, Chunk[Byte]] = + self.getBodyAsByteBuf.mapZIO(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) + + /** + * Extracts body as a string + */ + final def getBodyAsString(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, String] = + self.getBodyAsByteBuf.mapZIO(bytes => Task(bytes.toString(HTTP_CHARSET))) + + /** + * Extracts content-length from the response if available + */ + final def getContentLength(implicit eb: IsResponse[B]): Http[R, E, A, Option[Long]] = + getHeaders.map(_.getContentLength) + + /** + * Extracts the value of the provided header name. + */ + final def getHeaderValue(name: CharSequence)(implicit eb: IsResponse[B]): Http[R, E, A, Option[CharSequence]] = + getHeaders.map(_.getHeaderValue(name)) + + /** + * Extracts the `Headers` from the type `B` if possible + */ + final def getHeaders(implicit eb: IsResponse[B]): Http[R, E, A, Headers] = self.map(eb.getHeaders) + + /** + * Extracts `Status` from the type `B` is possible. + */ + final def getStatus(implicit ev: IsResponse[B]): Http[R, E, A, Status] = self.map(ev.getStatus) + /** * Transforms the output of the http app */ @@ -313,8 +348,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Widens the type of the output */ - final def widen[B1](implicit ev: B <:< B1): Http[R, E, A, B1] = - self.asInstanceOf[Http[R, E, A, B1]] + final def widen[E1, B1](implicit e: E <:< E1, b: B <:< B1): Http[R, E1, A, B1] = + self.asInstanceOf[Http[R, E1, A, B1]] /** * Combines the two apps and returns the result of the one on the right @@ -351,6 +386,15 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => case RunMiddleware(app, mid) => mid(app).execute(a) } + + /** + * Extracts body as a ByteBuf + */ + private[zhttp] final def getBodyAsByteBuf(implicit + eb: IsResponse[B], + ee: E <:< Throwable, + ): Http[R, Throwable, A, ByteBuf] = + self.widen[Throwable, B].mapZIO(eb.getBodyAsByteBuf) } object Http { @@ -633,12 +677,12 @@ object Http { dd: Http[R, EE, A, BB], ) extends Http[R, EE, A, BB] - private case object Empty extends Http[Any, Nothing, Any, Nothing] - - private case object Identity extends Http[Any, Nothing, Any, Nothing] - private final case class RunMiddleware[R, E, A1, B1, A2, B2]( http: Http[R, E, A1, B1], mid: Middleware[R, E, A1, B1, A2, B2], ) extends Http[R, E, A2, B2] + + private case object Empty extends Http[Any, Nothing, Any, Nothing] + + private case object Identity extends Http[Any, Nothing, Any, Nothing] } diff --git a/zio-http/src/main/scala/zhttp/http/IsResponse.scala b/zio-http/src/main/scala/zhttp/http/IsResponse.scala new file mode 100644 index 0000000000..8f68acf23c --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/IsResponse.scala @@ -0,0 +1,25 @@ +package zhttp.http + +import io.netty.buffer.ByteBuf +import zhttp.service.Client.ClientResponse +import zio.Task + +sealed trait IsResponse[-A] { + def getBodyAsByteBuf(a: A): Task[ByteBuf] + def getHeaders(a: A): Headers + def getStatus(a: A): Status +} + +object IsResponse { + implicit object serverResponse extends IsResponse[Response] { + def getBodyAsByteBuf(a: Response): Task[ByteBuf] = a.getBodyAsByteBuf + def getHeaders(a: Response): Headers = a.headers + def getStatus(a: Response): Status = a.status + } + + implicit object clientResponse extends IsResponse[ClientResponse] { + def getBodyAsByteBuf(a: ClientResponse): Task[ByteBuf] = a.getBodyAsByteBuf + def getHeaders(a: ClientResponse): Headers = a.headers + def getStatus(a: ClientResponse): Status = a.status + } +} diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index b59d13b08a..738aced8c3 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -1,6 +1,6 @@ package zhttp.http -import io.netty.buffer.Unpooled +import io.netty.buffer.{ByteBuf, Unpooled} import io.netty.handler.codec.http.HttpVersion.HTTP_1_1 import io.netty.handler.codec.http.{HttpHeaderNames, HttpResponse} import zhttp.core.Util @@ -8,7 +8,7 @@ import zhttp.html.Html import zhttp.http.HttpError.HTTPErrorWithCause import zhttp.http.headers.HeaderExtension import zhttp.socket.{IsWebSocket, Socket, SocketApp} -import zio.{Chunk, UIO, ZIO} +import zio.{Chunk, Task, UIO, ZIO} import java.nio.charset.Charset import java.nio.file.Files @@ -66,6 +66,11 @@ final case class Response private ( */ def wrapZIO: UIO[Response] = UIO(self) + /** + * Extracts the body as ByteBuf + */ + private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = self.data.toByteBuf + /** * Encodes the Response into a Netty HttpResponse. Sets default headers such as `content-length`. For performance * reasons, it is possible that it uses a FullHttpResponse if the complete data is available. Otherwise, it would diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 74d074172e..fb9afde801 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -176,13 +176,15 @@ object Client { self.copy(getHeaders = update(self.getHeaders)) } - final case class ClientResponse(status: Status, headers: Headers, private val buffer: ByteBuf) + final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) extends HeaderExtension[ClientResponse] { self => - def getBodyAsString: Task[String] = Task(buffer.toString(self.getCharset)) - def getBody: Task[Chunk[Byte]] = Task(Chunk.fromArray(ByteBufUtil.getBytes(buffer))) + def getBodyAsByteBuf: Task[ByteBuf] = Task(buffer) + + def getBodyAsString: Task[String] = Task(buffer.toString(self.getCharset)) + override def getHeaders: Headers = headers override def updateHeaders(update: Headers => Headers): ClientResponse = self.copy(headers = update(headers)) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 8fac5983fa..1642799a76 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -1,24 +1,92 @@ package zhttp.internal +import sttp.client3 import sttp.client3.asynchttpclient.zio.{SttpClient, send} -import sttp.client3.{Response => SResponse, UriContext, asWebSocketUnsafe, basicRequest} +import sttp.client3.{UriContext, asWebSocketUnsafe, basicRequest} import sttp.model.{Header => SHeader} import sttp.ws.WebSocket import zhttp.http.URL.Location import zhttp.http._ import zhttp.internal.DynamicServer.HttpEnv -import zhttp.internal.HttpRunnableSpec.HttpIO +import zhttp.internal.HttpRunnableSpec.HttpTestClient import zhttp.service._ import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zio.test.DefaultRunnableSpec -import zio.{Chunk, Has, Task, ZIO, ZManaged} +import zio.{Has, Task, ZIO, ZManaged} /** - * Should be used only when e2e tests needs to be written which is typically for logic that is part of the netty based - * backend. For most of the other use cases directly running the HttpApp should suffice. HttpRunnableSpec spins of an - * actual Http server and makes requests. + * Should be used only when e2e tests needs to be written. Typically we would want to do that when we want to test the + * logic that is part of the netty based backend. For most of the other use cases directly running the HttpApp should + * suffice. HttpRunnableSpec spins of an actual Http server and makes requests. */ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => + + implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Client.ClientRequest, A]) { + + /** + * Runs the deployed Http app by making a real http request to it. The method allows us to configure individual + * constituents of a ClientRequest. + */ + def run( + path: Path = !!, + method: Method = Method.GET, + content: String = "", + headers: Headers = Headers.empty, + ): ZIO[R, Throwable, A] = + app( + Client.ClientRequest( + method, + URL(path, Location.Absolute(Scheme.HTTP, "localhost", 0)), + headers, + HttpData.fromString(content), + ), + ).catchAll { + case Some(value) => ZIO.fail(value) + case None => ZIO.fail(new RuntimeException("No response")) + } + } + + implicit class RunnableHttpClientAppSyntax(app: HttpApp[HttpEnv, Throwable]) { + + /** + * Deploys the http application on the test server and returns a Http of type + * {{{Http[R, E, ClientRequest, ClientResponse}}}. This allows us to assert using all the powerful operators that + * are available on `Http` while writing tests. It also allows us to simply pass a request in the end, to execute, + * and resolve it with a response, like a normal HttpApp. + */ + def deploy: HttpTestClient[Any, Client.ClientResponse] = + for { + port <- Http.fromZIO(DynamicServer.getPort) + id <- Http.fromZIO(DynamicServer.deploy(app)) + response <- Http.fromFunctionZIO[Client.ClientRequest] { params => + Client.request( + params + .addHeader(DynamicServer.APP_ID, id) + .copy(url = URL(params.url.path, Location.Absolute(Scheme.HTTP, "localhost", port))), + ClientSSLOptions.DefaultSSL, + ) + } + } yield response + + /** + * Deploys the websocket application on the test server. + */ + def deployWebSocket: HttpTestClient[SttpClient, client3.Response[Either[String, WebSocket[Task]]]] = for { + id <- Http.fromZIO(DynamicServer.deploy(app)) + res <- + Http.fromFunctionZIO[Client.ClientRequest](params => + for { + port <- DynamicServer.getPort + url = s"ws://localhost:$port${params.url.path.asString}" + headerConv = params.addHeader(DynamicServer.APP_ID, id).getHeaders.toList.map(h => SHeader(h._1, h._2)) + res <- send(basicRequest.get(uri"$url").copy(headers = headerConv).response(asWebSocketUnsafe)) + } yield res, + ) + + } yield res + + } + def serve[R <: Has[_]]( app: HttpApp[R, Throwable], ): ZManaged[R with EventLoopGroup with ServerChannelFactory with DynamicServer, Nothing, Unit] = @@ -27,23 +95,10 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => _ <- DynamicServer.setStart(start).toManaged_ } yield () - def request( - path: Path = !!, + def status( method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, Client.ClientResponse] = { - for { - port <- DynamicServer.getPort - data = HttpData.fromString(content) - response <- Client.request( - Client.ClientRequest(method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", port)), headers, data), - ClientSSLOptions.DefaultSSL, - ) - } yield response - } - - def status(method: Method = Method.GET, path: Path): HttpIO[Any, Status] = { + path: Path, + ): ZIO[EventLoopGroup with ChannelFactory with DynamicServer, Throwable, Status] = { for { port <- DynamicServer.getPort status <- Client @@ -55,84 +110,14 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => .map(_.status) } yield status } - - def webSocketRequest( - path: Path = !!, - headers: Headers = Headers.empty, - ): HttpIO[SttpClient, SResponse[Either[String, WebSocket[Task]]]] = { - // todo: uri should be created by using URL().asString but currently support for ws Scheme is missing - for { - port <- DynamicServer.getPort - url = s"ws://localhost:$port${path.asString}" - headerConv: List[SHeader] = headers.toList.map(h => SHeader(h._1, h._2)) - res <- send(basicRequest.get(uri"$url").copy(headers = headerConv).response(asWebSocketUnsafe)) - } yield res - } - - implicit class RunnableHttpAppSyntax(app: HttpApp[HttpEnv, Throwable]) { - def deploy: ZIO[DynamicServer, Nothing, String] = DynamicServer.deploy(app) - - def request( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, Client.ClientResponse] = for { - id <- deploy - response <- self.request(path, method, content, Headers(DynamicServer.APP_ID, id) ++ headers) - } yield response - - def requestBodyAsString( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, String] = - request(path, method, content, headers).flatMap(_.getBodyAsString) - - def requestHeaderValueByName( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - )(name: CharSequence): HttpIO[Any, Option[String]] = - request(path, method, content, headers).map(_.getHeaderValue(name)) - - def requestStatus( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, Status] = - request(path, method, content, headers).map(_.status) - - def webSocketStatusCode( - path: Path = !!, - headers: Headers = Headers.empty, - ): HttpIO[SttpClient, Int] = for { - id <- deploy - res <- self.webSocketRequest(path, Headers(DynamicServer.APP_ID, id) ++ headers) - } yield res.code.code - - def requestBody( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, Chunk[Byte]] = - request(path, method, content, headers).flatMap(_.getBody) - - def requestContentLength( - path: Path = !!, - method: Method = Method.GET, - content: String = "", - headers: Headers = Headers.empty, - ): HttpIO[Any, Option[Long]] = - request(path, method, content, headers).map(_.getContentLength) - } } object HttpRunnableSpec { - type HttpIO[-R, +A] = - ZIO[R with EventLoopGroup with ChannelFactory with DynamicServer with ServerChannelFactory, Throwable, A] + type HttpTestClient[-R, +A] = + Http[ + R with EventLoopGroup with ChannelFactory with DynamicServer with ServerChannelFactory, + Throwable, + Client.ClientRequest, + A, + ] } diff --git a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala index 5424ea5b66..84d8c6b470 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala @@ -15,27 +15,27 @@ object ClientSpec extends HttpRunnableSpec { def clientSpec = suite("ClientSpec") { testM("respond Ok") { - val app = Http.ok.requestStatus() + val app = Http.ok.deploy.getStatus.run() assertM(app)(equalTo(Status.OK)) } + testM("non empty content") { val app = Http.text("abc") - val responseContent = app.requestBody() + val responseContent = app.deploy.getBody.run() assertM(responseContent)(isNonEmpty) } + testM("echo POST request content") { val app = Http.collectZIO[Request] { case req => req.getBodyAsString.map(Response.text(_)) } - val res = app.requestBodyAsString(method = Method.POST, content = "ZIO user") + val res = app.deploy.getBodyAsString.run(method = Method.POST, content = "ZIO user") assertM(res)(equalTo("ZIO user")) } + testM("empty content") { val app = Http.empty - val responseContent = app.requestBody() + val responseContent = app.deploy.getBody.run() assertM(responseContent)(isEmpty) } + testM("text content") { val app = Http.text("zio user does not exist") - val responseContent = app.requestBodyAsString() + val responseContent = app.deploy.getBodyAsString.run() assertM(responseContent)(containsString("user")) } } diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 66169ef60c..3c721eff22 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -1,6 +1,5 @@ package zhttp.service -import io.netty.handler.codec.http.HttpHeaderNames import zhttp.html._ import zhttp.http._ import zhttp.internal.{DynamicServer, HttpGen, HttpRunnableSpec} @@ -42,41 +41,41 @@ object ServerSpec extends HttpRunnableSpec { def dynamicAppSpec = suite("DynamicAppSpec") { suite("success") { testM("status is 200") { - val status = Http.ok.requestStatus() + val status = Http.ok.deploy.getStatus.run() assertM(status)(equalTo(Status.OK)) } + testM("status is 200") { - val res = Http.text("ABC").requestStatus() + val res = Http.text("ABC").deploy.getStatus.run() assertM(res)(equalTo(Status.OK)) } + testM("content is set") { - val res = Http.text("ABC").requestBodyAsString() + val res = Http.text("ABC").deploy.getBodyAsString.run() assertM(res)(containsString("ABC")) } } + suite("not found") { val app = Http.empty testM("status is 404") { - val res = app.requestStatus() + val res = app.deploy.getStatus.run() assertM(res)(equalTo(Status.NOT_FOUND)) } + testM("header is set") { - val res = app.request().map(_.getHeaderValue("Content-Length")) + val res = app.deploy.getHeaderValue(HeaderNames.contentLength).run() assertM(res)(isSome(equalTo("0"))) } } + suite("error") { val app = Http.fail(new Error("SERVER_ERROR")) testM("status is 500") { - val res = app.requestStatus() + val res = app.deploy.getStatus.run() assertM(res)(equalTo(Status.INTERNAL_SERVER_ERROR)) } + testM("content is set") { - val res = app.requestBodyAsString() + val res = app.deploy.getBodyAsString.run() assertM(res)(containsString("SERVER_ERROR")) } + testM("header is set") { - val res = app.request().map(_.getHeaderValue("Content-Length")) + val res = app.deploy.getHeaderValue(HeaderNames.contentLength).run() assertM(res)(isSome(anything)) } } + @@ -86,32 +85,32 @@ object ServerSpec extends HttpRunnableSpec { } testM("status is 200") { - val res = app.requestStatus() + val res = app.deploy.getStatus.run() assertM(res)(equalTo(Status.OK)) } + testM("body is ok") { - val res = app.requestBodyAsString(content = "ABC") + val res = app.deploy.getBodyAsString.run(content = "ABC") assertM(res)(equalTo("ABC")) } + testM("empty string") { - val res = app.requestBodyAsString(content = "") + val res = app.deploy.getBodyAsString.run(content = "") assertM(res)(equalTo("")) } + testM("one char") { - val res = app.requestBodyAsString(content = "1") + val res = app.deploy.getBodyAsString.run(content = "1") assertM(res)(equalTo("1")) } } + suite("headers") { val app = Http.ok.addHeader("Foo", "Bar") testM("headers are set") { - val res = app.request().map(_.getHeaderValue("Foo")) + val res = app.deploy.getHeaderValue("Foo").run() assertM(res)(isSome(equalTo("Bar"))) } } + suite("response") { val app = Http.response(Response(status = Status.OK, data = HttpData.fromString("abc"))) testM("body is set") { - val res = app.requestBodyAsString() + val res = app.deploy.getBodyAsString.run() assertM(res)(equalTo("abc")) } } @@ -123,13 +122,13 @@ object ServerSpec extends HttpRunnableSpec { } testM("has content-length") { checkAllM(Gen.alphaNumericString) { string => - val res = app.requestBodyAsString(content = string) + val res = app.deploy.getBodyAsString.run(content = string) assertM(res)(equalTo(string.length.toString)) } } + testM("POST Request.getBody") { val app = Http.collectZIO[Request] { case req => req.getBody.as(Response.ok) } - val res = app.requestStatus(!!, Method.POST, "some text") + val res = app.deploy.getStatus.run(!!, Method.POST, "some text") assertM(res)(equalTo(Status.OK)) } } @@ -137,13 +136,13 @@ object ServerSpec extends HttpRunnableSpec { def responseSpec = suite("ResponseSpec") { testM("data") { checkAllM(nonEmptyContent) { case (string, data) => - val res = Http.fromData(data).requestBodyAsString() + val res = Http.fromData(data).deploy.getBodyAsString.run() assertM(res)(equalTo(string)) } } + testM("data from file") { val file = new File(getClass.getResource("/TestFile.txt").getPath) - val res = Http.fromFile(file).requestBodyAsString() + val res = Http.fromFile(file).deploy.getBodyAsString.run() assertM(res)(equalTo("abc\nfoo")) } + testM("content-type header on file response") { @@ -151,24 +150,26 @@ object ServerSpec extends HttpRunnableSpec { val res = Http .fromFile(file) - .requestHeaderValueByName()(HttpHeaderNames.CONTENT_TYPE) + .deploy + .getHeaderValue(HeaderNames.contentType) + .run() .map(_.getOrElse("Content type header not found.")) assertM(res)(equalTo("text/plain")) } + testM("status") { - checkAllM(HttpGen.status) { case (status) => - val res = Http.status(status).requestStatus() + checkAllM(HttpGen.status) { case status => + val res = Http.status(status).deploy.getStatus.run() assertM(res)(equalTo(status)) } } + testM("header") { checkAllM(HttpGen.header) { case header @ (name, value) => - val res = Http.ok.addHeader(header).requestHeaderValueByName()(name) + val res = Http.ok.addHeader(header).deploy.getHeaderValue(name).run() assertM(res)(isSome(equalTo(value))) } } + testM("text streaming") { - val res = Http.fromStream(ZStream("a", "b", "c")).requestBodyAsString() + val res = Http.fromStream(ZStream("a", "b", "c")).deploy.getBodyAsString.run() assertM(res)(equalTo("abc")) } + testM("echo streaming") { @@ -176,33 +177,35 @@ object ServerSpec extends HttpRunnableSpec { .collectHttp[Request] { case req => Http.fromStream(ZStream.fromEffect(req.getBody).flattenChunks) } - .requestBodyAsString(content = "abc") + .deploy + .getBodyAsString + .run(content = "abc") assertM(res)(equalTo("abc")) } + testM("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath - val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).requestBodyAsString() + val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).deploy.getBodyAsString.run() assertM(res)(equalTo("abc\nfoo")) } + suite("html") { testM("body") { - val res = Http.html(html(body(div(id := "foo", "bar")))).requestBodyAsString() + val res = Http.html(html(body(div(id := "foo", "bar")))).deploy.getBodyAsString.run() assertM(res)(equalTo("""
bar
""")) } + testM("content-type") { val app = Http.html(html(body(div(id := "foo", "bar")))) - val res = app.requestHeaderValueByName()(HeaderNames.contentType) + val res = app.deploy.getHeaderValue(HeaderNames.contentType).run() assertM(res)(isSome(equalTo(HeaderValues.textHtml.toString))) } } + suite("content-length") { suite("string") { testM("unicode text") { - val res = Http.text("äöü").requestContentLength() + val res = Http.text("äöü").deploy.getContentLength.run() assertM(res)(isSome(equalTo(6L))) } + testM("already set") { - val res = Http.text("1234567890").withContentLength(4L).requestContentLength() + val res = Http.text("1234567890").withContentLength(4L).deploy.getContentLength.run() assertM(res)(isSome(equalTo(4L))) } } @@ -213,24 +216,19 @@ object ServerSpec extends HttpRunnableSpec { val expected = (0 to size) map (_ => Status.OK) for { response <- Response.text("abc").freeze - actual <- ZIO.foreachPar(0 to size)(_ => Http.response(response).requestStatus()) + actual <- ZIO.foreachPar(0 to size)(_ => Http.response(response).deploy.getStatus.run()) } yield assert(actual)(equalTo(expected)) } + testM("update after cache") { val server = "ZIO-Http" for { res <- Response.text("abc").freeze - actual <- Http.response(res).withServer(server).requestHeaderValueByName()(HeaderNames.server) + actual <- Http.response(res).withServer(server).deploy.getHeaderValue(HeaderNames.server).run() } yield assert(actual)(isSome(equalTo(server))) } } } - override def spec = - suiteM("Server") { - app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec, nonZIOSpec)).useNow - }.provideCustomLayerShared(env) @@ timeout(30 seconds) - def serverStartSpec = suite("ServerStartSpec") { testM("desired port") { val port = 8088 @@ -245,6 +243,11 @@ object ServerSpec extends HttpRunnableSpec { } } + override def spec = + suiteM("Server") { + app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec)).useNow + }.provideCustomLayerShared(env) @@ timeout(30 seconds) + def staticAppSpec = suite("StaticAppSpec") { testM("200 response") { val actual = status(path = !! / "success") diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index c09313e03c..5a9095e849 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -12,6 +12,12 @@ import zio.test._ object WebSocketServerSpec extends HttpRunnableSpec { + private val env = + EventLoopGroup.nio() ++ ServerChannelFactory.nio ++ AsyncHttpClientZioBackend + .layer() + .orDie ++ DynamicServer.live ++ ChannelFactory.nio + private val app = serve { DynamicServer.app } + override def spec = suiteM("Server") { app.as(List(websocketSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(30 seconds) @@ -21,15 +27,8 @@ object WebSocketServerSpec extends HttpRunnableSpec { testM("Multiple websocket upgrades") { val response = Socket.succeed(WebSocketFrame.text("BAR")).toResponse val app = Http.fromZIO(response) - assertM(app.webSocketStatusCode(!! / "subscriptions").repeatN(1024))(equalTo(101)) + assertM(app.deployWebSocket.map(_.code.code).run(!! / "subscriptions").repeatN(1024))(equalTo(101)) } } } - - private val env = - EventLoopGroup.nio() ++ ServerChannelFactory.nio ++ AsyncHttpClientZioBackend - .layer() - .orDie ++ DynamicServer.live ++ ChannelFactory.nio - - private val app = serve { DynamicServer.app } } From 6850897af8f91da1aa55cccb14bca5f9ef963c23 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 26 Jan 2022 17:13:35 +0530 Subject: [PATCH 35/95] update doc (#897) --- docs/website/docs/v1.x/getting-started.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index e3a09048b8..f10dc0d430 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -37,10 +37,10 @@ import zhttp.http._ val a = Http.collect[Request] { case Method.GET -> !! / "a" => Response.ok } val b = Http.collect[Request] { case Method.GET -> !! / "b" => Response.ok } -val app = a <> b +val app = a ++ b ``` -Apps can be composed using the `<>` operator. The way it works is, if none of the routes match in `a` , or a `NotFound` error is thrown from `a`, and then the control is passed on to the `b` app. +Apps can be composed using the `++` operator. The way it works is, if none of the routes match in `a` , then the control is passed on to the `b` app. ### ZIO Integration @@ -67,15 +67,14 @@ val app = Http.collectZIO[Request] { ### Testing -zhttp provides a `zhttp-test` package for use in unit tests. You can utilize it as follows: +Since `Http` is a function of the form `A => ZIO[R, Option[E], B]` to test it you can simply call an `Http` like a function. ```scala import zio.test._ -import zhttp.test._ import zhttp.http._ object Spec extends DefaultRunnableSpec { - + def spec = suite("http")( testM("should be ok") { val app = Http.ok From 14320efba779fd5f02b74452d979d9f4be62b0ea Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Wed, 26 Jan 2022 19:21:21 +0530 Subject: [PATCH 36/95] Docs: Getting started (#887) * fix: added more content * fixed comments * fix: getting started * modifications * added more * minor changes * minor changes * changes --- docs/website/docs/v1.x/getting-started.md | 53 ++++++++++++++++++----- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index f10dc0d430..7e1806035d 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -4,21 +4,31 @@ sidebar_position: 2 # Getting Started +**ZIO HTTP** is a powerful library that is used to build highly performant HTTP-based services and clients using functional scala and ZIO and uses [Netty](https://netty.io/) as its core. +ZIO HTTP has powerful functional domains which help in creating, modifying, composing apps easily. Let's start with the HTTP domain. +The first step when using ZIO HTTP is creating an HTTP app. + ## Http +`Http` is a domain that models HTTP apps using ZIO and works over any request and response types. `Http` Domain provides different constructors to create HTTP apps, `Http.text`, `Http.html`, `Http.fromFile`, `Http.fromData`, `Http.fromStream`, `Http.fromEffect`. + ### Creating a "_Hello World_" app +Creating an HTTP app using ZIO Http is as simple as given below, this app will always respond with "Hello World!" + ```scala import zhttp.http._ val app = Http.text("Hello World!") ``` - -An application can be made using any of the available operators on `zhttp.Http`. In the above program for any Http request, the response is always `"Hello World!"`. +An app can be made using any of the available constructors on `zhttp.Http`. ### Routing -```scala + For handling routes, Http Domain has a `collect` method that, accepts different requests and produces responses. Pattern matching on the route is supported by the framework +The example below shows how to create routes: + +```scala, import zhttp.http._ val app = Http.collect[Request] { @@ -26,11 +36,19 @@ val app = Http.collect[Request] { case Method.GET -> !! / "fruits" / "b" => Response.text("Banana") } ``` - -Pattern matching on route is supported by the framework +You can create typed routes as well. The below example shows how to accept count as `Int` only. + ```scala, + import zhttp.http._ + + val app = Http.collect[Request] { + case Method.GET -> !! / "Apple" / int(count) => Response.text(s"Apple: $count") + } + ``` ### Composition +HTTP app can be composed using the `++` operator. The way it works is if none of the routes matches in `a` or there is an error `a`, the control is passed to the `b` app. + ```scala import zhttp.http._ @@ -44,16 +62,18 @@ Apps can be composed using the `++` operator. The way it works is, if none of th ### ZIO Integration +For creating effectful apps, you can use `collectZIO` and wrap `Response` using `wrapZIO` to produce ZIO effect value. + ```scala val app = Http.collectZIO[Request] { case Method.GET -> !! / "hello" => Response.text("Hello World").wrapZIO } ``` -`Http.collectZIO` allow routes to return a ZIO effect value. - ### Accessing the Request +To access the request use `@` as it binds a matched pattern to a variable and can be used while creating a response. + ```scala import zhttp.http._ @@ -79,16 +99,24 @@ object Spec extends DefaultRunnableSpec { testM("should be ok") { val app = Http.ok val req = Request() - assertM(app(req))(equalTo(Response.ok)) // an apply method is added via `zhttp.test` package + assertM(app(req))(equalTo(Response.ok)) } ) } ``` +When we call the `app` with the `request` it calls the apply method of `Http` via `zhttp.test` package ## Socket +`Socket` is functional domain in ZIO HTTP. It provides constructors to create socket apps. +A socket app is an app that handles WebSocket connections. + ### Creating a socket app +Socket app can be created by using `Socket` constructors. To create a socket app, you need to create a socket that accepts `WebSocketFrame` and produces `ZStream` of `WebSocketFrame`. +Finally, we need to convert socketApp to `Response` using `toResponse`, so that we can run it like any other HTTP app. +The below example shows a simple socket app, we are using `collect` which returns a stream with WebsSocketTextFrame "BAR" on receiving WebsSocketTextFrame "FOO". + ```scala import zhttp.socket._ @@ -104,7 +132,12 @@ private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text(" ## Server -### Starting an Http App +As we have seen how to create HTTP apps, the only thing left is to run an HTTP server and serve requests. +ZIO HTTP provides a way to set configurations for your server. The server can be configured according to the leak detection level, request size, address etc. + +### Starting an HTTP App + +To launch our app, we need to start the server on a port. The below example shows a simple HTTP app that responds with empty content and a `200` status code, deployed on port `8090` using `Server.start`. ```scala import zhttp.http._ @@ -119,8 +152,6 @@ object HelloWorld extends App { } ``` -A simple Http app that responds with empty content and a `200` status code is deployed on port `8090` using `Server.start`. - ## Examples - [Simple Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorld.scala) From fe4424e0230d111cac178c4882b719e326daac02 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 26 Jan 2022 20:01:28 +0530 Subject: [PATCH 37/95] refactor: rename asString to encode in URI (#898) --- zio-http/src/main/scala/zhttp/http/URL.scala | 2 +- zio-http/src/main/scala/zhttp/http/middleware/Web.scala | 2 +- .../src/main/scala/zhttp/service/EncodeClientParams.scala | 2 +- .../test/scala/zhttp/http/EncodeClientRequestSpec.scala | 4 ++-- zio-http/src/test/scala/zhttp/http/URLSpec.scala | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index af54863417..fb11f3cfa7 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -28,7 +28,7 @@ final case class URL( case _ => self.copy(kind = URL.Location.Relative) } - def asString: String = URL.asString(self) + def encode: String = URL.asString(self) } object URL { sealed trait Location diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala index 9dee5307c7..d457861cb4 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala @@ -40,7 +40,7 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht for { end <- clock.nanoTime _ <- console - .putStrLn(s"${response.status.asJava.code()} ${method} ${url.asString} ${(end - start) / 1000000}ms") + .putStrLn(s"${response.status.asJava.code()} ${method} ${url.encode} ${(end - start) / 1000000}ms") .mapError(Option(_)) } yield Patch.empty } diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index eb9c935b3a..f9de469a08 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -14,7 +14,7 @@ trait EncodeClientParams { // As per the spec, the path should contain only the relative path. // Host and port information should be in the headers. - val path = url.relative.asString + val path = url.relative.encode val content = req.getBodyAsString match { case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index 6d2ebc5b24..b69a33246d 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -46,13 +46,13 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientPara testM("uri") { check(anyClientParam) { params => val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.relative.asString)) + assert(req.uri())(equalTo(params.url.relative.encode)) } } + testM("uri on HttpData.File") { check(HttpGen.clientParamsForFileHttpData()) { params => val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.relative.asString)) + assert(req.uri())(equalTo(params.url.relative.encode)) } } } + diff --git a/zio-http/src/test/scala/zhttp/http/URLSpec.scala b/zio-http/src/test/scala/zhttp/http/URLSpec.scala index 7451b59ae8..38beb65221 100644 --- a/zio-http/src/test/scala/zhttp/http/URLSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/URLSpec.scala @@ -47,18 +47,18 @@ object URLSpec extends DefaultRunnableSpec { val asStringSpec = { def roundtrip(url: String) = - assert(URL.fromString(url).map(_.asString))(isRight(equalTo(url))) + assert(URL.fromString(url).map(_.encode))(isRight(equalTo(url))) suite("asString")( testM("using gen") { checkAll(HttpGen.url) { case url => - val source = url.asString - val decoded = URL.fromString(source).map(_.asString) + val source = url.encode + val decoded = URL.fromString(source).map(_.encode) assert(decoded)(isRight(equalTo(source))) } } + test("empty") { - val actual = URL.fromString("/").map(_.asString) + val actual = URL.fromString("/").map(_.encode) assert(actual)(isRight(equalTo("/"))) } + test("relative with pathname only") { From 9d30a4457020d2ef1e972b5a62d96c8de78d6256 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 26 Jan 2022 20:16:48 +0530 Subject: [PATCH 38/95] refactor: rename asString to encode in Scheme (#904) --- zio-http/src/main/scala/zhttp/http/Scheme.scala | 2 +- zio-http/src/main/scala/zhttp/http/URL.scala | 4 ++-- zio-http/src/main/scala/zhttp/service/Client.scala | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Scheme.scala b/zio-http/src/main/scala/zhttp/http/Scheme.scala index 14e348031b..8e6585c851 100644 --- a/zio-http/src/main/scala/zhttp/http/Scheme.scala +++ b/zio-http/src/main/scala/zhttp/http/Scheme.scala @@ -2,7 +2,7 @@ package zhttp.http import io.netty.handler.codec.http.HttpScheme sealed trait Scheme { self => - def asString: String = Scheme.asString(self) + def encode: String = Scheme.asString(self) } object Scheme { def asString(self: Scheme): String = self match { diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index fb11f3cfa7..43f4c8d2c5 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -95,8 +95,8 @@ object URL { url.kind match { case Location.Relative => path case Location.Absolute(scheme, host, port) => - if (port == 80 || port == 443) s"${scheme.asString}://$host$path" - else s"${scheme.asString}://$host:$port$path" + if (port == 80 || port == 443) s"${scheme.encode}://$host$path" + else s"${scheme.encode}://$host:$port$path" } } diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index fb9afde801..853eab2be2 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -47,7 +47,7 @@ final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: } val scheme = req.url.kind match { case Location.Relative => "" - case Location.Absolute(scheme, _, _) => scheme.asString + case Location.Absolute(scheme, _, _) => scheme.encode } val init = ClientChannelInitializer(hand, scheme, sslOption) From 470206b724efc927cc0d14ee166e2ef60ca5e90d Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Wed, 26 Jan 2022 21:46:40 +0530 Subject: [PATCH 39/95] fix: example links (#906) --- docs/website/docs/v1.x/getting-started.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index 7e1806035d..a1b321fafd 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -154,10 +154,10 @@ object HelloWorld extends App { ## Examples -- [Simple Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorld.scala) -- [Advanced Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorldAdvanced.scala) -- [WebSocket Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SocketEchoServer.scala) -- [Streaming Response](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/StreamingResponse.scala) -- [Simple Client](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SimpleClient.scala) -- [File Streaming](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/FileStreaming.scala) -- [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) +- [Simple Server](https://dream11.github.io/zio-http/docs/v1.x/examples/zio-http-basic-examples/hello-world) +- [Advanced Server](https://dream11.github.io/zio-http/docs/v1.x/examples/advanced-examples/hello-world-advanced) +- [WebSocket Server](https://dream11.github.io/zio-http/docs/v1.x/examples/zio-http-basic-examples/web-socket) +- [Streaming Response](https://dream11.github.io/zio-http/docs/v1.x/examples/advanced-examples/stream-response) +- [Simple Client](https://dream11.github.io/zio-http/docs/v1.x/examples/zio-http-basic-examples/simple-client) +- [File Streaming](https://dream11.github.io/zio-http/docs/v1.x/examples/advanced-examples/stream-file) +- [Authentication](https://dream11.github.io/zio-http/docs/v1.x/examples/advanced-examples/authentication) From 23011a91a318aa0d726ddd72b034eb43456d8679 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Wed, 26 Jan 2022 22:06:27 +0530 Subject: [PATCH 40/95] Update getting-started.md (#907) --- docs/website/docs/v1.x/getting-started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index a1b321fafd..a1b2c93542 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -28,7 +28,7 @@ An app can be made using any of the available constructors on `zhttp.Http`. For handling routes, Http Domain has a `collect` method that, accepts different requests and produces responses. Pattern matching on the route is supported by the framework The example below shows how to create routes: -```scala, +```scala import zhttp.http._ val app = Http.collect[Request] { @@ -37,7 +37,7 @@ val app = Http.collect[Request] { } ``` You can create typed routes as well. The below example shows how to accept count as `Int` only. - ```scala, + ```scala import zhttp.http._ val app = Http.collect[Request] { @@ -47,7 +47,7 @@ You can create typed routes as well. The below example shows how to accept count ### Composition -HTTP app can be composed using the `++` operator. The way it works is if none of the routes matches in `a` or there is an error `a`, the control is passed to the `b` app. +HTTP app can be composed using the `++` operator. The way it works is if none of the routes matches in `a`, the control is passed to the `b` app. ```scala import zhttp.http._ From d58857c67116281e1860a1e4a760b85e6b0ab470 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 26 Jan 2022 22:26:22 +0530 Subject: [PATCH 41/95] refactor: rename asString to encode in Scheme (#905) From f75030c432080d28f8214e589139976cab94d8fa Mon Sep 17 00:00:00 2001 From: Shubham Girdhar Date: Wed, 26 Jan 2022 23:43:34 +0530 Subject: [PATCH 42/95] Doc: setup (#886) * doc: setup * resolve: PR comments --- docs/website/docs/v1.x/index.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/website/docs/v1.x/index.md b/docs/website/docs/v1.x/index.md index 5819dcca26..1523440356 100644 --- a/docs/website/docs/v1.x/index.md +++ b/docs/website/docs/v1.x/index.md @@ -4,4 +4,23 @@ sidebar_label: "Setup" --- # Setup -Work in progress \ No newline at end of file + +In this guide, you'll learn how to get started with a new zio-http project. + +Before we dive in, make sure that you have the following on your computer: + +* JDK 1.8 or higher +* sbt (scalaVersion >= 2.12) + +## As a dependency + +To use zio-http, add the following dependencies in your project: + +```scala +val ZHTTPVersion = "1.0.0.0-RC23" + +libraryDependencies ++= Seq( + "io.d11" %% "zhttp" % ZHTTPVersion, + "io.d11" %% "zhttp-test" % ZHTTPVersion % Test +) +``` From 5e714e0a1c199544483334ca43cff36d2e70afac Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Thu, 27 Jan 2022 05:51:18 +0100 Subject: [PATCH 43/95] Update netty-incubator-transport-native-io_uring to 0.0.12.Final (#908) --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 01979e7170..6e5999d2d0 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -3,7 +3,7 @@ import sbt._ object Dependencies { val JwtCoreVersion = "9.0.3" val NettyVersion = "4.1.73.Final" - val NettyIncubatorVersion = "0.0.11.Final" + val NettyIncubatorVersion = "0.0.12.Final" val ScalaCompactCollectionVersion = "2.6.0" val ZioVersion = "1.0.13" val SttpVersion = "3.3.18" From b656936ba635b010ebac4530e289d1c847e3f64c Mon Sep 17 00:00:00 2001 From: sumawa Date: Thu, 27 Jan 2022 10:21:29 +0530 Subject: [PATCH 44/95] Documentation for Server (#885) * removed config.md and make configurations part of Server page * added server configurations * markdwon appearing fine in docusaurus generated page * added one missing configuration * Server documentation changed according to PR comments * change note to tip Co-authored-by: Sumant Awasthi Co-authored-by: amitsingh --- docs/website/docs/v1.x/dsl/server/config.md | 3 - docs/website/docs/v1.x/dsl/server/index.md | 109 ++++++++++++++++++++ 2 files changed, 109 insertions(+), 3 deletions(-) delete mode 100644 docs/website/docs/v1.x/dsl/server/config.md create mode 100644 docs/website/docs/v1.x/dsl/server/index.md diff --git a/docs/website/docs/v1.x/dsl/server/config.md b/docs/website/docs/v1.x/dsl/server/config.md deleted file mode 100644 index 50b2454a71..0000000000 --- a/docs/website/docs/v1.x/dsl/server/config.md +++ /dev/null @@ -1,3 +0,0 @@ -# Config - -Work in progress \ No newline at end of file diff --git a/docs/website/docs/v1.x/dsl/server/index.md b/docs/website/docs/v1.x/dsl/server/index.md new file mode 100644 index 0000000000..eff8c9feff --- /dev/null +++ b/docs/website/docs/v1.x/dsl/server/index.md @@ -0,0 +1,109 @@ +# ZIO HTTP Server + +This section describes, ZIO HTTP Server and different configurations you can provide while creating the Server + +## Start a ZIO HTTP Server with default configurations +```scala + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app.silent).exitCode +``` +## Start a ZIO HTTP Server with custom configurations. +1. Imports required by the customised server. + ```scala + import zhttp.http._ + import zhttp.service.server.ServerChannelFactory + import zhttp.service.{EventLoopGroup, Server} + import zio._ + import scala.util.Try + ``` +2. The Server can be built incrementally with a `++` each returning a new Server overriding any default configuration. (More properties are given in the [Server Configurations](#server-configurations) section below.) + ```scala + private val server = + Server.port(PORT) ++ // Setup port + Server.maxRequestSize(8 * 1024) ++ // handle max request size of 8 KB (default 4 KB) + Server.app(fooBar ++ app) // Setup the Http app + ``` +3. And then use ```Server.make``` to get a "managed" instance use it to run a server forever + ```scala + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + server.make + .use(start => + console.putStrLn(s"Server started on port ${start.port}") + *> ZIO.never, + ).provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(2)) + .exitCode + ``` + **Tip :** `ServerChannelFactory.auto ++ EventLoopGroup.auto(num Threads)` is supplied as an external dependency to choose netty transport type. One can leave it as `auto` to let the application handle it for you. + Also in `EventLoopGroup.auto(numThreads)` you can choose number of threads based on number of available processors. + +### Binding Server to a socket address +One can bind server to Inet address in multiple ways, either by providing a port number or +- If no port is provided, the default port is 8080 +- If specified port is 0, it will use a dynamically selected port. + +
+A complete example + +- Example below shows how the server can be started in forever mode to serve HTTP requests: + +```scala +import zhttp.http._ +import zhttp.service._ +import zhttp.service.server.ServerChannelFactory +import zio._ + +import scala.util.Try + +object HelloWorldAdvanced extends App { + // Set a port + private val PORT = 8090 + + private val fooBar: HttpApp[Any, Nothing] = Http.collect[Request] { + case Method.GET -> !! / "foo" => Response.text("bar") + case Method.GET -> !! / "bar" => Response.text("foo") + } + + private val app = Http.collectM[Request] { + case Method.GET -> !! / "random" => random.nextString(10).map(Response.text) + case Method.GET -> !! / "utc" => clock.currentDateTime.map(s => Response.text(s.toString)) + } + + private val server = + Server.port(PORT) ++ // Setup port + Server.paranoidLeakDetection ++ // Paranoid leak detection (affects performance) + Server.app(fooBar +++ app) // Setup the Http app + + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + // Configure thread count using CLI + val nThreads: Int = args.headOption.flatMap(x => Try(x.toInt).toOption).getOrElse(0) + + // Create a new server + server.make + .use(_ => + // Waiting for the server to start + console.putStrLn(s"Server started on port $PORT") + + // Ensures the server doesn't die after printing + *> ZIO.never, + ) + .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(nThreads)) + .exitCode + } +} + ``` +
+ +## Server Configurations + +| **Configuration** | **Purpose and usage** | +| ----------- | ----------- | +| `Server.app(httpApp)` | Mount routes. Refer to complete example above | +| `Server.maxRequestSize(8 * 1024)` | handle max request size of 8 KB (default 4 KB) | +| `Server.port(portNum)` or `Server.bind(portNum)` | Bind server to the port, refer to examples above | +| `Server.ssl(sslOptions)` | Creates a new server with ssl options. [HttpsHelloWorld](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/example/HttpsHelloWorld.scala) | +| `Server.acceptContinue` | Sends a [100 CONTINUE](https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3) | +| `Server.disableFlowControl` | Refer [Netty FlowControlHandler](https://netty.io/4.1/api/io/netty/handler/flow/FlowControlHandler.html) | +| `Server.disableLeakDetection` | Disable any leak detection Refer netty's [ResourceLeakDetector](https://netty.io/4.0/api/io/netty/util/ResourceLeakDetector.Level.html) | +| `Server.simpleLeakDetection` | Simplistic leak detection comes with small over head. Refer netty's [ResourceLeakDetector](https://netty.io/4.0/api/io/netty/util/ResourceLeakDetector.Level.html) | +| `Server.paranoidLeakDetection` | Comes with highest possible overhead (for testing purposes only). Refer netty's [ResourceLeakDetector](https://netty.io/4.0/api/io/netty/util/ResourceLeakDetector.Level.html) | +| `Server.consolidateFlush` | Flushing content is done in batches. Can potentially improve performance. | From 594d8cbb7b69e249a75ba00cbdc92ce3b75781d0 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 27 Jan 2022 10:27:58 +0530 Subject: [PATCH 45/95] Performance: Improve performance of `collectM` (#882) * Use ZIO response * fix: improve cancellation performance * refactor: use sticky server * refactor: reduce allocations * revert example --- build.sbt | 2 +- .../scala/zhttp/service/HttpRuntime.scala | 58 +++++++++++-------- .../src/main/scala/zhttp/service/Server.scala | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/build.sbt b/build.sbt index 36490ac34b..ebaa132997 100644 --- a/build.sbt +++ b/build.sbt @@ -124,6 +124,6 @@ lazy val zhttpTest = (project in file("zio-http-test")) lazy val example = (project in file("./example")) .settings(stdSettings("example")) .settings(publishSetting(false)) - .settings(runSettings("example.FileStreaming")) + .settings(runSettings("example.Main")) .settings(libraryDependencies ++= Seq(`jwt-core`)) .dependsOn(zhttp) diff --git a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala index 05b67735e2..2d3e0888ab 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala @@ -1,9 +1,9 @@ package zhttp.service import io.netty.channel.{ChannelHandlerContext, EventLoopGroup => JEventLoopGroup} -import io.netty.util.concurrent.{EventExecutor, Future} +import io.netty.util.concurrent.{EventExecutor, Future, GenericFutureListener} +import zio._ import zio.internal.Executor -import zio.{Exit, Runtime, URIO, ZIO} import scala.collection.mutable import scala.concurrent.{ExecutionContext => JExecutionContext} @@ -14,16 +14,23 @@ import scala.jdk.CollectionConverters._ * cancel the execution when the channel closes. */ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { - def unsafeRun(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { + val rtm = strategy.getRuntime(ctx) + + // Close the connection if the program fails + // When connection closes, interrupt the program + rtm .unsafeRunAsync(for { fiber <- program.fork - _ <- ZIO.effect { - ctx.channel().closeFuture.addListener((_: Future[_ <: Void]) => rtm.unsafeRunAsync_(fiber.interrupt): Unit) + close <- UIO { + val close = closeListener(rtm, fiber) + ctx.channel().closeFuture.addListener(close) + close } _ <- fiber.join + _ <- UIO(ctx.channel().closeFuture().removeListener(close)) } yield ()) { case Exit.Success(_) => () case Exit.Failure(cause) => @@ -31,18 +38,39 @@ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { case None => () case Some(_) => System.err.println(cause.prettyPrint) } - ctx.close() + if (ctx.channel().isOpen) ctx.close() } } + + private def closeListener(rtm: Runtime[Any], fiber: Fiber.Runtime[_, _]): GenericFutureListener[Future[_ >: Void]] = + (_: Future[_ >: Void]) => rtm.unsafeRunAsync_(fiber.interrupt): Unit } object HttpRuntime { + def dedicated[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = + Strategy.dedicated(group).map(runtime => new HttpRuntime[R](runtime)) + + def default[R]: URIO[R, HttpRuntime[R]] = + Strategy.default().map(runtime => new HttpRuntime[R](runtime)) + + def sticky[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = + Strategy.sticky(group).map(runtime => new HttpRuntime[R](runtime)) + sealed trait Strategy[R] { def getRuntime(ctx: ChannelHandlerContext): Runtime[R] } object Strategy { + def dedicated[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Dedicated(runtime, group)) + + def default[R](): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Default(runtime)) + + def sticky[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Group(runtime, group)) + case class Default[R](runtime: Runtime[R]) extends Strategy[R] { override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = runtime } @@ -73,23 +101,5 @@ object HttpRuntime { override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime.getOrElse(ctx.executor(), runtime) } - - def sticky[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Group(runtime, group)) - - def default[R](): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Default(runtime)) - - def dedicated[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Dedicated(runtime, group)) } - - def sticky[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = - Strategy.sticky(group).map(runtime => new HttpRuntime[R](runtime)) - - def dedicated[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = - Strategy.dedicated(group).map(runtime => new HttpRuntime[R](runtime)) - - def default[R]: URIO[R, HttpRuntime[R]] = - Strategy.default().map(runtime => new HttpRuntime[R](runtime)) } diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index cc2137a754..711f957734 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -215,7 +215,7 @@ object Server { for { channelFactory <- ZManaged.access[ServerChannelFactory](_.get) eventLoopGroup <- ZManaged.access[EventLoopGroup](_.get) - zExec <- HttpRuntime.default[R].toManaged_ + zExec <- HttpRuntime.sticky[R](eventLoopGroup).toManaged_ reqHandler = settings.app.compile(zExec, settings) respHandler = ServerResponseHandler(zExec, settings, ServerTimeGenerator.make) init = ServerChannelInitializer(zExec, settings, reqHandler, respHandler) From b54e9351392fe2d631548b95a6f80ce46ba9e3ab Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Thu, 27 Jan 2022 10:58:11 +0530 Subject: [PATCH 46/95] Doc: Added <> operator in getting started (#910) * fix: ++ operator doc * fix: composition --- docs/website/docs/v1.x/getting-started.md | 24 +++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index a1b2c93542..2d6e72ab8d 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -47,19 +47,31 @@ You can create typed routes as well. The below example shows how to accept count ### Composition -HTTP app can be composed using the `++` operator. The way it works is if none of the routes matches in `a`, the control is passed to the `b` app. +Apps can be composed using operators in `Http`: + +- Using the `++` operator. The way it works is, if none of the routes match in `a`, then the control is passed on to the `b` app. + +```scala + import zhttp.http._ + + val a = Http.collect[Request] { case Method.GET -> !! / "a" => Response.ok } + val b = Http.collect[Request] { case Method.GET -> !! / "b" => Response.ok } + + val app = a ++ b + ``` + + +- Using the `<>` operator. The way it works is, if `a` fails, then the control is passed on to the `b` app. ```scala import zhttp.http._ -val a = Http.collect[Request] { case Method.GET -> !! / "a" => Response.ok } -val b = Http.collect[Request] { case Method.GET -> !! / "b" => Response.ok } +val a = Http.fail(new Error("SERVER_ERROR")) +val b = Http.text("OK") -val app = a ++ b +val app = a <> b ``` -Apps can be composed using the `++` operator. The way it works is, if none of the routes match in `a` , then the control is passed on to the `b` app. - ### ZIO Integration For creating effectful apps, you can use `collectZIO` and wrap `Response` using `wrapZIO` to produce ZIO effect value. From 8e73e9ee7e87034d553e179ab127b87c76cfb5e2 Mon Sep 17 00:00:00 2001 From: James Beem Date: Thu, 27 Jan 2022 04:49:25 -0500 Subject: [PATCH 47/95] feature: Add `collectManaged` to Http (#909) * Add collectManaged * comment typo --- zio-http/src/main/scala/zhttp/http/Http.scala | 15 +++++++++++++++ zio-http/src/test/scala/zhttp/http/HttpSpec.scala | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index da986539c8..566ec45fa7 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -102,6 +102,11 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => ): Http[R1, E1, A1, C] = self >>> Http.collectZIO(pf) + final def collectManaged[R1 <: R, E1 >: E, A1 <: A, B1 >: B, C]( + pf: PartialFunction[B1, ZManaged[R1, E1, C]], + ): Http[R1, E1, A1, C] = + self >>> Http.collectManaged(pf) + /** * Named alias for `<<<` */ @@ -465,6 +470,11 @@ object Http { */ def collectZIO[A]: Http.PartialCollectZIO[A] = Http.PartialCollectZIO(()) + /** + * Creates an Http app which accepts a request and produces response from a managed resource + */ + def collectManaged[A]: Http.PartialCollectManaged[A] = Http.PartialCollectManaged(()) + /** * Combines multiple Http apps into one */ @@ -619,6 +629,11 @@ object Http { Http.collect[A] { case a if pf.isDefinedAt(a) => Http.fromZIO(pf(a)) }.flatten } + final case class PartialCollectManaged[A](unit: Unit) extends AnyVal { + def apply[R, E, B](pf: PartialFunction[A, ZManaged[R, E, B]]): Http[R, E, A, B] = + Http.collect[A] { case a if pf.isDefinedAt(a) => Http.fromZIO(pf(a).useNow) }.flatten + } + final case class PartialCollect[A](unit: Unit) extends AnyVal { def apply[B](pf: PartialFunction[A, B]): Http[Any, Nothing, A, B] = Collect(pf) } diff --git a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala index 944656f5f0..7fcaa2fd48 100644 --- a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala @@ -114,6 +114,11 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { val actual = a.execute(1) assert(actual)(isEffect) } + + test("should resolve managed") { + val a = Http.collectManaged[Int] { case 1 => ZManaged.succeed("A") } + val actual = a.execute(1) + assert(actual)(isEffect) + } + test("should resolve second effect") { val a = Http.empty.flatten val b = Http.succeed("B") From 0a3d486edc9bb83c1fab637c0d9c8c51f5ccc5de Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 27 Jan 2022 19:08:40 +0530 Subject: [PATCH 48/95] feature: add `echo` operator to `Socket` (#900) --- .../src/main/scala/zhttp/socket/Socket.scala | 6 ++ .../test/scala/zhttp/socket/SocketSpec.scala | 70 +++++++++++-------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 54190c52eb..1833aa031d 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -57,8 +57,14 @@ sealed trait Socket[-R, +E, -A, +B] { self => } object Socket { + def collect[A]: PartialCollect[A] = new PartialCollect[A](()) + /** + * Simply echos the incoming message back + */ + def echo[A]: Socket[Any, Nothing, A, A] = Socket.collect[A] { case a => ZStream.succeed(a) } + def end: ZStream[Any, Nothing, Nothing] = ZStream.halt(Cause.empty) def fromFunction[A]: PartialFromFunction[A] = new PartialFromFunction[A](()) diff --git a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala index 6313830056..04109fa95c 100644 --- a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala +++ b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala @@ -1,17 +1,19 @@ package zhttp.socket import zio._ +import zio.duration.durationInt import zio.stream.ZStream import zio.test.Assertion._ +import zio.test.TestAspect.timeout import zio.test._ object SocketSpec extends DefaultRunnableSpec { def spec = suite("SocketSpec") { - OperationsSpec - } + operationsSpec + } @@ timeout(5 seconds) - def OperationsSpec = suite("Operations Spec") { + def operationsSpec = suite("OperationsSpec") { testM("fromStream provide") { val text = "Cat ipsum dolor sit amet" val environment = ZStream.environment[String] @@ -23,38 +25,44 @@ object SocketSpec extends DefaultRunnableSpec { assertM(socket.runCollect) { equalTo(Chunk(text)) } - } + testM("fromFunction provide") { - val environmentFunction = (_: Any) => ZStream.environment[WebSocketFrame] - val socket = Socket - .fromFunction(environmentFunction) - .provide(WebSocketFrame.text("Foo")) - .execute(WebSocketFrame.text("Bar")) + } + + testM("fromFunction provide") { + val environmentFunction = (_: Any) => ZStream.environment[WebSocketFrame] + val socket = Socket + .fromFunction(environmentFunction) + .provide(WebSocketFrame.text("Foo")) + .execute(WebSocketFrame.text("Bar")) - assertM(socket.runCollect) { - equalTo(Chunk(WebSocketFrame.text("Foo"))) - } - } + testM("collect provide") { - val environment = ZStream.environment[WebSocketFrame] - val socket = Socket - .collect[WebSocketFrame] { case WebSocketFrame.Pong => - environment + assertM(socket.runCollect) { + equalTo(Chunk(WebSocketFrame.text("Foo"))) } - .provide(WebSocketFrame.ping) - .execute(WebSocketFrame.pong) + } + + testM("collect provide") { + val environment = ZStream.environment[WebSocketFrame] + val socket = Socket + .collect[WebSocketFrame] { case WebSocketFrame.Pong => + environment + } + .provide(WebSocketFrame.ping) + .execute(WebSocketFrame.pong) - assertM(socket.runCollect) { - equalTo(Chunk(WebSocketFrame.ping)) - } - } + testM("ordered provide") { - val socket = Socket.collect[Int] { case _ => - ZStream.environment[Int] - } + assertM(socket.runCollect) { + equalTo(Chunk(WebSocketFrame.ping)) + } + } + + testM("ordered provide") { + val socket = Socket.collect[Int] { case _ => + ZStream.environment[Int] + } - val socketA: Socket[Int, Nothing, Int, Int] = socket.provide(12) - val socketB: Socket[Int, Nothing, Int, Int] = socketA.provide(1) - val socketC: Socket[Any, Nothing, Int, Int] = socketB.provide(42) + val socketA: Socket[Int, Nothing, Int, Int] = socket.provide(12) + val socketB: Socket[Int, Nothing, Int, Int] = socketA.provide(1) + val socketC: Socket[Any, Nothing, Int, Int] = socketB.provide(42) - assertM(socketC.execute(1000).runCollect)(equalTo(Chunk(12))) - } + assertM(socketC.execute(1000).runCollect)(equalTo(Chunk(12))) + } + + testM("echo") { + assertM(Socket.echo(1).runCollect)(equalTo(Chunk(1))) + } } } From cfa6c3e7b2666777eb334585a4d6a2f3a346f2b5 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 27 Jan 2022 19:36:06 +0530 Subject: [PATCH 49/95] feature: add `Socket.empty` (#901) * feature: add `Socket.empty` * test: add unit test case for Socket#empty Co-authored-by: Shubham Girdhar --- zio-http/src/main/scala/zhttp/socket/Socket.scala | 8 ++++++++ zio-http/src/test/scala/zhttp/socket/SocketSpec.scala | 3 +++ 2 files changed, 11 insertions(+) diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 1833aa031d..2bdefef9a7 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -21,6 +21,7 @@ sealed trait Socket[-R, +E, -A, +B] { self => case FMerge(sa, sb) => sa(a) merge sb(a) case Succeed(a) => ZStream.succeed(a) case Provide(s, r) => s(a).asInstanceOf[ZStream[R, E, B]].provide(r.asInstanceOf[R]) + case Empty => ZStream.empty } def contramap[Z](za: Z => A): Socket[R, E, Z, B] = Socket.FCMap(self, za) @@ -65,6 +66,11 @@ object Socket { */ def echo[A]: Socket[Any, Nothing, A, A] = Socket.collect[A] { case a => ZStream.succeed(a) } + /** + * Creates a socket that doesn't do anything. + */ + def empty: Socket[Any, Nothing, Any, Nothing] = Socket.Empty + def end: ZStream[Any, Nothing, Nothing] = ZStream.halt(Cause.empty) def fromFunction[A]: PartialFromFunction[A] = new PartialFromFunction[A](()) @@ -108,4 +114,6 @@ object Socket { private final case class Provide[R, E, A, B](s: Socket[R, E, A, B], r: R) extends Socket[Any, E, A, B] private case object End extends Socket[Any, Nothing, Any, Nothing] + + private case object Empty extends Socket[Any, Nothing, Any, Nothing] } diff --git a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala index 04109fa95c..68adc4f7eb 100644 --- a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala +++ b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala @@ -63,6 +63,9 @@ object SocketSpec extends DefaultRunnableSpec { } + testM("echo") { assertM(Socket.echo(1).runCollect)(equalTo(Chunk(1))) + } + + testM("empty") { + assertM(Socket.empty(()).runCollect)(isEmpty) } } } From 36f8c83155d6f59a693c036932ce4cf661e7799e Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 27 Jan 2022 20:27:08 +0530 Subject: [PATCH 50/95] feature: add `toHttp` to Socket.scala (#902) * feature: add `toHttp` to Socket.scala * test: add unit test for `toApp` to Socket.scala Co-authored-by: Shubham Girdhar --- .../src/main/scala/zhttp/socket/Socket.scala | 7 ++++++- .../test/scala/zhttp/socket/SocketSpec.scala | 17 ++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 2bdefef9a7..0cf086c7af 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -1,6 +1,6 @@ package zhttp.socket -import zhttp.http.Response +import zhttp.http.{Http, Response} import zio.stream.ZStream import zio.{Cause, NeedsEnv, ZIO} @@ -44,6 +44,11 @@ sealed trait Socket[-R, +E, -A, +B] { self => */ def provide(r: R)(implicit env: NeedsEnv[R]): Socket[Any, E, A, B] = Provide(self, r) + /** + * Converts the Socket into an Http + */ + def toHttp(implicit ev: IsWebSocket[R, E, A, B]): Http[R, E, Any, Response] = Http.fromZIO(toResponse) + /** * Creates a response from the socket. */ diff --git a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala index 68adc4f7eb..b0889fadf2 100644 --- a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala +++ b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala @@ -1,5 +1,6 @@ package zhttp.socket +import zhttp.http.Status import zio._ import zio.duration.durationInt import zio.stream.ZStream @@ -22,9 +23,7 @@ object SocketSpec extends DefaultRunnableSpec { .provide(text) .execute("") - assertM(socket.runCollect) { - equalTo(Chunk(text)) - } + assertM(socket.runCollect)(equalTo(Chunk(text))) } + testM("fromFunction provide") { val environmentFunction = (_: Any) => ZStream.environment[WebSocketFrame] @@ -33,9 +32,7 @@ object SocketSpec extends DefaultRunnableSpec { .provide(WebSocketFrame.text("Foo")) .execute(WebSocketFrame.text("Bar")) - assertM(socket.runCollect) { - equalTo(Chunk(WebSocketFrame.text("Foo"))) - } + assertM(socket.runCollect)(equalTo(Chunk(WebSocketFrame.text("Foo")))) } + testM("collect provide") { val environment = ZStream.environment[WebSocketFrame] @@ -46,9 +43,7 @@ object SocketSpec extends DefaultRunnableSpec { .provide(WebSocketFrame.ping) .execute(WebSocketFrame.pong) - assertM(socket.runCollect) { - equalTo(Chunk(WebSocketFrame.ping)) - } + assertM(socket.runCollect)(equalTo(Chunk(WebSocketFrame.ping))) } + testM("ordered provide") { val socket = Socket.collect[Int] { case _ => @@ -66,6 +61,10 @@ object SocketSpec extends DefaultRunnableSpec { } + testM("empty") { assertM(Socket.empty(()).runCollect)(isEmpty) + } + + testM("toHttp") { + val http = Socket.succeed(WebSocketFrame.ping).toHttp + assertM(http(()).map(_.status))(equalTo(Status.SWITCHING_PROTOCOLS)) } } } From fc8b9b5a155e7c59b548d191265d30e0e6b61d8b Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 27 Jan 2022 20:38:38 +0530 Subject: [PATCH 51/95] refactor: merge Request for Client and Server (#894) --- .../src/main/scala/zhttp/http/Request.scala | 4 +- .../src/main/scala/zhttp/service/Client.scala | 63 ++++---------- .../zhttp/service/EncodeClientParams.scala | 58 ++++++------- .../zhttp/http/EncodeClientRequestSpec.scala | 83 ------------------ .../scala/zhttp/http/EncodeRequestSpec.scala | 85 +++++++++++++++++++ .../zhttp/http/GetBodyAsStringSpec.scala | 30 +++---- .../test/scala/zhttp/internal/HttpGen.scala | 7 +- .../zhttp/internal/HttpRunnableSpec.scala | 11 +-- 8 files changed, 152 insertions(+), 189 deletions(-) delete mode 100644 zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala create mode 100644 zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala diff --git a/zio-http/src/main/scala/zhttp/http/Request.scala b/zio-http/src/main/scala/zhttp/http/Request.scala index a930ea5ed5..e78be8918b 100644 --- a/zio-http/src/main/scala/zhttp/http/Request.scala +++ b/zio-http/src/main/scala/zhttp/http/Request.scala @@ -95,8 +95,8 @@ object Request { method: Method = Method.GET, url: URL = URL.root, headers: Headers = Headers.empty, - remoteAddress: Option[InetAddress] = None, data: HttpData = HttpData.Empty, + remoteAddress: Option[InetAddress] = None, ): Request = { val m = method val u = url @@ -121,7 +121,7 @@ object Request { remoteAddress: Option[InetAddress], content: HttpData = HttpData.empty, ): UIO[Request] = - UIO(Request(method, url, headers, remoteAddress, content)) + UIO(Request(method, url, headers, content, remoteAddress)) /** * Lift request to TypedRequest with option to extract params diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 853eab2be2..40beb22f0f 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -2,42 +2,38 @@ package zhttp.service import io.netty.bootstrap.Bootstrap import io.netty.buffer.{ByteBuf, ByteBufUtil} -import io.netty.channel.{ - Channel, - ChannelFactory => JChannelFactory, - ChannelHandlerContext, - EventLoopGroup => JEventLoopGroup, -} -import io.netty.handler.codec.http.HttpVersion +import io.netty.channel.{Channel, ChannelFactory => JChannelFactory, EventLoopGroup => JEventLoopGroup} +import io.netty.handler.codec.http.{FullHttpRequest, HttpVersion} import zhttp.http.URL.Location import zhttp.http._ import zhttp.http.headers.HeaderExtension import zhttp.service -import zhttp.service.Client.{ClientRequest, ClientResponse} +import zhttp.service.Client.ClientResponse import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.client.{ClientChannelInitializer, ClientInboundHandler} import zio.{Chunk, Promise, Task, ZIO} -import java.net.{InetAddress, InetSocketAddress} +import java.net.InetSocketAddress final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: JEventLoopGroup) extends HttpMessageCodec { def request( - request: Client.ClientRequest, + request: Request, sslOption: ClientSSLOptions = ClientSSLOptions.DefaultSSL, ): Task[Client.ClientResponse] = for { promise <- Promise.make[Throwable, Client.ClientResponse] - _ <- Task(asyncRequest(request, promise, sslOption)).catchAll(cause => promise.fail(cause)) + jReq <- encodeClientParams(HttpVersion.HTTP_1_1, request) + _ <- Task(asyncRequest(request, jReq, promise, sslOption)).catchAll(cause => promise.fail(cause)) res <- promise.await } yield res private def asyncRequest( - req: ClientRequest, + req: Request, + jReq: FullHttpRequest, promise: Promise[Throwable, ClientResponse], sslOption: ClientSSLOptions, ): Unit = { - val jReq = encodeClientParams(HttpVersion.HTTP_1_1, req) try { val hand = ClientInboundHandler(rtm, jReq, promise) val host = req.url.host @@ -111,14 +107,14 @@ object Client { method: Method, url: URL, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url)) + request(Request(method, url)) def request( method: Method, url: URL, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url), sslOptions) + request(Request(method, url), sslOptions) def request( method: Method, @@ -126,7 +122,7 @@ object Client { headers: Headers, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url, headers), sslOptions) + request(Request(method, url, headers), sslOptions) def request( method: Method, @@ -134,48 +130,19 @@ object Client { headers: Headers, content: HttpData, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url, headers, content)) + request(Request(method, url, headers, content, None)) def request( - req: ClientRequest, + req: Request, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req)) def request( - req: ClientRequest, + req: Request, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req, sslOptions)) - final case class ClientRequest( - method: Method, - url: URL, - getHeaders: Headers = Headers.empty, - data: HttpData = HttpData.empty, - private val channelContext: ChannelHandlerContext = null, - ) extends HeaderExtension[ClientRequest] { self => - - def getBodyAsString: Option[String] = data match { - case HttpData.Text(text, _) => Some(text) - case HttpData.BinaryChunk(data) => Some(new String(data.toArray, HTTP_CHARSET)) - case HttpData.BinaryByteBuf(data) => Some(data.toString(HTTP_CHARSET)) - case _ => Option.empty - } - - def remoteAddress: Option[InetAddress] = { - if (channelContext != null && channelContext.channel().remoteAddress().isInstanceOf[InetSocketAddress]) - Some(channelContext.channel().remoteAddress().asInstanceOf[InetSocketAddress].getAddress) - else - None - } - - /** - * Updates the headers using the provided function - */ - override def updateHeaders(update: Headers => Headers): ClientRequest = - self.copy(getHeaders = update(self.getHeaders)) - } - final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) extends HeaderExtension[ClientResponse] { self => diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index f9de469a08..ca5d4b4807 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -1,41 +1,37 @@ package zhttp.service -import io.netty.buffer.Unpooled import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames, HttpVersion} -import zhttp.http.HTTP_CHARSET +import zhttp.http.Request +import zio.Task trait EncodeClientParams { /** * Converts client params to JFullHttpRequest */ - def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { - val method = req.method.asHttpMethod - val url = req.url - - // As per the spec, the path should contain only the relative path. - // Host and port information should be in the headers. - val path = url.relative.encode - - val content = req.getBodyAsString match { - case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) - case None => Unpooled.EMPTY_BUFFER - } - - val encodedReqHeaders = req.getHeaders.encode - - val headers = url.host match { - case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) - case None => encodedReqHeaders - } - - val writerIndex = content.writerIndex() - if (writerIndex != 0) { - headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) - } - // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. - val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) - jReq.headers().set(headers) - - jReq + def encodeClientParams(jVersion: HttpVersion, req: Request): Task[FullHttpRequest] = req.getBodyAsByteBuf.map { + content => + val method = req.method.asHttpMethod + val url = req.url + + // As per the spec, the path should contain only the relative path. + // Host and port information should be in the headers. + val path = url.relative.encode + + val encodedReqHeaders = req.getHeaders.encode + + val headers = url.host match { + case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) + case None => encodedReqHeaders + } + + val writerIndex = content.writerIndex() + if (writerIndex != 0) { + headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) + } + // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. + val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) + jReq.headers().set(headers) + + jReq } } diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala deleted file mode 100644 index b69a33246d..0000000000 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ /dev/null @@ -1,83 +0,0 @@ -package zhttp.http - -import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} -import zhttp.internal.HttpGen -import zhttp.service.{Client, EncodeClientParams} -import zio.random.Random -import zio.test.Assertion._ -import zio.test._ - -object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientParams { - - val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( - HttpGen.httpData( - Gen.listOf(Gen.alphaNumericString), - ), - ) - - val clientParamWithAbsoluteUrl = HttpGen.clientRequest( - dataGen = HttpGen.httpData( - Gen.listOf(Gen.alphaNumericString), - ), - urlGen = HttpGen.genAbsoluteURL, - ) - - def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( - for { - content <- Gen.alphaNumericStringBounded(size, size) - data <- Gen.fromIterable(List(HttpData.fromString(content))) - } yield data, - ) - - def spec = suite("EncodeClientParams") { - testM("method") { - check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.method())(equalTo(params.method.asHttpMethod)) - } - } + - testM("method on HttpData.File") { - check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.method())(equalTo(params.method.asHttpMethod)) - } - } + - suite("uri") { - testM("uri") { - check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.relative.encode)) - } - } + - testM("uri on HttpData.File") { - check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.uri())(equalTo(params.url.relative.encode)) - } - } - } + - testM("content-length") { - check(clientParamWithFiniteData(5)) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - assert(req.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong)(equalTo(5L)) - } - } + - testM("host header") { - check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - val hostHeader = HttpHeaderNames.HOST - assert(Option(req.headers().get(hostHeader)))(equalTo(params.url.host)) - } - } + - testM("host header when absolute url") { - check(clientParamWithAbsoluteUrl) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) - val reqHeaders = req.headers() - val hostHeader = HttpHeaderNames.HOST - - assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && - assert(Option(reqHeaders.get(hostHeader)))(equalTo(params.url.host)) - } - } - } -} diff --git a/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala new file mode 100644 index 0000000000..0dcf1c3b5e --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala @@ -0,0 +1,85 @@ +package zhttp.http + +import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} +import zhttp.internal.HttpGen +import zhttp.service.EncodeClientParams +import zio.random.Random +import zio.test.Assertion._ +import zio.test._ + +object EncodeRequestSpec extends DefaultRunnableSpec with EncodeClientParams { + + val anyClientParam: Gen[Random with Sized, Request] = HttpGen.clientRequest( + HttpGen.httpData( + Gen.listOf(Gen.alphaNumericString), + ), + ) + + val clientParamWithAbsoluteUrl = HttpGen.clientRequest( + dataGen = HttpGen.httpData( + Gen.listOf(Gen.alphaNumericString), + ), + urlGen = HttpGen.genAbsoluteURL, + ) + + def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Request] = HttpGen.clientRequest( + for { + content <- Gen.alphaNumericStringBounded(size, size) + data <- Gen.fromIterable(List(HttpData.fromString(content))) + } yield data, + ) + + def spec = suite("EncodeClientParams") { + testM("method") { + checkM(anyClientParam) { params => + val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) + assertM(method)(equalTo(params.method.asHttpMethod)) + } + } + + testM("method on HttpData.File") { + checkM(HttpGen.clientParamsForFileHttpData()) { params => + val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) + assertM(method)(equalTo(params.method.asHttpMethod)) + } + } + + suite("uri") { + testM("uri") { + checkM(anyClientParam) { params => + val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) + assertM(uri)(equalTo(params.url.relative.encode)) + } + } + + testM("uri on HttpData.File") { + checkM(HttpGen.clientParamsForFileHttpData()) { params => + val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) + assertM(uri)(equalTo(params.url.relative.encode)) + } + } + } + + testM("content-length") { + checkM(clientParamWithFiniteData(5)) { params => + val len = encodeClientParams(HttpVersion.HTTP_1_1, params).map( + _.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong, + ) + assertM(len)(equalTo(5L)) + } + } + + testM("host header") { + checkM(anyClientParam) { params => + val hostHeader = HttpHeaderNames.HOST + val headers = encodeClientParams(HttpVersion.HTTP_1_1, params).map(h => Option(h.headers().get(hostHeader))) + assertM(headers)(equalTo(params.url.host)) + } + } + + testM("host header when absolute url") { + checkM(clientParamWithAbsoluteUrl) { params => + val hostHeader = HttpHeaderNames.HOST + for { + reqHeaders <- encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.headers()) + } yield assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && assert(Option(reqHeaders.get(hostHeader)))( + equalTo(params.url.host), + ) + } + } + } +} diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index aad22542d1..bd3da3cc7e 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -1,7 +1,6 @@ package zhttp.http import io.netty.handler.codec.http.HttpHeaderNames -import zhttp.service.Client import zio.Chunk import zio.test.Assertion._ import zio.test._ @@ -16,27 +15,26 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { val charsetGen: Gen[Any, Charset] = Gen.fromIterable(List(UTF_8, UTF_16, UTF_16BE, UTF_16LE, US_ASCII, ISO_8859_1)) - check(charsetGen) { charset => - val encoded = Client - .ClientRequest( - Method.GET, - URL(Path("/")), - getHeaders = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), - data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes())), - ) - .getBodyAsString - val actual = Option(new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset)) + checkM(charsetGen) { charset => + val encoded = Request( + Method.GET, + URL(Path("/")), + headers = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), + data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes(charset))), + ).getBodyAsString - assert(actual)(equalTo(encoded)) + val expected = new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset) + + assertM(encoded)(equalTo(expected)) } } + - test("should map bytes to default utf-8 if no charset given") { + testM("should map bytes to default utf-8 if no charset given") { val data = Chunk.fromArray("abc".getBytes()) val content = HttpData.BinaryChunk(data) - val request = Client.ClientRequest(Method.GET, URL(Path("/")), data = content) + val request = Request(Method.GET, URL(Path("/")), data = content) val encoded = request.getBodyAsString - val actual = Option(new String(data.toArray, HTTP_CHARSET)) - assert(actual)(equalTo(encoded)) + val actual = new String(data.toArray, HTTP_CHARSET) + assertM(encoded)(equalTo(actual)) }, ) } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 996deb4d4a..5b06448608 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -3,7 +3,6 @@ package zhttp.internal import io.netty.buffer.Unpooled import zhttp.http.URL.Location import zhttp.http._ -import zhttp.service.Client.ClientRequest import zio.random.Random import zio.stream.ZStream import zio.test.{Gen, Sized} @@ -23,7 +22,7 @@ object HttpGen { url <- urlGen headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen - } yield ClientRequest(method, url, headers, data) + } yield Request(method, url, headers, data, None) def clientParamsForFileHttpData() = { for { @@ -31,7 +30,7 @@ object HttpGen { method <- HttpGen.method url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) - } yield ClientRequest(method, url, headers, HttpData.fromFile(file)) + } yield Request(method, url, headers, HttpData.fromFile(file), None) } def cookies: Gen[Random with Sized, Cookie] = for { @@ -119,7 +118,7 @@ object HttpGen { url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) data <- HttpGen.httpData(Gen.listOf(Gen.alphaNumericString)) - } yield Request(method, url, headers, None, data) + } yield Request(method, url, headers, data, None) def response[R](gContent: Gen[R, List[String]]): Gen[Random with Sized with R, Response] = { for { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 1642799a76..5718e794c4 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -21,7 +21,7 @@ import zio.{Has, Task, ZIO, ZManaged} */ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => - implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Client.ClientRequest, A]) { + implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Request, A]) { /** * Runs the deployed Http app by making a real http request to it. The method allows us to configure individual @@ -34,11 +34,12 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => headers: Headers = Headers.empty, ): ZIO[R, Throwable, A] = app( - Client.ClientRequest( + Request( method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", 0)), headers, HttpData.fromString(content), + None, ), ).catchAll { case Some(value) => ZIO.fail(value) @@ -58,7 +59,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => for { port <- Http.fromZIO(DynamicServer.getPort) id <- Http.fromZIO(DynamicServer.deploy(app)) - response <- Http.fromFunctionZIO[Client.ClientRequest] { params => + response <- Http.fromFunctionZIO[Request] { params => Client.request( params .addHeader(DynamicServer.APP_ID, id) @@ -74,7 +75,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => def deployWebSocket: HttpTestClient[SttpClient, client3.Response[Either[String, WebSocket[Task]]]] = for { id <- Http.fromZIO(DynamicServer.deploy(app)) res <- - Http.fromFunctionZIO[Client.ClientRequest](params => + Http.fromFunctionZIO[Request](params => for { port <- DynamicServer.getPort url = s"ws://localhost:$port${params.url.path.asString}" @@ -117,7 +118,7 @@ object HttpRunnableSpec { Http[ R with EventLoopGroup with ChannelFactory with DynamicServer with ServerChannelFactory, Throwable, - Client.ClientRequest, + Request, A, ] } From 91db176da235dc301be0e4884ac77a78c01bed59 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Fri, 28 Jan 2022 12:01:26 +0530 Subject: [PATCH 52/95] Revert "refactor: merge Request for Client and Server (#894)" (#915) This reverts commit fc8b9b5a155e7c59b548d191265d30e0e6b61d8b. --- .../src/main/scala/zhttp/http/Request.scala | 4 +- .../src/main/scala/zhttp/service/Client.scala | 63 ++++++++++---- .../zhttp/service/EncodeClientParams.scala | 58 +++++++------ .../zhttp/http/EncodeClientRequestSpec.scala | 83 ++++++++++++++++++ .../scala/zhttp/http/EncodeRequestSpec.scala | 85 ------------------- .../zhttp/http/GetBodyAsStringSpec.scala | 30 ++++--- .../test/scala/zhttp/internal/HttpGen.scala | 7 +- .../zhttp/internal/HttpRunnableSpec.scala | 11 ++- 8 files changed, 189 insertions(+), 152 deletions(-) create mode 100644 zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala delete mode 100644 zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala diff --git a/zio-http/src/main/scala/zhttp/http/Request.scala b/zio-http/src/main/scala/zhttp/http/Request.scala index e78be8918b..a930ea5ed5 100644 --- a/zio-http/src/main/scala/zhttp/http/Request.scala +++ b/zio-http/src/main/scala/zhttp/http/Request.scala @@ -95,8 +95,8 @@ object Request { method: Method = Method.GET, url: URL = URL.root, headers: Headers = Headers.empty, - data: HttpData = HttpData.Empty, remoteAddress: Option[InetAddress] = None, + data: HttpData = HttpData.Empty, ): Request = { val m = method val u = url @@ -121,7 +121,7 @@ object Request { remoteAddress: Option[InetAddress], content: HttpData = HttpData.empty, ): UIO[Request] = - UIO(Request(method, url, headers, content, remoteAddress)) + UIO(Request(method, url, headers, remoteAddress, content)) /** * Lift request to TypedRequest with option to extract params diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 40beb22f0f..853eab2be2 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -2,38 +2,42 @@ package zhttp.service import io.netty.bootstrap.Bootstrap import io.netty.buffer.{ByteBuf, ByteBufUtil} -import io.netty.channel.{Channel, ChannelFactory => JChannelFactory, EventLoopGroup => JEventLoopGroup} -import io.netty.handler.codec.http.{FullHttpRequest, HttpVersion} +import io.netty.channel.{ + Channel, + ChannelFactory => JChannelFactory, + ChannelHandlerContext, + EventLoopGroup => JEventLoopGroup, +} +import io.netty.handler.codec.http.HttpVersion import zhttp.http.URL.Location import zhttp.http._ import zhttp.http.headers.HeaderExtension import zhttp.service -import zhttp.service.Client.ClientResponse +import zhttp.service.Client.{ClientRequest, ClientResponse} import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.client.{ClientChannelInitializer, ClientInboundHandler} import zio.{Chunk, Promise, Task, ZIO} -import java.net.InetSocketAddress +import java.net.{InetAddress, InetSocketAddress} final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: JEventLoopGroup) extends HttpMessageCodec { def request( - request: Request, + request: Client.ClientRequest, sslOption: ClientSSLOptions = ClientSSLOptions.DefaultSSL, ): Task[Client.ClientResponse] = for { promise <- Promise.make[Throwable, Client.ClientResponse] - jReq <- encodeClientParams(HttpVersion.HTTP_1_1, request) - _ <- Task(asyncRequest(request, jReq, promise, sslOption)).catchAll(cause => promise.fail(cause)) + _ <- Task(asyncRequest(request, promise, sslOption)).catchAll(cause => promise.fail(cause)) res <- promise.await } yield res private def asyncRequest( - req: Request, - jReq: FullHttpRequest, + req: ClientRequest, promise: Promise[Throwable, ClientResponse], sslOption: ClientSSLOptions, ): Unit = { + val jReq = encodeClientParams(HttpVersion.HTTP_1_1, req) try { val hand = ClientInboundHandler(rtm, jReq, promise) val host = req.url.host @@ -107,14 +111,14 @@ object Client { method: Method, url: URL, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(Request(method, url)) + request(ClientRequest(method, url)) def request( method: Method, url: URL, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(Request(method, url), sslOptions) + request(ClientRequest(method, url), sslOptions) def request( method: Method, @@ -122,7 +126,7 @@ object Client { headers: Headers, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(Request(method, url, headers), sslOptions) + request(ClientRequest(method, url, headers), sslOptions) def request( method: Method, @@ -130,19 +134,48 @@ object Client { headers: Headers, content: HttpData, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(Request(method, url, headers, content, None)) + request(ClientRequest(method, url, headers, content)) def request( - req: Request, + req: ClientRequest, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req)) def request( - req: Request, + req: ClientRequest, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = make.flatMap(_.request(req, sslOptions)) + final case class ClientRequest( + method: Method, + url: URL, + getHeaders: Headers = Headers.empty, + data: HttpData = HttpData.empty, + private val channelContext: ChannelHandlerContext = null, + ) extends HeaderExtension[ClientRequest] { self => + + def getBodyAsString: Option[String] = data match { + case HttpData.Text(text, _) => Some(text) + case HttpData.BinaryChunk(data) => Some(new String(data.toArray, HTTP_CHARSET)) + case HttpData.BinaryByteBuf(data) => Some(data.toString(HTTP_CHARSET)) + case _ => Option.empty + } + + def remoteAddress: Option[InetAddress] = { + if (channelContext != null && channelContext.channel().remoteAddress().isInstanceOf[InetSocketAddress]) + Some(channelContext.channel().remoteAddress().asInstanceOf[InetSocketAddress].getAddress) + else + None + } + + /** + * Updates the headers using the provided function + */ + override def updateHeaders(update: Headers => Headers): ClientRequest = + self.copy(getHeaders = update(self.getHeaders)) + } + final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) extends HeaderExtension[ClientResponse] { self => diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index ca5d4b4807..f9de469a08 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -1,37 +1,41 @@ package zhttp.service +import io.netty.buffer.Unpooled import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames, HttpVersion} -import zhttp.http.Request -import zio.Task +import zhttp.http.HTTP_CHARSET trait EncodeClientParams { /** * Converts client params to JFullHttpRequest */ - def encodeClientParams(jVersion: HttpVersion, req: Request): Task[FullHttpRequest] = req.getBodyAsByteBuf.map { - content => - val method = req.method.asHttpMethod - val url = req.url - - // As per the spec, the path should contain only the relative path. - // Host and port information should be in the headers. - val path = url.relative.encode - - val encodedReqHeaders = req.getHeaders.encode - - val headers = url.host match { - case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) - case None => encodedReqHeaders - } - - val writerIndex = content.writerIndex() - if (writerIndex != 0) { - headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) - } - // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. - val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) - jReq.headers().set(headers) - - jReq + def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { + val method = req.method.asHttpMethod + val url = req.url + + // As per the spec, the path should contain only the relative path. + // Host and port information should be in the headers. + val path = url.relative.encode + + val content = req.getBodyAsString match { + case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) + case None => Unpooled.EMPTY_BUFFER + } + + val encodedReqHeaders = req.getHeaders.encode + + val headers = url.host match { + case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) + case None => encodedReqHeaders + } + + val writerIndex = content.writerIndex() + if (writerIndex != 0) { + headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) + } + // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. + val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) + jReq.headers().set(headers) + + jReq } } diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala new file mode 100644 index 0000000000..b69a33246d --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -0,0 +1,83 @@ +package zhttp.http + +import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} +import zhttp.internal.HttpGen +import zhttp.service.{Client, EncodeClientParams} +import zio.random.Random +import zio.test.Assertion._ +import zio.test._ + +object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientParams { + + val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( + HttpGen.httpData( + Gen.listOf(Gen.alphaNumericString), + ), + ) + + val clientParamWithAbsoluteUrl = HttpGen.clientRequest( + dataGen = HttpGen.httpData( + Gen.listOf(Gen.alphaNumericString), + ), + urlGen = HttpGen.genAbsoluteURL, + ) + + def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( + for { + content <- Gen.alphaNumericStringBounded(size, size) + data <- Gen.fromIterable(List(HttpData.fromString(content))) + } yield data, + ) + + def spec = suite("EncodeClientParams") { + testM("method") { + check(anyClientParam) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.method())(equalTo(params.method.asHttpMethod)) + } + } + + testM("method on HttpData.File") { + check(HttpGen.clientParamsForFileHttpData()) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.method())(equalTo(params.method.asHttpMethod)) + } + } + + suite("uri") { + testM("uri") { + check(anyClientParam) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.uri())(equalTo(params.url.relative.encode)) + } + } + + testM("uri on HttpData.File") { + check(HttpGen.clientParamsForFileHttpData()) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.uri())(equalTo(params.url.relative.encode)) + } + } + } + + testM("content-length") { + check(clientParamWithFiniteData(5)) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + assert(req.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong)(equalTo(5L)) + } + } + + testM("host header") { + check(anyClientParam) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val hostHeader = HttpHeaderNames.HOST + assert(Option(req.headers().get(hostHeader)))(equalTo(params.url.host)) + } + } + + testM("host header when absolute url") { + check(clientParamWithAbsoluteUrl) { params => + val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val reqHeaders = req.headers() + val hostHeader = HttpHeaderNames.HOST + + assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && + assert(Option(reqHeaders.get(hostHeader)))(equalTo(params.url.host)) + } + } + } +} diff --git a/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala deleted file mode 100644 index 0dcf1c3b5e..0000000000 --- a/zio-http/src/test/scala/zhttp/http/EncodeRequestSpec.scala +++ /dev/null @@ -1,85 +0,0 @@ -package zhttp.http - -import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} -import zhttp.internal.HttpGen -import zhttp.service.EncodeClientParams -import zio.random.Random -import zio.test.Assertion._ -import zio.test._ - -object EncodeRequestSpec extends DefaultRunnableSpec with EncodeClientParams { - - val anyClientParam: Gen[Random with Sized, Request] = HttpGen.clientRequest( - HttpGen.httpData( - Gen.listOf(Gen.alphaNumericString), - ), - ) - - val clientParamWithAbsoluteUrl = HttpGen.clientRequest( - dataGen = HttpGen.httpData( - Gen.listOf(Gen.alphaNumericString), - ), - urlGen = HttpGen.genAbsoluteURL, - ) - - def clientParamWithFiniteData(size: Int): Gen[Random with Sized, Request] = HttpGen.clientRequest( - for { - content <- Gen.alphaNumericStringBounded(size, size) - data <- Gen.fromIterable(List(HttpData.fromString(content))) - } yield data, - ) - - def spec = suite("EncodeClientParams") { - testM("method") { - checkM(anyClientParam) { params => - val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) - assertM(method)(equalTo(params.method.asHttpMethod)) - } - } + - testM("method on HttpData.File") { - checkM(HttpGen.clientParamsForFileHttpData()) { params => - val method = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.method()) - assertM(method)(equalTo(params.method.asHttpMethod)) - } - } + - suite("uri") { - testM("uri") { - checkM(anyClientParam) { params => - val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) - assertM(uri)(equalTo(params.url.relative.encode)) - } - } + - testM("uri on HttpData.File") { - checkM(HttpGen.clientParamsForFileHttpData()) { params => - val uri = encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.uri()) - assertM(uri)(equalTo(params.url.relative.encode)) - } - } - } + - testM("content-length") { - checkM(clientParamWithFiniteData(5)) { params => - val len = encodeClientParams(HttpVersion.HTTP_1_1, params).map( - _.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong, - ) - assertM(len)(equalTo(5L)) - } - } + - testM("host header") { - checkM(anyClientParam) { params => - val hostHeader = HttpHeaderNames.HOST - val headers = encodeClientParams(HttpVersion.HTTP_1_1, params).map(h => Option(h.headers().get(hostHeader))) - assertM(headers)(equalTo(params.url.host)) - } - } + - testM("host header when absolute url") { - checkM(clientParamWithAbsoluteUrl) { params => - val hostHeader = HttpHeaderNames.HOST - for { - reqHeaders <- encodeClientParams(HttpVersion.HTTP_1_1, params).map(_.headers()) - } yield assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && assert(Option(reqHeaders.get(hostHeader)))( - equalTo(params.url.host), - ) - } - } - } -} diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index bd3da3cc7e..aad22542d1 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -1,6 +1,7 @@ package zhttp.http import io.netty.handler.codec.http.HttpHeaderNames +import zhttp.service.Client import zio.Chunk import zio.test.Assertion._ import zio.test._ @@ -15,26 +16,27 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { val charsetGen: Gen[Any, Charset] = Gen.fromIterable(List(UTF_8, UTF_16, UTF_16BE, UTF_16LE, US_ASCII, ISO_8859_1)) - checkM(charsetGen) { charset => - val encoded = Request( - Method.GET, - URL(Path("/")), - headers = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), - data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes(charset))), - ).getBodyAsString + check(charsetGen) { charset => + val encoded = Client + .ClientRequest( + Method.GET, + URL(Path("/")), + getHeaders = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), + data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes())), + ) + .getBodyAsString + val actual = Option(new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset)) - val expected = new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset) - - assertM(encoded)(equalTo(expected)) + assert(actual)(equalTo(encoded)) } } + - testM("should map bytes to default utf-8 if no charset given") { + test("should map bytes to default utf-8 if no charset given") { val data = Chunk.fromArray("abc".getBytes()) val content = HttpData.BinaryChunk(data) - val request = Request(Method.GET, URL(Path("/")), data = content) + val request = Client.ClientRequest(Method.GET, URL(Path("/")), data = content) val encoded = request.getBodyAsString - val actual = new String(data.toArray, HTTP_CHARSET) - assertM(encoded)(equalTo(actual)) + val actual = Option(new String(data.toArray, HTTP_CHARSET)) + assert(actual)(equalTo(encoded)) }, ) } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 5b06448608..996deb4d4a 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -3,6 +3,7 @@ package zhttp.internal import io.netty.buffer.Unpooled import zhttp.http.URL.Location import zhttp.http._ +import zhttp.service.Client.ClientRequest import zio.random.Random import zio.stream.ZStream import zio.test.{Gen, Sized} @@ -22,7 +23,7 @@ object HttpGen { url <- urlGen headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen - } yield Request(method, url, headers, data, None) + } yield ClientRequest(method, url, headers, data) def clientParamsForFileHttpData() = { for { @@ -30,7 +31,7 @@ object HttpGen { method <- HttpGen.method url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) - } yield Request(method, url, headers, HttpData.fromFile(file), None) + } yield ClientRequest(method, url, headers, HttpData.fromFile(file)) } def cookies: Gen[Random with Sized, Cookie] = for { @@ -118,7 +119,7 @@ object HttpGen { url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) data <- HttpGen.httpData(Gen.listOf(Gen.alphaNumericString)) - } yield Request(method, url, headers, data, None) + } yield Request(method, url, headers, None, data) def response[R](gContent: Gen[R, List[String]]): Gen[Random with Sized with R, Response] = { for { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 5718e794c4..1642799a76 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -21,7 +21,7 @@ import zio.{Has, Task, ZIO, ZManaged} */ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => - implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Request, A]) { + implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Client.ClientRequest, A]) { /** * Runs the deployed Http app by making a real http request to it. The method allows us to configure individual @@ -34,12 +34,11 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => headers: Headers = Headers.empty, ): ZIO[R, Throwable, A] = app( - Request( + Client.ClientRequest( method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", 0)), headers, HttpData.fromString(content), - None, ), ).catchAll { case Some(value) => ZIO.fail(value) @@ -59,7 +58,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => for { port <- Http.fromZIO(DynamicServer.getPort) id <- Http.fromZIO(DynamicServer.deploy(app)) - response <- Http.fromFunctionZIO[Request] { params => + response <- Http.fromFunctionZIO[Client.ClientRequest] { params => Client.request( params .addHeader(DynamicServer.APP_ID, id) @@ -75,7 +74,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => def deployWebSocket: HttpTestClient[SttpClient, client3.Response[Either[String, WebSocket[Task]]]] = for { id <- Http.fromZIO(DynamicServer.deploy(app)) res <- - Http.fromFunctionZIO[Request](params => + Http.fromFunctionZIO[Client.ClientRequest](params => for { port <- DynamicServer.getPort url = s"ws://localhost:$port${params.url.path.asString}" @@ -118,7 +117,7 @@ object HttpRunnableSpec { Http[ R with EventLoopGroup with ChannelFactory with DynamicServer with ServerChannelFactory, Throwable, - Request, + Client.ClientRequest, A, ] } From d88c0c4b4462cf89d17ddc44e4246bca9ad26be2 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Fri, 28 Jan 2022 17:58:08 +0530 Subject: [PATCH 53/95] Feature: add `toHttp` to Response (#903) * feature: add `wrapHttp` to Response * test: add unit test for wrapHttp in Response.scala * refactor: operator name changed to `toHttp` Co-authored-by: Shubham Girdhar --- .../src/main/scala/zhttp/http/Response.scala | 5 ++++ ...seHelpersSpec.scala => ResponseSpec.scala} | 26 ++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) rename zio-http/src/test/scala/zhttp/http/{ResponseHelpersSpec.scala => ResponseSpec.scala} (74%) diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index 738aced8c3..94cde589d6 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -61,6 +61,11 @@ final case class Response private ( */ def withServerTime: Response = self.copy(attribute = self.attribute.withServerTime) + /** + * Wraps the current response as a Http + */ + def toHttp: Http[Any, Nothing, Any, Response] = Http.succeed(self) + /** * Wraps the current response into a ZIO */ diff --git a/zio-http/src/test/scala/zhttp/http/ResponseHelpersSpec.scala b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala similarity index 74% rename from zio-http/src/test/scala/zhttp/http/ResponseHelpersSpec.scala rename to zio-http/src/test/scala/zhttp/http/ResponseSpec.scala index d66b219727..4ae3c56ac7 100644 --- a/zio-http/src/test/scala/zhttp/http/ResponseHelpersSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala @@ -1,11 +1,12 @@ package zhttp.http +import zio.test.Assertion._ import zio.test._ -object ResponseHelpersSpec extends DefaultRunnableSpec { - val redirectSpec = { - val location = "www.google.com" - suite("redirectSpec")( +object ResponseSpec extends DefaultRunnableSpec { + def spec = suite("Response")( + suite("redirect") { + val location = "www.google.com" test("Temporary redirect should produce a response with a TEMPORARY_REDIRECT") { val x = Response.redirect(location) assertTrue(x.status == Status.TEMPORARY_REDIRECT) && @@ -22,14 +23,19 @@ object ResponseHelpersSpec extends DefaultRunnableSpec { test("Permanent redirect should produce a response with a location") { val x = Response.redirect(location, true) assertTrue(x.getHeaderValue(HeaderNames.location).contains(location)) - } + + } + } + + suite("json")( test("Json should set content type to ApplicationJson") { val x = Response.json("""{"message": "Hello"}""") assertTrue(x.getHeaderValue(HeaderNames.contentType).contains(HeaderValues.applicationJson.toString)) }, - ) - } - - def spec = - suite("ResponseHelpers")(redirectSpec) + ) + + suite("toHttp")( + testM("should convert response to Http") { + val http = Response.ok.toHttp + assertM(http(()))(equalTo(Response.ok)) + }, + ), + ) } From 4e2d48c2b636e1a497ee2b423c679a204ec429be Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Tue, 1 Feb 2022 14:32:24 +0530 Subject: [PATCH 54/95] Update scalafmt-core to 3.4.0 (#920) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 19a16b06f9..43acb10301 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.3.3 +version = 3.4.0 maxColumn = 120 align.preset = more From 7d5a80ff3f16ecdbfa18a131bf99ab7640192b0d Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Tue, 1 Feb 2022 10:04:43 +0100 Subject: [PATCH 55/95] Update sbt to 1.6.2 (#931) --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 3161d2146c..c8fcab543a 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.6.1 +sbt.version=1.6.2 From d8b0143768d7901e1cce37a686beeed3e483effb Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Tue, 1 Feb 2022 16:33:20 +0530 Subject: [PATCH 56/95] Remove outdated benchmark.md (#940) * removed benchmark file * removed benchmark hyperlink from readme --- BENCHMARKS.md | 232 -------------------------------------------------- README.md | 1 - 2 files changed, 233 deletions(-) delete mode 100644 BENCHMARKS.md diff --git a/BENCHMARKS.md b/BENCHMARKS.md deleted file mode 100644 index 8bf4f1a29b..0000000000 --- a/BENCHMARKS.md +++ /dev/null @@ -1,232 +0,0 @@ -# Table of Contents - -- [Table of Contents](#table-of-contents) -- [Methodology](#methodology) -- [Benchmarks](#benchmarks) - - [ZIO Http](#zio-http) - - [Vert.x](#vertx) - - [Http4s](#http4s) - - [Play](#play) - - [Finagle](#finagle) - -# Methodology - -1. For more realistic benchmarks the client and the server were deployed on different machines, with the following configuration — - - 1. EC2(C5.4xLarge) 16 vCPUs 32 GB RAM as **server**. - 1. EC2(C5.4xLarge) 16 vCPUs 32 GB RAM as **client** with [wrk] setup. - -1. After the servers were started they were warmed up using wrk until the results start stabilizing. - -[wrk]: https://github.com/wg/wrk - -# Benchmarks - -## [ZIO Http](https://github.com/dream11/zio-http) - -[source code](https://github.com/dream11/zio-http/tree/master/example/src/main/scala/HelloWorldAdvanced.scala) - -**Plain Text** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.105.8:8090/text -Running 10s test @ http://10.10.109.3:8090 - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 1.37ms 844.59us 206.84ms 97.72% - Req/Sec 60.42k 2.20k 74.51k 70.22% - Latency Distribution - 50% 1.28ms - 75% 1.48ms - 90% 1.72ms - 99% 2.55ms - 7267713 requests in 10.10s, 346.55MB read -Requests/sec: 719576.04 -Transfer/sec: 34.31MB -``` - -**JSON** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.105.8:8090/json -Running 10s test @ http://10.10.109.3:8090/json - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 1.40ms 421.62us 32.84ms 90.14% - Req/Sec 58.73k 2.81k 68.19k 68.51% - Latency Distribution - 50% 1.32ms - 75% 1.53ms - 90% 1.80ms - 99% 2.49ms - 7070158 requests in 10.10s, 660.78MB read -Requests/sec: 700073.31 -``` - -## [Vert.x](https://vertx.io/) - -[source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Scala/vertx-web-scala) - -**Plain Text** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:8080/plaintext -Running 10s test @ http://10.10.109.3:8080/plaintext - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 4.86ms 20.51ms 455.47ms 96.42% - Req/Sec 59.89k 17.38k 82.30k 82.17% - Latency Distribution - 50% 1.12ms - 75% 1.46ms - 90% 4.20ms - 99% 103.73ms - 7150937 requests in 10.10s, 0.87GB read -Requests/sec: 707991.69 -Transfer/sec: 87.78MB -``` - -**JSON** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:8080/json -Running 10s test @ http://10.10.109.3:8080/json - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 5.98ms 20.68ms 331.64ms 94.99% - Req/Sec 55.01k 19.93k 93.01k 78.66% - Latency Distribution - 50% 1.18ms - 75% 1.69ms - 90% 9.91ms - 99% 114.11ms - 6513121 requests in 10.10s, 0.92GB read -Requests/sec: 644854.27 -Transfer/sec: 92.86MB -``` - -## [Http4s](https://github.com/http4s/http4s) - -[source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Scala/http4s) - -**Plain Text** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:8080/plaintext -Running 10s test @ http://10.10.109.3:8080/plaintext - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 78.36ms 455.43ms 6.74s 97.14% - Req/Sec 11.76k 3.34k 47.87k 79.03% - Latency Distribution - 50% 5.35ms - 75% 9.36ms - 90% 45.89ms - 99% 2.46s - 1406517 requests in 10.08s, 202.55MB read -Requests/sec: 139573.98 -Transfer/sec: 20.10MB -``` - -**JSON** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:8080/json -Running 10s test @ http://10.10.109.3:8080/json - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 87.89ms 500.30ms 6.71s 97.02% - Req/Sec 11.43k 3.52k 36.27k 74.58% - Latency Distribution - 50% 5.37ms - 75% 9.45ms - 90% 47.89ms - 99% 2.78s - 1369098 requests in 10.10s, 203.69MB read -Requests/sec: 135565.22 -Transfer/sec: 20.17MB -``` - -## [Play](https://www.playframework.com/documentation/2.8.x/ScalaHome) - -[source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Scala/play2-scala) - -**Plain text** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:9000/plaintext -Running 10s test @ http://10.10.109.3:9000/plaintext - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 54.78ms 320.71ms 6.72s 96.49% - Req/Sec 22.46k 8.60k 81.67k 84.98% - Latency Distribution - 50% 3.31ms - 75% 3.84ms - 90% 4.60ms - 99% 1.59s - 2664591 requests in 10.10s, 292.23MB read -Requests/sec: 263819.25 -Transfer/sec: 28.93MB -``` - -**JSON** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.109.3:9000/json -Running 10s test @ http://10.10.109.3:9000/json - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 124.11ms 568.53ms 6.68s 95.06% - Req/Sec 22.21k 7.34k 60.60k 84.84% - Latency Distribution - 50% 3.39ms - 75% 3.99ms - 90% 8.18ms - 99% 3.17s - 2638210 requests in 10.10s, 339.66MB read -Requests/sec: 261223.68 -Transfer/sec: 33.63MB -``` - -## [Finagle](https://twitter.github.io/finagle/) - -[source code](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Scala/finagle) - -**Plain Text** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.110.217:8080/plaintext -Running 10s test @ http://10.10.110.217:8080/plaintext - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 1.74ms 712.71us 22.53ms 83.65% - Req/Sec 48.17k 2.11k 69.16k 90.63% - Latency Distribution - 50% 1.54ms - 75% 1.96ms - 90% 2.65ms - 99% 4.22ms - 5779092 requests in 10.10s, 721.99MB read -Requests/sec: 572231.69 -Transfer/sec: 71.49MB -``` - -**JSON** - -```dtd -./wrk -t12 -c1000 --latency --timeout=10s --duration=10s http://10.10.110.217:8080/json -Running 10s test @ http://10.10.110.217:8080/json - 12 threads and 1000 connections - Thread Stats Avg Stdev Max +/- Stdev - Latency 1.77ms 811.08us 32.39ms 88.24% - Req/Sec 47.65k 2.36k 59.13k 86.19% - Latency Distribution - 50% 1.54ms - 75% 2.03ms - 90% 2.57ms - 99% 4.39ms - 5731384 requests in 10.10s, 825.35MB read -Requests/sec: 567496.97 -Transfer/sec: 81.72MB -``` diff --git a/README.md b/README.md index 095a08891c..b388eaf246 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ Check out the full documentation here: [Documentation] - [ZIO Http](#zio-http) - [Getting Started](#getting-started) - [Installation](#installation) -- [Benchmarks](#benchmarks) - [Documentation](https://dream11.github.io/zio-http/) # Getting Started From 120450b51d3030038f44ca6a65d8e8fb8d770039 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 1 Feb 2022 16:34:13 +0530 Subject: [PATCH 57/95] refactor: rename `getHeaders` to `headers` in `ClientRequest` (#928) * refactor: rename `getHeaders` to `headers` in `ClientRequest` * fix: compiler errors * fix: compiler errors --- zio-http/src/main/scala/zhttp/service/Client.scala | 6 ++++-- .../src/test/scala/zhttp/http/GetBodyAsStringSpec.scala | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 853eab2be2..1b2e258140 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -150,7 +150,7 @@ object Client { final case class ClientRequest( method: Method, url: URL, - getHeaders: Headers = Headers.empty, + headers: Headers = Headers.empty, data: HttpData = HttpData.empty, private val channelContext: ChannelHandlerContext = null, ) extends HeaderExtension[ClientRequest] { self => @@ -162,6 +162,8 @@ object Client { case _ => Option.empty } + def getHeaders: Headers = headers + def remoteAddress: Option[InetAddress] = { if (channelContext != null && channelContext.channel().remoteAddress().isInstanceOf[InetSocketAddress]) Some(channelContext.channel().remoteAddress().asInstanceOf[InetSocketAddress].getAddress) @@ -173,7 +175,7 @@ object Client { * Updates the headers using the provided function */ override def updateHeaders(update: Headers => Headers): ClientRequest = - self.copy(getHeaders = update(self.getHeaders)) + self.copy(headers = update(self.getHeaders)) } final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index aad22542d1..5e2c97030f 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -21,7 +21,7 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { .ClientRequest( Method.GET, URL(Path("/")), - getHeaders = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), + headers = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes())), ) .getBodyAsString From aec73823146b58d7b81158c2f9c152c250e98768 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 1 Feb 2022 16:35:01 +0530 Subject: [PATCH 58/95] Refactor: rename `asString` to `encode` in `Path` (#927) * refactor: rename `asString` to `encode` in Path * fix: compiler errors --- zio-http/src/main/scala/zhttp/http/Cookie.scala | 2 +- zio-http/src/main/scala/zhttp/http/HttpError.scala | 2 +- zio-http/src/main/scala/zhttp/http/PathModule.scala | 10 +++++----- zio-http/src/main/scala/zhttp/http/URL.scala | 2 +- zio-http/src/test/scala/zhttp/http/PathSpec.scala | 8 ++++---- .../test/scala/zhttp/internal/HttpRunnableSpec.scala | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Cookie.scala b/zio-http/src/main/scala/zhttp/http/Cookie.scala index 024b434838..bc30b097a1 100644 --- a/zio-http/src/main/scala/zhttp/http/Cookie.scala +++ b/zio-http/src/main/scala/zhttp/http/Cookie.scala @@ -132,7 +132,7 @@ final case class Cookie( expires.map(e => s"Expires=$e"), maxAge.map(a => s"Max-Age=${a.toString}"), domain.map(d => s"Domain=$d"), - path.map(p => s"Path=${p.asString}"), + path.map(p => s"Path=${p.encode}"), if (isSecure) Some("Secure") else None, if (isHttpOnly) Some("HttpOnly") else None, sameSite.map(s => s"SameSite=${s.asString}"), diff --git a/zio-http/src/main/scala/zhttp/http/HttpError.scala b/zio-http/src/main/scala/zhttp/http/HttpError.scala index 71999c77c4..1a71d50a08 100644 --- a/zio-http/src/main/scala/zhttp/http/HttpError.scala +++ b/zio-http/src/main/scala/zhttp/http/HttpError.scala @@ -24,7 +24,7 @@ object HttpError { final case class Forbidden(msg: String = "Forbidden") extends HttpError(Status.FORBIDDEN, msg) final case class NotFound(path: Path) - extends HttpError(Status.NOT_FOUND, s"""The requested URI "${path.asString}" was not found on this server\n""") + extends HttpError(Status.NOT_FOUND, s"""The requested URI "${path.encode}" was not found on this server\n""") final case class MethodNotAllowed(msg: String = "Method Not Allowed") extends HttpError(Status.METHOD_NOT_ALLOWED, msg) diff --git a/zio-http/src/main/scala/zhttp/http/PathModule.scala b/zio-http/src/main/scala/zhttp/http/PathModule.scala index da8375562d..5dae4e1b5b 100644 --- a/zio-http/src/main/scala/zhttp/http/PathModule.scala +++ b/zio-http/src/main/scala/zhttp/http/PathModule.scala @@ -8,13 +8,17 @@ private[zhttp] trait PathModule { module => val Root = !! sealed trait Path { self => + final override def toString: String = this.encode + final def /(name: String): Path = Path(self.toList :+ name) final def /:(name: String): Path = append(name) final def append(name: String): Path = if (name.isEmpty) self else Path.Cons(name, self) - final def asString: String = { + final def drop(n: Int): Path = Path(self.toList.drop(n)) + + final def encode: String = { def loop(self: Path): String = { self match { case Path.End => "" @@ -25,8 +29,6 @@ private[zhttp] trait PathModule { module => if (result.isEmpty) "/" else result } - final def drop(n: Int): Path = Path(self.toList.drop(n)) - final def initial: Path = self match { case Path.End => self case Path.Cons(_, path) => path @@ -58,8 +60,6 @@ private[zhttp] trait PathModule { module => final def take(n: Int): Path = Path(self.toList.take(n)) def toList: List[String] - - final override def toString: String = this.asString } object Path { diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index 43f4c8d2c5..1befd10f50 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -85,7 +85,7 @@ object URL { def asString(url: URL): String = { def path: String = { - val encoder = new QueryStringEncoder(s"${url.path.asString}${url.fragment.fold("")(f => "#" + f.raw)}") + val encoder = new QueryStringEncoder(s"${url.path.encode}${url.fragment.fold("")(f => "#" + f.raw)}") url.queryParams.foreach { case (key, values) => if (key != "") values.foreach { value => encoder.addParam(key, value) } } diff --git a/zio-http/src/test/scala/zhttp/http/PathSpec.scala b/zio-http/src/test/scala/zhttp/http/PathSpec.scala index 3457e1804f..0549505738 100644 --- a/zio-http/src/test/scala/zhttp/http/PathSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/PathSpec.scala @@ -32,15 +32,15 @@ object PathSpec extends DefaultRunnableSpec with HExitAssertion { ) + suite("asString")( test("a, b, c") { - val path = Path("a", "b", "c").asString + val path = Path("a", "b", "c").encode assert(path)(equalTo("/a/b/c")) } + test("Path()") { - val path = Path().asString + val path = Path().encode assert(path)(equalTo("/")) } + test("!!") { - val path = !!.asString + val path = !!.encode assert(path)(equalTo("/")) }, ) + @@ -69,7 +69,7 @@ object PathSpec extends DefaultRunnableSpec with HExitAssertion { } + suite("default")( test("extract path 'name' /: name") { - val path = collect { case "name" /: name => name.asString } + val path = collect { case "name" /: name => name.encode } assert(path(Path("name", "a", "b", "c")))(isSome(equalTo("/a/b/c"))) } + test("extract paths 'name' /: a /: b /: 'c' /: !!") { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 1642799a76..4438f517c1 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -77,7 +77,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => Http.fromFunctionZIO[Client.ClientRequest](params => for { port <- DynamicServer.getPort - url = s"ws://localhost:$port${params.url.path.asString}" + url = s"ws://localhost:$port${params.url.path.encode}" headerConv = params.addHeader(DynamicServer.APP_ID, id).getHeaders.toList.map(h => SHeader(h._1, h._2)) res <- send(basicRequest.get(uri"$url").copy(headers = headerConv).response(asWebSocketUnsafe)) } yield res, From 21cdee6fe03b653d5fa716885b9f65220a80f332 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Tue, 1 Feb 2022 16:38:40 +0530 Subject: [PATCH 59/95] Disable flow Control (#854) --- example/src/main/scala/example/PlainTextBenchmarkServer.scala | 3 ++- zio-http/src/main/scala/zhttp/service/Server.scala | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/src/main/scala/example/PlainTextBenchmarkServer.scala b/example/src/main/scala/example/PlainTextBenchmarkServer.scala index 33af49d087..7ebf1ecbef 100644 --- a/example/src/main/scala/example/PlainTextBenchmarkServer.scala +++ b/example/src/main/scala/example/PlainTextBenchmarkServer.scala @@ -36,6 +36,7 @@ object Main extends App { Server.error(_ => UIO.unit) ++ Server.keepAlive ++ Server.disableLeakDetection ++ - Server.consolidateFlush + Server.consolidateFlush ++ + Server.disableFlowControl } diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 711f957734..1b21f0d6b2 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -129,7 +129,7 @@ object Server { acceptContinue: Boolean = false, keepAlive: Boolean = false, consolidateFlush: Boolean = false, - flowControl: Boolean = false, + flowControl: Boolean = true, ) /** From b192d897c52a5e068ebf2221e078ce46c417bd12 Mon Sep 17 00:00:00 2001 From: James Beem Date: Wed, 2 Feb 2022 08:55:13 -0500 Subject: [PATCH 60/95] Add builder pattern for URL (#930) * Add builder pattern for URL * Compare encoded value to string literal --- zio-http/src/main/scala/zhttp/http/URL.scala | 50 ++++++++++++++++--- .../src/test/scala/zhttp/http/URLSpec.scala | 24 ++++++++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index 1befd10f50..966dbec60e 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -29,6 +29,43 @@ final case class URL( } def encode: String = URL.asString(self) + + def setPath(path: Path) = + copy(path = path) + + def setPath(path: String) = copy(path = Path(path)) + + def setHost(host: String) = { + val location = kind match { + case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, host, URL.portFromScheme(Scheme.HTTP)) + case abs: URL.Location.Absolute => abs.copy(host = host) + } + copy(kind = location) + } + + def setQueryParams(queryParams: Map[String, List[String]]) = + copy(queryParams = queryParams) + + def setQueryParams(query: String) = + copy(queryParams = URL.queryParams(query)) + + def setPort(port: Int) = { + val location = kind match { + case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, "", port) + case abs: URL.Location.Absolute => abs.copy(port = port) + } + + copy(kind = location) + } + + def setScheme(scheme: Scheme) = { + val location = kind match { + case URL.Location.Relative => URL.Location.Absolute(scheme, "", URL.portFromScheme(scheme)) + case abs: URL.Location.Absolute => abs.copy(scheme = scheme) + } + + copy(kind = location) + } } object URL { sealed trait Location @@ -47,13 +84,12 @@ object URL { } } - private def fromAbsoluteURI(uri: URI): Option[URL] = { - - def portFromScheme(scheme: Scheme): Int = scheme match { - case Scheme.HTTP => 80 - case Scheme.HTTPS => 443 - } + private def portFromScheme(scheme: Scheme): Int = scheme match { + case Scheme.HTTP => 80 + case Scheme.HTTPS => 443 + } + private def fromAbsoluteURI(uri: URI): Option[URL] = { for { scheme <- Scheme.fromString(uri.getScheme) host <- Option(uri.getHost) @@ -67,6 +103,8 @@ object URL { path <- Option(uri.getRawPath) } yield URL(Path(path), Location.Relative, queryParams(uri.getRawQuery), Fragment.fromURI(uri)) + def empty: URL = root + def fromString(string: String): Either[HttpError, URL] = { def invalidURL = Left(HttpError.BadRequest(s"Invalid URL: $string")) for { diff --git a/zio-http/src/test/scala/zhttp/http/URLSpec.scala b/zio-http/src/test/scala/zhttp/http/URLSpec.scala index 38beb65221..04d9f6e2e7 100644 --- a/zio-http/src/test/scala/zhttp/http/URLSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/URLSpec.scala @@ -99,6 +99,28 @@ object URLSpec extends DefaultRunnableSpec { }, ) + val builderSpec = suite("builder")( + test("creates a URL with all attributes set") { + val builderUrl = URL.empty + .setHost("www.yourdomain.com") + .setPath("/list") + .setPort(8080) + .setScheme(Scheme.HTTPS) + .setQueryParams("?type=builder&query=provided") + + assert(builderUrl.encode)(equalTo("https://www.yourdomain.com:8080/list?type=builder&query=provided")) + }, + test("returns relative URL if port, host, and scheme are not set") { + val builderUrl = URL.empty + .setPath(Path("/list")) + .setQueryParams( + Map("type" -> List("builder"), "query" -> List("provided")), + ) + + assert(builderUrl.encode)(equalTo("/list?type=builder&query=provided")) + }, + ) + def spec = - suite("URL")(fromStringSpec, asStringSpec, relativeSpec) + suite("URL")(fromStringSpec, asStringSpec, relativeSpec, builderSpec) } From c1a306e58b406601975bb5d288339ecabd096172 Mon Sep 17 00:00:00 2001 From: Dino Babu John <66246799+dinojohn@users.noreply.github.com> Date: Thu, 3 Feb 2022 00:36:50 +0530 Subject: [PATCH 61/95] Documentation: Http (#888) * initial commit for http documentation * refactor: adding bold formatting for HTTP and resolving review comments * refactor: Chnage app to application in http documentation * refactor:fixed review comments * added combinators section * style: formatting the code blocks * added getBodyAsString to http documentation * added HttpApp section * fixing typos * added mapZIO and contamapZIO documentation for http * provide layer documentation for http * doc: added a secion- Running an HttpApp Co-authored-by: Dino John --- docs/website/docs/v1.x/dsl/http/index.md | 368 ++++++++++++++++++++++- 1 file changed, 367 insertions(+), 1 deletion(-) diff --git a/docs/website/docs/v1.x/dsl/http/index.md b/docs/website/docs/v1.x/dsl/http/index.md index acfff8c574..2a0cc6ce65 100644 --- a/docs/website/docs/v1.x/dsl/http/index.md +++ b/docs/website/docs/v1.x/dsl/http/index.md @@ -1 +1,367 @@ -# Work in progress \ No newline at end of file +# Http Domain + +`Http` is a functional domain that models HTTP applications. It’s polymorphic on input and output type. + +A `Http[-R, +E, -A, +B]` models a function from `A` to `ZIO[R, Option[E], B]`. When a value of type `A` is evaluated against an `Http[R,E,A,B]`, it can either succeed with a `B` , fail with a `Some[E]` or if `A` is not defined in the application, fail with `None`. + +`Http` domain provides several operators and constructors to model the application as per your use case. + +## Creating an HTTP Application + +### HTTP application that always succeeds + +To create an HTTP application that always returns the same response and never fails, you can use the `succeed` constructor. + +```scala + val app: Http[Any, Nothing, Any, Int] = Http.succeed(1) +``` + +### HTTP application that always fails + +To create an HTTP application that always fails with the given error, you can use the `fail` constructor. + +```scala + val app: Http[Any, Error, Any, Nothing] = Http.fail(new Error("Error_Message")) + ``` +HTTP applications can also be created from total and partial functions. These are some constructors to create HTTP applications from total as well as partial functions. + +### HTTP application from a partial function + +`Http.Collect` can create an `Http[Any, Nothing, A, B]` from a `PartialFunction[A, B]`. In case the input is not defined for the partial function, the application will return a `None` type error. + +```scala + val app: Http[Any, Nothing, String, String] = Http.collect[String] { + case "case 1" => "response 1" + case "case 2" => "response 2" + } +``` + +`Http.CollectZIO` can be used to create a `Http[R, E, A, B]` from a partial function that returns a ZIO effect, i.e `PartialFunction[A, ZIO[R, E, B]`. This constructor is used when the output is effectful. + +```scala + val app: Http[Any, Nothing, String, String] = Http.collectZIO[String] { + case "case 1" => ZIO.succeed("response 1") + } +``` + +### HTTP application from a total function + +`Http.fromFunction` can create an `Http[Any, Nothing, A, B]` from a function `f: A=>B`. + +```scala + val app: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](i => i + 1) +``` + +`Http.fromFunctionZIO` can create a `Http[R, E, A, B]` from a function that returns a ZIO effect, i.e `f: A => ZIO[R, E, B]`. + +```scala + val app: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](i => ZIO.succeed(i + 1)) +``` + +## Transforming Http Applications + +Http operators are used to transform one or more HTTP applications to create a new HTTP application. Http domain provides plenty of such powerful operators. + +### Transforming the output + +To transform the output of the HTTP application, you can use `map` operator . It takes a function `f: B=>C` to convert a `Http[R,E,A,B]`to `Http[R,E,A,C]`. + +```scala + val a: Http[Any, Nothing, Any, String] = Http.succeed("text") + val app: Http[Any, Nothing, Any, Int] = a.map(s => s.length()) +``` + +To transform the output of the HTTP application effectfully, you can use `mapZIO` operator. It takes a function `B => ZIO[R1, E1, C]` to convert a `Http[R,E,A,B]` to `Http[R,E,A,C]`. + +```scala + val a: Http[Any, Nothing, Any, String] = Http.succeed("text") + val app: Http[Any, Nothing, Any, Int] = a.mapZIO(s => ZIO.succeed(s.length())) +``` + +### Transforming the input + +To transform the input of the HTTP application, you can use `contramap` operator. Before passing the input on to the HTTP application, `contramap` applies a function `xa: X => A` on it. + +```scala + val a: Http[Any, Nothing, String, String] = Http.fromFunction[String](s => s + ' ' + s) + val app: Http[Any, Nothing, Int, String] = a.contramap[Int](_.toString) +``` + +To transform the input of the HTTP application effectfully, you can use `contramapZIO` operator. Before passing the input on to the HTTP application, `contramapZIO` applies a function `xa: X => ZIO[R1, E1, A]` on it. + +```scala + val a: Http[Any, Nothing, String, String] = Http.fromFunction[String](s => s + ' ' + s) + val app: Http[Any, Any, Int, String] = a.contramapZIO[Any, Any,Int](a=>ZIO.succeed(a.toString)) +``` + +### Chaining HTTP applications + +To chain two HTTP applications, you can use `flatMap` operator.It creates a new `Http[R1, E1, A1, C1]` from the output of a `Http[R,E,A,B]`, using a function `f: B => Http[R1, E1, A1, C1]`. `>>=` is an alias for flatMap. + +```scala + val a: Http[Any, Nothing, Any, String] = Http.succeed("text1") + val app: Http[Any, Nothing, Any, String] = a >>= (s => Http.succeed(s + " text2")) +``` + +### Folding an HTTP application + +`foldHttp` lets you handle the success and failure values of an HTTP application. It takes in two functions, one for failure and one for success, and one more HTTP application. +- If the application fails with `Some[E]` the first function will be executed with `E`, +- If the application succeeds with `B`, the second function will be executed with `B` and +- If the application fails with `None` the given HTTP application will be executed with the original input. + +```scala + val a: Http[Any, String, String, String] = Http.collectHttp[String]{ + case "case" => Http.fail("1") + case _ => Http.succeed("2") + } + val b: Http[Any, Nothing, Any, String] = Http.succeed("3") + val app: Http[Any, Nothing, String, String] = a.foldHttp(e => Http.succeed(e), s => Http.succeed(s), b) +``` +## Error Handling +These are several ways in which error handling can be done in `Http` domain, + +### Catch all errors + +To catch all errors in case of failure of an HTTP application, you can use `catchAll` operator. It pipes the error to a function `f: E => Http[R1, E1, A1, B1]`. + +```scala + val a: Http[Any, Throwable, Any, Nothing] = Http.fail(new Throwable("Error_Message")) + val app: Http[Any, Nothing, Any, Option[Throwable]] = a.catchAll(e => Http.succeed(Option(e))) +``` + +### Mapping the error + +To transform the failure of an HTTP application, you can use `mapError` operator. It pipes the error to a function `ee: E => E1`. + +```scala + val a: Http[Any, Throwable, Any, Nothing] = Http.fail(new Throwable("Error_Message")) + val app: Http[Any, Option[Throwable], Any, Nothing] = a.mapError(e => Option(e)) +``` + +## Composition of HTTP applications + +HTTP applications can be composed using several special operators. + +### Using `++` + +`++` is an alias for `defaultWith`. While using `++`, if the first HTTP application returns `None` the second HTTP application will be evaluated, ignoring the result from the first. If the first HTTP application is failing with a `Some[E]` the second HTTP application won't be evaluated. + +```scala + val a: Http[Any, Nothing, String, String] = Http.collect[String] { + case "case 1" => "response 1" + case "case 2" => "response 2" + } + val b: Http[Any, Nothing, String, String] = Http.collect[String] { + case "case 3" => "response 3" + case "case 4" => "response 4" + } + val app: Http[Any, Nothing, String, String] = a ++ b +``` + +### Using `<>` + +`<>` is an alias for `orElse`. While using `<>`, if the first HTTP application fails with `Some[E]`, the second HTTP application will be evaluated, ignoring the result from the first. If the first HTTP application returns `None`, the second HTTP application won't be evaluated. + +```scala + val app: Http[Any, Nothing, Any, Int] = Http.fail(1) <> Http.succeed(2) +``` + +### Using `>>>` + +`>>>` is an alias for `andThen`. It runs the first HTTP application and pipes the output into the other. + +```scala + val a: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](a => a + 1) + val b: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](b => b * 2) + val app: Http[Any, Nothing, Int, Int] = a >>> (b) +``` + +### Using `<<<` + +`<<<` is the alias for `compose`. Compose is similar to andThen. It runs the second HTTP application and pipes the output to the first HTTP +application. + +```scala + val a: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](a => a + 1) + val b: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](b => b * 2) + val app: Http[Any, Nothing, Int, Int] = a <<< (b) +``` + +## Providing environments + +There are many operators to provide the HTTP application with its required environment. + +### provideCustomLayer + +Provides the HTTP application with the part of the environment that is not part of the ZEnv, leaving an effect that only depends on the ZEnv. + +```scala + val a: Http[Clock, DateTimeException, String, OffsetDateTime] = Http.collectZIO[String] { + case "case 1" => clock.currentDateTime + } + val app: Http[zio.ZEnv, DateTimeException, String, OffsetDateTime] = a.provideCustomLayer(Clock.live) +``` + +## Attaching Middleware + +Middlewares are essentially transformations that one can apply to any `Http` to produce a new one. To attach middleware to the HTTP application, you can use `middleware` operator. `@@` is an alias for `middleware`. + +```scala + val app: Http[Any, Int, Any, Nothing] = Http.succeed(1) @@ Middleware.fail(2) +``` + +## Unit testing + +Since an HTTP application `Http[R, E, A, B]` is a function from `A` to `ZIO[R, Option[E], B]`, we can write unit tests just like we do for normal functions. + +The below snippet tests an app that takes `Int` as input and responds by adding 1 to the input. +```scala + package zhttp.http.middleware + + import zhttp.http._ + import zio.test.Assertion.equalTo + import zio.test._ + + object Spec extends DefaultRunnableSpec { + + def spec = suite("http")( + testM("1 + 1 = 2") { + val app: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](_ + 1) + assertM(app(1))(equalTo(2)) + } + ) + } +``` + +# What is HttpApp? + +`HttpApp[-R, +E]` is a type alias for `Http[R, E, Request, Response]`, i.e `HttpApp[-R, +E]` is a function +from `Request` to `ZIO[R, Option[E], Response]`. ZIO HTTP server runs `HttpApp[R, E]` only. + +## Special Constructors for HttpApp + +These are some of the special constructors for HttpApp: + +### Http.ok + +Creates an `HttpApp` that always responds with a 200 status code. + +```scala + val app: HttpApp[Any, Nothing] = Http.ok +``` + +### Http.text + +Creates an `HttpApp` that always responds with the same plain text. + +```scala + val app: HttpApp[Any, Nothing] = Http.text("Text Response") +``` + +### Http.status + +Creates an `HttpApp` that always responds with the same status code and empty data. + +```scala + val app: HttpApp[Any, Nothing] = Http.status(Status.OK) +``` + +### Http.error + +Creates an `HttpApp` that always fails with the given `HttpError`. + +```scala + val app: HttpApp[Any, Nothing] = Http.error(HttpError.Forbidden()) +``` + +### Http.response + +Creates an `HttpApp` that always responds with the same `Response`. + +```scala + val app: HttpApp[Any, Nothing] = Http.response(Response.ok) +``` + +## Special operators on HttpApp + +These are some special operators for `HttpApps`. + +### setMethod + +Overwrites the method in the incoming request to the `HttpApp` + +```scala + val a: HttpApp[Any, Nothing] = Http.collect[Request] { + case Method.GET -> !! / "text" => Response.text("Hello World!") + } + val app = a setMethod (Method.POST) +``` + +### patch + +Patches the response produced by the HTTP application using a `Patch`. + +```scala + val a: HttpApp[Any, Nothing] = Http.collect[Request] { + case Method.GET -> !! / "text" => Response.text("Hello World!") + } + val app = a.patch(Patch.setStatus(Status.ACCEPTED)) +``` + +### getBodyAsString + +`getBodyAsString` extract the body of the response as a string and make it the output type. + +```scala + val a: HttpApp[Any, Nothing] = Http.collect[Request] { + case Method.GET -> !! / "text" => Response.text("Hello World!") + } + val app: Http[Any, Throwable, Request, String] = a.getBodyAsString +``` + +## Converting an `Http` to `HttpApp` +If you want to run an `Http[R, E, A, B]` app on the ZIO HTTP server you need to convert it to `HttpApp[R, E]` using operators +like `map`, `contramap`, `codec` etc. + +### Using map and contramap + +Below snippet shows an app of type `Http` which takes a string and responds with a string. +```scala + val http: Http[Any, Nothing, String, String] = Http.collect[String] { + case "GET" => "Ok" + } +``` +Now, to convert it into an `HttpApp` +- use `contramap` to transform the input ie `String` to `Request` +- use `map` to transform the output ie `String` to `Response` + +```scala + val app: HttpApp[Any, Nothing] = http.contramap[Request](r => r.method.toString()).map[Response](s => Response.text(s)) +``` + +### Using middleware + +We can also convert an `Http` to `HttpApp` using codec middlewares that take in 2 functions `decoder: AOut => Either[E, AIn]` and +`encoder: BIn => Either[E, BOut]`. Please find more operators in middlewares. + +```scala + val a: Http[Any, Nothing, String, String] = Http.collect[String] { + case "GET" => "Ok" + } + val app: Http[Any, Nothing, Request, Response] = a @@ Middleware.codec[Request,String](r => Right(r.method.toString()),s => Right(Response.text(s))) +``` +## Running an HttpApp + +ZIO HTTP server needs an `HttpApp[R,E]` for running. +We can use `Server.app()` method to bootstrap the server with an `HttpApp[R,E]` +```scala + import zhttp.http._ + import zhttp.service.Server + import zio._ + + object HelloWorld extends App { + val app: HttpApp[Any, Nothing] = Http.ok + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = Server.start(8090, app).exitCode + } +``` \ No newline at end of file From 456d198bace9d5a8ad2b844f63a2a1dd86c3c11f Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 3 Feb 2022 14:25:51 +0530 Subject: [PATCH 62/95] feature: add `Http.apply` (#949) --- zio-http/src/main/scala/zhttp/http/Http.scala | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 566ec45fa7..116f388fe4 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -94,6 +94,11 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def collect[R1 <: R, E1 >: E, A1 <: A, B1 >: B, C](pf: PartialFunction[B1, C]): Http[R1, E1, A1, C] = self >>> Http.collect(pf) + final def collectManaged[R1 <: R, E1 >: E, A1 <: A, B1 >: B, C]( + pf: PartialFunction[B1, ZManaged[R1, E1, C]], + ): Http[R1, E1, A1, C] = + self >>> Http.collectManaged(pf) + /** * Collects some of the results of the http and effectfully converts it to another type. */ @@ -102,11 +107,6 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => ): Http[R1, E1, A1, C] = self >>> Http.collectZIO(pf) - final def collectManaged[R1 <: R, E1 >: E, A1 <: A, B1 >: B, C]( - pf: PartialFunction[B1, ZManaged[R1, E1, C]], - ): Http[R1, E1, A1, C] = - self >>> Http.collectManaged(pf) - /** * Named alias for `<<<` */ @@ -453,6 +453,11 @@ object Http { Handler(http.asInstanceOf[HttpApp[R1, Throwable]], zExec, settings) } + /** + * Equivalent to `Http.succeed` + */ + def apply[B](b: B): Http[Any, Nothing, Any, B] = Http.succeed(b) + /** * Creates an HTTP app which always responds with a 400 status code. */ @@ -466,14 +471,14 @@ object Http { def collectHttp[A]: Http.PartialCollectHttp[A] = Http.PartialCollectHttp(()) /** - * Creates an HTTP app which accepts a request and produces response effectfully. + * Creates an Http app which accepts a request and produces response from a managed resource */ - def collectZIO[A]: Http.PartialCollectZIO[A] = Http.PartialCollectZIO(()) + def collectManaged[A]: Http.PartialCollectManaged[A] = Http.PartialCollectManaged(()) /** - * Creates an Http app which accepts a request and produces response from a managed resource + * Creates an HTTP app which accepts a request and produces response effectfully. */ - def collectManaged[A]: Http.PartialCollectManaged[A] = Http.PartialCollectManaged(()) + def collectZIO[A]: Http.PartialCollectZIO[A] = Http.PartialCollectZIO(()) /** * Combines multiple Http apps into one From 95cddc3d49f25f106b6df382afeb2d9bb014da53 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 3 Feb 2022 14:47:48 +0530 Subject: [PATCH 63/95] Refactor: Drop `toZIO` and `wrapZIO` APIs (#950) * feature: add `Http.apply` * refactor: remove ZIO wrapping APIs --- .../examples/advanced-examples/web-socket-advanced.md | 2 +- .../examples/zio-http-basic-examples/web-socket.md | 2 +- docs/website/docs/v1.x/getting-started.md | 8 ++++---- example/src/main/scala/example/WebSocketAdvanced.scala | 2 +- example/src/main/scala/example/WebSocketEcho.scala | 4 ++-- zio-http/src/main/scala/zhttp/http/Response.scala | 10 ---------- zio-http/src/test/scala/zhttp/http/ResponseSpec.scala | 2 +- 7 files changed, 10 insertions(+), 20 deletions(-) diff --git a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md index 004161a107..1d9f8131bd 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md @@ -49,7 +49,7 @@ object WebSocketAdvanced extends App { private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings ${name}!").wrapZIO + case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings ${name}!")) case Method.GET -> !! / "subscriptions" => socketApp.toResponse } diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md index 8b119c992b..d5396923cd 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md @@ -20,7 +20,7 @@ object WebSocketEcho extends App { private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings {$name}!")) case Method.GET -> !! / "subscriptions" => socket.toResponse } diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index 2d6e72ab8d..47b1b1c188 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -74,11 +74,11 @@ val app = a <> b ### ZIO Integration -For creating effectful apps, you can use `collectZIO` and wrap `Response` using `wrapZIO` to produce ZIO effect value. +For creating effectful apps, you can use `collectZIO` and wrap `Response` with `UIO` to produce ZIO effect value. ```scala val app = Http.collectZIO[Request] { - case Method.GET -> !! / "hello" => Response.text("Hello World").wrapZIO + case Method.GET -> !! / "hello" => UIO(Response.text("Hello World")) } ``` @@ -91,7 +91,7 @@ import zhttp.http._ val app = Http.collectZIO[Request] { case req @ Method.GET -> !! / "fruits" / "a" => - Response.text("URL:" + req.url.path.asString + " Headers: " + req.getHeaders).wrapZIO + UIO(Response.text("URL:" + req.url.path.asString + " Headers: " + req.getHeaders)) case req @ Method.POST -> !! / "fruits" / "a" => req.getBodyAsString.map(Response.text(_)) } @@ -137,7 +137,7 @@ private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text(" } private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings {$name}!")) case Method.GET -> !! / "ws" => socket.toResponse } ``` diff --git a/example/src/main/scala/example/WebSocketAdvanced.scala b/example/src/main/scala/example/WebSocketAdvanced.scala index 48e34955d4..7682a65af3 100644 --- a/example/src/main/scala/example/WebSocketAdvanced.scala +++ b/example/src/main/scala/example/WebSocketAdvanced.scala @@ -49,7 +49,7 @@ object WebSocketAdvanced extends App { private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings ${name}!").wrapZIO + case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings ${name}!")) case Method.GET -> !! / "subscriptions" => socketApp.toResponse } diff --git a/example/src/main/scala/example/WebSocketEcho.scala b/example/src/main/scala/example/WebSocketEcho.scala index 403b6516e7..c1cf4778bf 100644 --- a/example/src/main/scala/example/WebSocketEcho.scala +++ b/example/src/main/scala/example/WebSocketEcho.scala @@ -5,7 +5,7 @@ import zhttp.service.Server import zhttp.socket.{Socket, WebSocketFrame} import zio.duration._ import zio.stream.ZStream -import zio.{App, ExitCode, Schedule, URIO} +import zio.{App, ExitCode, Schedule, UIO, URIO} object WebSocketEcho extends App { private val socket = @@ -19,7 +19,7 @@ object WebSocketEcho extends App { private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings {$name}!")) case Method.GET -> !! / "subscriptions" => socket.toResponse } diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index 94cde589d6..a0174befec 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -61,16 +61,6 @@ final case class Response private ( */ def withServerTime: Response = self.copy(attribute = self.attribute.withServerTime) - /** - * Wraps the current response as a Http - */ - def toHttp: Http[Any, Nothing, Any, Response] = Http.succeed(self) - - /** - * Wraps the current response into a ZIO - */ - def wrapZIO: UIO[Response] = UIO(self) - /** * Extracts the body as ByteBuf */ diff --git a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala index 4ae3c56ac7..c24ad0b339 100644 --- a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala @@ -33,7 +33,7 @@ object ResponseSpec extends DefaultRunnableSpec { ) + suite("toHttp")( testM("should convert response to Http") { - val http = Response.ok.toHttp + val http = Http(Response.ok) assertM(http(()))(equalTo(Response.ok)) }, ), From 7873444f8c41d81ce0c6aa1a8118a3c5ecea018b Mon Sep 17 00:00:00 2001 From: sumawa Date: Thu, 3 Feb 2022 15:36:41 +0530 Subject: [PATCH 64/95] Fix: Server KeepAlive true by default and enable client to set Http version on requests (#792) * IT cases for KeepAlive included in ServerConfigSpec * Allow possibility of modifying server conf in HttpRunnableSpec * reverted Header.scala * reverted Header.scala * reverted Header.scala * struggling with fmt * pull latest from main * reverting changes in ci files * included review recommendations * Concise test description * removed extra comments * readjusted ServerConfigSpec * enable keep alive by default; added more test cases for Http 1.0; tweaked test cases and description * removed configurableServe * removed unnecessary lines; shorter tests * reverted Server disabled and some spec changes * Test/keepalive httpversion (#800) * make httpVersion first param in request methods * tweaked test cases even further using requestHeaderValueByName * changed names * resolved comments, and more tweaking of test * deleted extra line Co-authored-by: Sumant Awasthi * Renamed ServerConfigSpec to KeepAliveSpec * made httpVersion first param in ClientParams, made relevant changes * in EncodeClientParams use http version from ClientParams * a minor change * changed server keepAlive = true by default, also rebased with main Co-authored-by: Sumant Awasthi --- .../example/PlainTextBenchmarkServer.scala | 1 - .../src/main/scala/zhttp/service/Client.scala | 11 ++-- .../zhttp/service/EncodeClientParams.scala | 11 ++-- .../src/main/scala/zhttp/service/Server.scala | 4 +- .../zhttp/http/EncodeClientRequestSpec.scala | 16 +++--- .../zhttp/http/GetBodyAsStringSpec.scala | 6 +-- .../test/scala/zhttp/internal/HttpGen.scala | 4 +- .../zhttp/internal/HttpRunnableSpec.scala | 4 ++ .../scala/zhttp/service/KeepAliveSpec.scala | 50 +++++++++++++++++++ .../test/scala/zhttp/service/ServerSpec.scala | 2 +- .../zhttp/service/WebSocketServerSpec.scala | 2 +- 11 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala diff --git a/example/src/main/scala/example/PlainTextBenchmarkServer.scala b/example/src/main/scala/example/PlainTextBenchmarkServer.scala index 7ebf1ecbef..882ea286ed 100644 --- a/example/src/main/scala/example/PlainTextBenchmarkServer.scala +++ b/example/src/main/scala/example/PlainTextBenchmarkServer.scala @@ -34,7 +34,6 @@ object Main extends App { Server.app(app(response)) ++ Server.port(8080) ++ Server.error(_ => UIO.unit) ++ - Server.keepAlive ++ Server.disableLeakDetection ++ Server.consolidateFlush ++ Server.disableFlowControl diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 1b2e258140..d69c1a23b5 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -37,7 +37,7 @@ final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: promise: Promise[Throwable, ClientResponse], sslOption: ClientSSLOptions, ): Unit = { - val jReq = encodeClientParams(HttpVersion.HTTP_1_1, req) + val jReq = encodeClientParams(req) try { val hand = ClientInboundHandler(rtm, jReq, promise) val host = req.url.host @@ -111,14 +111,14 @@ object Client { method: Method, url: URL, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url)) + request(ClientRequest(method = method, url = url)) def request( method: Method, url: URL, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url), sslOptions) + request(ClientRequest(method = method, url = url), sslOptions) def request( method: Method, @@ -126,7 +126,7 @@ object Client { headers: Headers, sslOptions: ClientSSLOptions, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url, headers), sslOptions) + request(ClientRequest(method = method, url = url, headers = headers), sslOptions) def request( method: Method, @@ -134,7 +134,7 @@ object Client { headers: Headers, content: HttpData, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method, url, headers, content)) + request(ClientRequest(method = method, url = url, headers = headers, data = content)) def request( req: ClientRequest, @@ -148,6 +148,7 @@ object Client { make.flatMap(_.request(req, sslOptions)) final case class ClientRequest( + httpVersion: HttpVersion = HttpVersion.HTTP_1_1, method: Method, url: URL, headers: Headers = Headers.empty, diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala index f9de469a08..eaed85b437 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala @@ -1,16 +1,17 @@ package zhttp.service import io.netty.buffer.Unpooled -import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames, HttpVersion} +import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames} import zhttp.http.HTTP_CHARSET trait EncodeClientParams { /** * Converts client params to JFullHttpRequest */ - def encodeClientParams(jVersion: HttpVersion, req: Client.ClientRequest): FullHttpRequest = { - val method = req.method.asHttpMethod - val url = req.url + def encodeClientParams(req: Client.ClientRequest): FullHttpRequest = { + val httpVersion = req.httpVersion + val method = req.method.asHttpMethod + val url = req.url // As per the spec, the path should contain only the relative path. // Host and port information should be in the headers. @@ -33,7 +34,7 @@ trait EncodeClientParams { headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) } // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. - val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) + val jReq = new DefaultFullHttpRequest(httpVersion, method, path, content) jReq.headers().set(headers) jReq diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 1b21f0d6b2..23f43e34ca 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -127,7 +127,7 @@ object Server { app: HttpApp[R, E] = Http.empty, address: InetSocketAddress = new InetSocketAddress(8080), acceptContinue: Boolean = false, - keepAlive: Boolean = false, + keepAlive: Boolean = true, consolidateFlush: Boolean = false, flowControl: Boolean = true, ) @@ -164,7 +164,7 @@ object Server { val simpleLeakDetection: UServer = LeakDetection(LeakDetectionLevel.SIMPLE) val advancedLeakDetection: UServer = LeakDetection(LeakDetectionLevel.ADVANCED) val paranoidLeakDetection: UServer = LeakDetection(LeakDetectionLevel.PARANOID) - val keepAlive: UServer = KeepAlive(true) + val disableKeepAlive: UServer = Server.KeepAlive(false) val consolidateFlush: UServer = ConsolidateFlush(true) /** diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index b69a33246d..c3c8610bcb 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -1,6 +1,6 @@ package zhttp.http -import io.netty.handler.codec.http.{HttpHeaderNames, HttpVersion} +import io.netty.handler.codec.http.HttpHeaderNames import zhttp.internal.HttpGen import zhttp.service.{Client, EncodeClientParams} import zio.random.Random @@ -32,46 +32,46 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientPara def spec = suite("EncodeClientParams") { testM("method") { check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) assert(req.method())(equalTo(params.method.asHttpMethod)) } } + testM("method on HttpData.File") { check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) assert(req.method())(equalTo(params.method.asHttpMethod)) } } + suite("uri") { testM("uri") { check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) assert(req.uri())(equalTo(params.url.relative.encode)) } } + testM("uri on HttpData.File") { check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) assert(req.uri())(equalTo(params.url.relative.encode)) } } } + testM("content-length") { check(clientParamWithFiniteData(5)) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) assert(req.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong)(equalTo(5L)) } } + testM("host header") { check(anyClientParam) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) val hostHeader = HttpHeaderNames.HOST assert(Option(req.headers().get(hostHeader)))(equalTo(params.url.host)) } } + testM("host header when absolute url") { check(clientParamWithAbsoluteUrl) { params => - val req = encodeClientParams(HttpVersion.HTTP_1_1, params) + val req = encodeClientParams(params) val reqHeaders = req.headers() val hostHeader = HttpHeaderNames.HOST diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index 5e2c97030f..228d985fc9 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -19,8 +19,8 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { check(charsetGen) { charset => val encoded = Client .ClientRequest( - Method.GET, - URL(Path("/")), + method = Method.GET, + url = URL(Path("/")), headers = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes())), ) @@ -33,7 +33,7 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { test("should map bytes to default utf-8 if no charset given") { val data = Chunk.fromArray("abc".getBytes()) val content = HttpData.BinaryChunk(data) - val request = Client.ClientRequest(Method.GET, URL(Path("/")), data = content) + val request = Client.ClientRequest(method = Method.GET, url = URL(Path("/")), data = content) val encoded = request.getBodyAsString val actual = Option(new String(data.toArray, HTTP_CHARSET)) assert(actual)(equalTo(encoded)) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 996deb4d4a..21e7f59927 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -23,7 +23,7 @@ object HttpGen { url <- urlGen headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen - } yield ClientRequest(method, url, headers, data) + } yield ClientRequest(method = method, url = url, headers = headers, data = data) def clientParamsForFileHttpData() = { for { @@ -31,7 +31,7 @@ object HttpGen { method <- HttpGen.method url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) - } yield ClientRequest(method, url, headers, HttpData.fromFile(file)) + } yield ClientRequest(method = method, url = url, headers = headers, data = HttpData.fromFile(file)) } def cookies: Gen[Random with Sized, Cookie] = for { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 4438f517c1..e1895cf5ab 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -1,5 +1,7 @@ package zhttp.internal +import io.netty.handler.codec.http.HttpVersion +import io.netty.handler.codec.http.HttpVersion._ import sttp.client3 import sttp.client3.asynchttpclient.zio.{SttpClient, send} import sttp.client3.{UriContext, asWebSocketUnsafe, basicRequest} @@ -28,6 +30,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => * constituents of a ClientRequest. */ def run( + httpVersion: HttpVersion = HTTP_1_1, path: Path = !!, method: Method = Method.GET, content: String = "", @@ -35,6 +38,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => ): ZIO[R, Throwable, A] = app( Client.ClientRequest( + httpVersion, method, URL(path, Location.Absolute(Scheme.HTTP, "localhost", 0)), headers, diff --git a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala new file mode 100644 index 0000000000..84f6931758 --- /dev/null +++ b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala @@ -0,0 +1,50 @@ +package zhttp.service + +import io.netty.handler.codec.http.{HttpHeaderValues, HttpVersion} +import zhttp.http.{HeaderNames, Headers, Http} +import zhttp.internal.{DynamicServer, HttpRunnableSpec} +import zhttp.service.server._ +import zio.test.Assertion.{equalTo, isNone, isSome} +import zio.test.assertM + +object KeepAliveSpec extends HttpRunnableSpec { + + val app = Http.ok + val connectionCloseHeader = Headers.connection(HttpHeaderValues.CLOSE) + val keepAliveHeader = Headers.connection(HttpHeaderValues.KEEP_ALIVE) + + def keepAliveSpec = suite("KeepAlive") { + suite("Http 1.1") { + testM("without connection close") { + val res = app.deploy.getHeaderValue(HeaderNames.connection).run() + assertM(res)(isNone) + } + + testM("with connection close") { + val res = app.deploy.getHeaderValue(HeaderNames.connection).run(headers = connectionCloseHeader) + assertM(res)(isSome(equalTo("close"))) + } + } + + suite("Http 1.0") { + testM("without keep-alive") { + val res = app.deploy.getHeaderValue(HeaderNames.connection).run(httpVersion = HttpVersion.HTTP_1_0) + assertM(res)(isSome(equalTo("close"))) + } + + testM("with keep-alive") { + val res = app.deploy + .getHeaderValue(HeaderNames.connection) + .run(httpVersion = HttpVersion.HTTP_1_0, headers = keepAliveHeader) + assertM(res)(isNone) + } + } + } + + private val env = EventLoopGroup.nio() ++ ChannelFactory.nio ++ ServerChannelFactory.nio ++ DynamicServer.live + private val appKeepAliveEnabled = serve(DynamicServer.app) + + override def spec = { + suiteM("ServerConfigSpec") { + appKeepAliveEnabled.as(List(keepAliveSpec)).useNow + }.provideCustomLayerShared(env) + } + +} diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 3c721eff22..2e71eca506 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -128,7 +128,7 @@ object ServerSpec extends HttpRunnableSpec { } + testM("POST Request.getBody") { val app = Http.collectZIO[Request] { case req => req.getBody.as(Response.ok) } - val res = app.deploy.getStatus.run(!!, Method.POST, "some text") + val res = app.deploy.getStatus.run(path = !!, method = Method.POST, content = "some text") assertM(res)(equalTo(Status.OK)) } } diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index 5a9095e849..81721d2410 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -27,7 +27,7 @@ object WebSocketServerSpec extends HttpRunnableSpec { testM("Multiple websocket upgrades") { val response = Socket.succeed(WebSocketFrame.text("BAR")).toResponse val app = Http.fromZIO(response) - assertM(app.deployWebSocket.map(_.code.code).run(!! / "subscriptions").repeatN(1024))(equalTo(101)) + assertM(app.deployWebSocket.map(_.code.code).run(path = !! / "subscriptions").repeatN(1024))(equalTo(101)) } } } From ad3cf22af4eee9618bad80afe28a7815bb07dab6 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Thu, 3 Feb 2022 23:51:22 +0530 Subject: [PATCH 65/95] feat: url add `isAbsolute` and `isRelative` operators (#946) * refactor: add type-params * feat: url add `isAbsolute` and `isRelative` operators # Conflicts: # zio-http/src/main/scala/zhttp/http/URL.scala --- zio-http/src/main/scala/zhttp/http/URL.scala | 146 ++++++++++--------- 1 file changed, 78 insertions(+), 68 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index 966dbec60e..a79bd8e36e 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -1,7 +1,7 @@ package zhttp.http import io.netty.handler.codec.http.{QueryStringDecoder, QueryStringEncoder} -import zhttp.http.URL.Fragment +import zhttp.http.URL.{Fragment, Location} import java.net.URI import scala.jdk.CollectionConverters._ @@ -13,29 +13,26 @@ final case class URL( queryParams: Map[String, List[String]] = Map.empty, fragment: Option[Fragment] = None, ) { self => - val host: Option[String] = kind match { - case URL.Location.Relative => None - case abs: URL.Location.Absolute => Option(abs.host) - } + def encode: String = URL.encode(self) - val port: Option[Int] = kind match { + def host: Option[String] = kind match { case URL.Location.Relative => None - case abs: URL.Location.Absolute => Option(abs.port) + case abs: URL.Location.Absolute => Option(abs.host) } - private[zhttp] def relative: URL = self.kind match { - case URL.Location.Relative => self - case _ => self.copy(kind = URL.Location.Relative) + def isAbsolute: Boolean = self.kind match { + case Location.Absolute(_, _, _) => true + case Location.Relative => false } - def encode: String = URL.asString(self) + def isRelative: Boolean = !isAbsolute - def setPath(path: Path) = - copy(path = path) - - def setPath(path: String) = copy(path = Path(path)) + def port: Option[Int] = kind match { + case URL.Location.Relative => None + case abs: URL.Location.Absolute => Option(abs.port) + } - def setHost(host: String) = { + def setHost(host: String): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, host, URL.portFromScheme(Scheme.HTTP)) case abs: URL.Location.Absolute => abs.copy(host = host) @@ -43,13 +40,12 @@ final case class URL( copy(kind = location) } - def setQueryParams(queryParams: Map[String, List[String]]) = - copy(queryParams = queryParams) + def setPath(path: String): URL = copy(path = Path(path)) - def setQueryParams(query: String) = - copy(queryParams = URL.queryParams(query)) + def setPath(path: Path): URL = + copy(path = path) - def setPort(port: Int) = { + def setPort(port: Int): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, "", port) case abs: URL.Location.Absolute => abs.copy(port = port) @@ -58,7 +54,13 @@ final case class URL( copy(kind = location) } - def setScheme(scheme: Scheme) = { + def setQueryParams(query: String): URL = + copy(queryParams = URL.queryParams(query)) + + def setQueryParams(queryParams: Map[String, List[String]]): URL = + copy(queryParams = queryParams) + + def setScheme(scheme: Scheme): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(scheme, "", URL.portFromScheme(scheme)) case abs: URL.Location.Absolute => abs.copy(scheme = scheme) @@ -66,29 +68,50 @@ final case class URL( copy(kind = location) } + + private[zhttp] def relative: URL = self.kind match { + case URL.Location.Relative => self + case _ => self.copy(kind = URL.Location.Relative) + } } object URL { - sealed trait Location - object Location { - case object Relative extends Location - final case class Absolute(scheme: Scheme, host: String, port: Int) extends Location - } + def empty: URL = root - private def queryParams(query: String) = { - if (query == null || query.isEmpty) { - Map.empty[String, List[String]] - } else { - val decoder = new QueryStringDecoder(query, false) - val params = decoder.parameters() - params.asScala.view.map { case (k, v) => (k, v.asScala.toList) }.toMap + def encode(url: URL): String = { + + def path: String = { + val encoder = new QueryStringEncoder(s"${url.path.encode}${url.fragment.fold("")(f => "#" + f.raw)}") + url.queryParams.foreach { case (key, values) => + if (key != "") values.foreach { value => encoder.addParam(key, value) } + } + encoder.toString + } + + url.kind match { + case Location.Relative => path + case Location.Absolute(scheme, host, port) => + if (port == 80 || port == 443) s"${scheme.encode}://$host$path" + else s"${scheme.encode}://$host:$port$path" } } - private def portFromScheme(scheme: Scheme): Int = scheme match { - case Scheme.HTTP => 80 - case Scheme.HTTPS => 443 + def fromString(string: String): Either[HttpError, URL] = { + def invalidURL = Left(HttpError.BadRequest(s"Invalid URL: $string")) + for { + url <- Try(new URI(string)).toEither match { + case Left(_) => invalidURL + case Right(value) => Right(value) + } + url <- (if (url.isAbsolute) fromAbsoluteURI(url) else fromRelativeURI(url)) match { + case None => invalidURL + case Some(value) => Right(value) + } + + } yield url } + def root: URL = URL(!!) + private def fromAbsoluteURI(uri: URI): Option[URL] = { for { scheme <- Scheme.fromString(uri.getScheme) @@ -103,48 +126,35 @@ object URL { path <- Option(uri.getRawPath) } yield URL(Path(path), Location.Relative, queryParams(uri.getRawQuery), Fragment.fromURI(uri)) - def empty: URL = root - - def fromString(string: String): Either[HttpError, URL] = { - def invalidURL = Left(HttpError.BadRequest(s"Invalid URL: $string")) - for { - url <- Try(new URI(string)).toEither match { - case Left(_) => invalidURL - case Right(value) => Right(value) - } - url <- (if (url.isAbsolute) fromAbsoluteURI(url) else fromRelativeURI(url)) match { - case None => invalidURL - case Some(value) => Right(value) - } + private def portFromScheme(scheme: Scheme): Int = scheme match { + case Scheme.HTTP => 80 + case Scheme.HTTPS => 443 + } - } yield url + private def queryParams(query: String) = { + if (query == null || query.isEmpty) { + Map.empty[String, List[String]] + } else { + val decoder = new QueryStringDecoder(query, false) + val params = decoder.parameters() + params.asScala.view.map { case (k, v) => (k, v.asScala.toList) }.toMap + } } - def asString(url: URL): String = { + sealed trait Location - def path: String = { - val encoder = new QueryStringEncoder(s"${url.path.encode}${url.fragment.fold("")(f => "#" + f.raw)}") - url.queryParams.foreach { case (key, values) => - if (key != "") values.foreach { value => encoder.addParam(key, value) } - } - encoder.toString - } + case class Fragment private (raw: String, decoded: String) - url.kind match { - case Location.Relative => path - case Location.Absolute(scheme, host, port) => - if (port == 80 || port == 443) s"${scheme.encode}://$host$path" - else s"${scheme.encode}://$host:$port$path" - } + object Location { + final case class Absolute(scheme: Scheme, host: String, port: Int) extends Location + + case object Relative extends Location } - case class Fragment private (raw: String, decoded: String) object Fragment { def fromURI(uri: URI): Option[Fragment] = for { raw <- Option(uri.getRawFragment) decoded <- Option(uri.getFragment) } yield Fragment(raw, decoded) } - - def root: URL = URL(!!) } From 3a7e14f9864d2f89da817f261ba8507a3778cfef Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Fri, 4 Feb 2022 17:00:31 +0530 Subject: [PATCH 66/95] WebSocket Client Support (#933) * wip: websocket client support * test: add unit test for WebSocket using native websocket client * fix: fromZIO in websocket client spec * refactor: queue usage simplified * feat: websocket client support * refactor: imports optimized * doc: for ClientSocketHandler * refactor: bootstrap method * websocket client with response support * feat: wss support * refactor: SocketProtocol * refactor: add SocketClient example: add WebSocketSimpleClient * refactor: SocketProtocol with type evidence refactor: general clean up * test: for Scheme * refactor: rename asString to encode in URI * refactor: remove example of SecureClient * refactor: url doesn't need to be part of the protocol. Url can be passed as an additional parameter for now. This simplifies the overall design. * refactor: socket client for now will take the complete url * refactor: update client example * refactor: add `connect` operator to SocketApp * refactor: use `url` as a string instead of URL type * refactor: re-order methods * style(*): apply scala fmt * revert: unnecessary changes * feature: add `echo` operator to `Socket` * refactor: update type info * feature: add `Socket.empty` * feature: add `wrapHttp` to Response * feature: add `toHttp` to Socket.scala * style(*): apply scala fmt * refactor: rename asString to encode in Scheme * refactor: cleanup Scheme changes * test: update test assertion * refactor: combine server and client handlers * refactor: add hint in touch for ClientSocketUpgradeHandler * refactor: change package for SocketAppHandler * refactor: rename methods in SocketProtocol * fix: add host header and port in Request automatically * fix: example links (#906) * Update getting-started.md (#907) * refactor: rename asString to encode in Scheme (#905) * Doc: setup (#886) * doc: setup * resolve: PR comments * Update netty-incubator-transport-native-io_uring to 0.0.12.Final (#908) * Documentation for Server (#885) * removed config.md and make configurations part of Server page * added server configurations * markdwon appearing fine in docusaurus generated page * added one missing configuration * Server documentation changed according to PR comments * change note to tip Co-authored-by: Sumant Awasthi Co-authored-by: amitsingh * Performance: Improve performance of `collectM` (#882) * Use ZIO response * fix: improve cancellation performance * refactor: use sticky server * refactor: reduce allocations * revert example * Doc: Added <> operator in getting started (#910) * fix: ++ operator doc * fix: composition * feature: Add `collectManaged` to Http (#909) * Add collectManaged * comment typo * feature: add `echo` operator to `Socket` (#900) * feature: add `Socket.empty` (#901) * feature: add `Socket.empty` * test: add unit test case for Socket#empty Co-authored-by: Shubham Girdhar * refactor: add attribute to Request created by Handler * refactor: remove "case" from ClientInboundHandler * refactor: rename to WebSocketAppHandler * feature: add `toHttp` to Socket.scala (#902) * feature: add `toHttp` to Socket.scala * test: add unit test for `toApp` to Socket.scala Co-authored-by: Shubham Girdhar * cleaning up residue files * refactor: rename `asString` to `encode` in Path * refactor: rename `getHeaders` to `headers` in `ClientRequest` * refactor: simplify client API * refactor: update client params encoder * style: ordering methods in URL.scala * refactor: ClientRequest will throw if the url is invalid * refactor: pass URL instead of String in ClientRequest * test: fix `GetBodyAsStringSpec` * style(*): apply scala fmt * refactor: fix invalid url being passed in HttpRunnableSpec * refactor: Move SSL requirements to ClientAttirbute * feature: add `scheme` operator on URL * feature: add `IsWebSocket` and `isSecure` operators on Scheme * refactor: use named imports in WebSocketAppHandler * test: fix base url for websockets * refactor: update how flags are set inside client * test: add non-zio spec to the spec list * refactor: fix client test * style: scalafmt error and remove TODO * refactor: remove unused handler * refactor: remove host header changes and RequestSpec (#945) * refactor: move java scheme generators to SchemeSpec (#944) * refactor: move java scheme generators to SchemeSpec * refactor: resolve PR comments * feat: url add `isAbsolute` and `isRelative` operators * refactor: rename EncodeClientParams.scala to EncodeClientRequest * fix: handle errors on client connection * style(*): apply scala fmt * refactor: simplify multiple websocket upgrades test (#948) * refactor: resolve PR comments style: fmt fix * refactor: general refactor and style changes Co-authored-by: Shubham Girdhar Co-authored-by: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Co-authored-by: Amit Kumar Singh Co-authored-by: Scala Steward <43047562+scala-steward@users.noreply.github.com> Co-authored-by: sumawa Co-authored-by: Sumant Awasthi Co-authored-by: amitsingh Co-authored-by: James Beem --- build.sbt | 2 - .../src/main/scala/example/HttpsClient.scala | 2 +- .../scala/example/WebSocketSimpleClient.scala | 26 ++ project/Dependencies.scala | 3 - .../src/main/scala/zhttp/http/Scheme.scala | 77 ++++-- zio-http/src/main/scala/zhttp/http/URL.scala | 31 ++- .../src/main/scala/zhttp/service/Client.scala | 251 ++++++++++-------- .../zhttp/service/EncodeClientParams.scala | 42 --- .../zhttp/service/EncodeClientRequest.scala | 38 +++ .../zhttp/service/HttpMessageCodec.scala | 2 +- ...andler.scala => WebSocketAppHandler.scala} | 65 +++-- .../client/ClientChannelInitializer.scala | 26 -- .../service/client/ClientInboundHandler.scala | 31 ++- .../handlers/ClientResponseHandler.scala | 22 -- .../main/scala/zhttp/service/package.scala | 29 +- .../server/ServerChannelInitializer.scala | 2 +- .../service/server/WebSocketUpgrade.scala | 10 +- .../main/scala/zhttp/socket/SocketApp.scala | 7 + .../scala/zhttp/socket/SocketProtocol.scala | 94 +++++-- .../zhttp/http/EncodeClientRequestSpec.scala | 68 +++-- .../zhttp/http/GetBodyAsStringSpec.scala | 53 ++-- .../test/scala/zhttp/http/SchemeSpec.scala | 33 +++ .../src/test/scala/zhttp/http/URLSpec.scala | 6 + .../scala/zhttp/internal/DynamicServer.scala | 43 ++- .../test/scala/zhttp/internal/HttpGen.scala | 55 ++-- .../zhttp/internal/HttpRunnableSpec.scala | 62 ++--- .../scala/zhttp/service/ClientHttpsSpec.scala | 6 +- .../test/scala/zhttp/service/ClientSpec.scala | 8 +- .../scala/zhttp/service/KeepAliveSpec.scala | 9 +- .../test/scala/zhttp/service/SSLSpec.scala | 14 +- .../test/scala/zhttp/service/ServerSpec.scala | 2 +- .../zhttp/service/WebSocketServerSpec.scala | 19 +- 32 files changed, 656 insertions(+), 482 deletions(-) create mode 100644 example/src/main/scala/example/WebSocketSimpleClient.scala delete mode 100644 zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala create mode 100644 zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala rename zio-http/src/main/scala/zhttp/service/{server/ServerSocketHandler.scala => WebSocketAppHandler.scala} (74%) delete mode 100644 zio-http/src/main/scala/zhttp/service/client/ClientChannelInitializer.scala delete mode 100644 zio-http/src/main/scala/zhttp/service/client/content/handlers/ClientResponseHandler.scala create mode 100644 zio-http/src/test/scala/zhttp/http/SchemeSpec.scala diff --git a/build.sbt b/build.sbt index ebaa132997..c669bc3a40 100644 --- a/build.sbt +++ b/build.sbt @@ -97,13 +97,11 @@ lazy val zhttp = (project in file("zio-http")) .settings( testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"), libraryDependencies ++= Seq( - sttp, netty, `zio`, `zio-streams`, `zio-test`, `zio-test-sbt`, - `sttp-zio`, `netty-incubator`, `scala-compact-collection`, ), diff --git a/example/src/main/scala/example/HttpsClient.scala b/example/src/main/scala/example/HttpsClient.scala index 5ffa0dbd8b..12b98c47c1 100644 --- a/example/src/main/scala/example/HttpsClient.scala +++ b/example/src/main/scala/example/HttpsClient.scala @@ -29,7 +29,7 @@ object HttpsClient extends App { ClientSSLOptions.CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) val program = for { - res <- Client.request(url, headers, sslOption) + res <- Client.request(url, headers = headers, ssl = sslOption) data <- res.getBodyAsString _ <- console.putStrLn { data } } yield () diff --git a/example/src/main/scala/example/WebSocketSimpleClient.scala b/example/src/main/scala/example/WebSocketSimpleClient.scala new file mode 100644 index 0000000000..2a669c83c5 --- /dev/null +++ b/example/src/main/scala/example/WebSocketSimpleClient.scala @@ -0,0 +1,26 @@ +package example + +import zhttp.service.{ChannelFactory, EventLoopGroup} +import zhttp.socket.{Socket, WebSocketFrame} +import zio._ +import zio.stream.ZStream + +object WebSocketSimpleClient extends zio.App { + + // Setup client envs + val env = EventLoopGroup.auto() ++ ChannelFactory.auto + + val url = "ws://localhost:8090/subscriptions" + + val app = Socket + .collect[WebSocketFrame] { + case WebSocketFrame.Text("BAZ") => ZStream.succeed(WebSocketFrame.close(1000)) + case frame => ZStream.succeed(frame) + } + .toSocketApp + .connect(url) + + override def run(args: List[String]): URIO[ZEnv, ExitCode] = { + app.exitCode.provideCustomLayer(env) + } +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6e5999d2d0..9a49de38af 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -15,9 +15,6 @@ object Dependencies { val `netty-incubator` = "io.netty.incubator" % "netty-incubator-transport-native-io_uring" % NettyIncubatorVersion classifier "linux-x86_64" - val sttp = "com.softwaremill.sttp.client3" %% "core" % SttpVersion % "test" - val `sttp-zio` = "com.softwaremill.sttp.client3" %% "async-http-client-backend-zio" % SttpVersion % "test" - val zio = "dev.zio" %% "zio" % ZioVersion val `zio-streams` = "dev.zio" %% "zio-streams" % ZioVersion val `zio-test` = "dev.zio" %% "zio-test" % ZioVersion % "test" diff --git a/zio-http/src/main/scala/zhttp/http/Scheme.scala b/zio-http/src/main/scala/zhttp/http/Scheme.scala index 8e6585c851..ad0a77392a 100644 --- a/zio-http/src/main/scala/zhttp/http/Scheme.scala +++ b/zio-http/src/main/scala/zhttp/http/Scheme.scala @@ -1,29 +1,70 @@ package zhttp.http import io.netty.handler.codec.http.HttpScheme +import io.netty.handler.codec.http.websocketx.WebSocketScheme +import zhttp.http.Scheme.{HTTP, HTTPS, WS, WSS} + sealed trait Scheme { self => - def encode: String = Scheme.asString(self) -} -object Scheme { - def asString(self: Scheme): String = self match { + def encode: String = self match { case HTTP => "http" case HTTPS => "https" + case WS => "ws" + case WSS => "wss" + } + + def isHttp: Boolean = !isWebSocket + + def isWebSocket: Boolean = self match { + case Scheme.WS => true + case Scheme.WSS => true + case _ => false + } + + def isSecure: Boolean = self match { + case Scheme.HTTPS => true + case Scheme.WSS => true + case _ => false + } + + def toJHttpScheme: Option[HttpScheme] = self match { + case HTTP => Option(HttpScheme.HTTP) + case HTTPS => Option(HttpScheme.HTTPS) + case _ => None + } + + def toJWebSocketScheme: Option[WebSocketScheme] = self match { + case WS => Option(WebSocketScheme.WS) + case WSS => Option(WebSocketScheme.WSS) + case _ => None + } +} +object Scheme { + + def decode(scheme: String): Option[Scheme] = scheme.toUpperCase match { + case "HTTPS" => Option(HTTPS) + case "HTTP" => Option(HTTP) + case "WS" => Option(WS) + case "WSS" => Option(WSS) + case _ => None } - case object HTTP extends Scheme + def fromJScheme(scheme: HttpScheme): Option[Scheme] = scheme match { + case HttpScheme.HTTPS => Option(HTTPS) + case HttpScheme.HTTP => Option(HTTP) + case _ => None + } + + def fromJScheme(scheme: WebSocketScheme): Option[Scheme] = scheme match { + case WebSocketScheme.WSS => Option(WSS) + case WebSocketScheme.WS => Option(WS) + case _ => None + } + + case object HTTP extends Scheme + case object HTTPS extends Scheme - def fromJScheme(scheme: HttpScheme): Option[Scheme] = - scheme match { - case HttpScheme.HTTPS => Option(HTTPS) - case HttpScheme.HTTP => Option(HTTP) - case _ => None - } - - def fromString(scheme: String): Option[Scheme] = - scheme.toUpperCase match { - case "HTTPS" => Option(HTTPS) - case "HTTP" => Option(HTTP) - case _ => None - } + case object WS extends Scheme + + case object WSS extends Scheme } diff --git a/zio-http/src/main/scala/zhttp/http/URL.scala b/zio-http/src/main/scala/zhttp/http/URL.scala index a79bd8e36e..93a1c9096c 100644 --- a/zio-http/src/main/scala/zhttp/http/URL.scala +++ b/zio-http/src/main/scala/zhttp/http/URL.scala @@ -3,7 +3,8 @@ package zhttp.http import io.netty.handler.codec.http.{QueryStringDecoder, QueryStringEncoder} import zhttp.http.URL.{Fragment, Location} -import java.net.URI +import java.io.IOException +import java.net.{MalformedURLException, URI} import scala.jdk.CollectionConverters._ import scala.util.Try @@ -13,6 +14,7 @@ final case class URL( queryParams: Map[String, List[String]] = Map.empty, fragment: Option[Fragment] = None, ) { self => + def encode: String = URL.encode(self) def host: Option[String] = kind match { @@ -32,6 +34,11 @@ final case class URL( case abs: URL.Location.Absolute => Option(abs.port) } + def scheme: Option[Scheme] = kind match { + case Location.Absolute(scheme, _, _) => Some(scheme) + case Location.Relative => None + } + def setHost(host: String): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, host, URL.portFromScheme(Scheme.HTTP)) @@ -40,11 +47,11 @@ final case class URL( copy(kind = location) } - def setPath(path: String): URL = copy(path = Path(path)) - def setPath(path: Path): URL = copy(path = path) + def setPath(path: String): URL = copy(path = Path(path)) + def setPort(port: Int): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(Scheme.HTTP, "", port) @@ -54,12 +61,12 @@ final case class URL( copy(kind = location) } - def setQueryParams(query: String): URL = - copy(queryParams = URL.queryParams(query)) - def setQueryParams(queryParams: Map[String, List[String]]): URL = copy(queryParams = queryParams) + def setQueryParams(query: String): URL = + copy(queryParams = URL.queryParams(query)) + def setScheme(scheme: Scheme): URL = { val location = kind match { case URL.Location.Relative => URL.Location.Absolute(scheme, "", URL.portFromScheme(scheme)) @@ -75,7 +82,7 @@ final case class URL( } } object URL { - def empty: URL = root + def empty: URL = URL(!!) def encode(url: URL): String = { @@ -95,8 +102,8 @@ object URL { } } - def fromString(string: String): Either[HttpError, URL] = { - def invalidURL = Left(HttpError.BadRequest(s"Invalid URL: $string")) + def fromString(string: String): Either[IOException, URL] = { + def invalidURL = Left(new MalformedURLException(s"""Invalid URL: "$string"""")) for { url <- Try(new URI(string)).toEither match { case Left(_) => invalidURL @@ -114,7 +121,7 @@ object URL { private def fromAbsoluteURI(uri: URI): Option[URL] = { for { - scheme <- Scheme.fromString(uri.getScheme) + scheme <- Scheme.decode(uri.getScheme) host <- Option(uri.getHost) path <- Option(uri.getRawPath) port = Option(uri.getPort).filter(_ != -1).getOrElse(portFromScheme(scheme)) @@ -127,8 +134,8 @@ object URL { } yield URL(Path(path), Location.Relative, queryParams(uri.getRawQuery), Fragment.fromURI(uri)) private def portFromScheme(scheme: Scheme): Int = scheme match { - case Scheme.HTTP => 80 - case Scheme.HTTPS => 443 + case Scheme.HTTP | Scheme.WS => 80 + case Scheme.HTTPS | Scheme.WSS => 443 } private def queryParams(query: String) = { diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index d69c1a23b5..d8ce33f9cb 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -1,167 +1,181 @@ package zhttp.service import io.netty.bootstrap.Bootstrap -import io.netty.buffer.{ByteBuf, ByteBufUtil} +import io.netty.buffer.{ByteBuf, ByteBufUtil, Unpooled} import io.netty.channel.{ Channel, ChannelFactory => JChannelFactory, + ChannelFuture => JChannelFuture, ChannelHandlerContext, + ChannelInitializer, EventLoopGroup => JEventLoopGroup, } -import io.netty.handler.codec.http.HttpVersion -import zhttp.http.URL.Location +import io.netty.handler.codec.http._ +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler import zhttp.http._ import zhttp.http.headers.HeaderExtension import zhttp.service import zhttp.service.Client.{ClientRequest, ClientResponse} import zhttp.service.client.ClientSSLHandler.ClientSSLOptions -import zhttp.service.client.{ClientChannelInitializer, ClientInboundHandler} +import zhttp.service.client.{ClientInboundHandler, ClientSSLHandler} +import zhttp.socket.{Socket, SocketApp} import zio.{Chunk, Promise, Task, ZIO} -import java.net.{InetAddress, InetSocketAddress} +import java.net.{InetAddress, InetSocketAddress, URI} -final case class Client(rtm: HttpRuntime[Any], cf: JChannelFactory[Channel], el: JEventLoopGroup) +final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el: JEventLoopGroup) extends HttpMessageCodec { - def request( - request: Client.ClientRequest, - sslOption: ClientSSLOptions = ClientSSLOptions.DefaultSSL, - ): Task[Client.ClientResponse] = + + def request(request: Client.ClientRequest): Task[Client.ClientResponse] = for { promise <- Promise.make[Throwable, Client.ClientResponse] - _ <- Task(asyncRequest(request, promise, sslOption)).catchAll(cause => promise.fail(cause)) + jReq <- encode(request) + _ <- ChannelFuture + .unit(unsafeRequest(request, jReq, promise)) + .catchAll(cause => promise.fail(cause)) res <- promise.await } yield res - private def asyncRequest( + def socket( + url: URL, + headers: Headers = Headers.empty, + socketApp: SocketApp[R], + sslOptions: ClientSSLOptions = ClientSSLOptions.DefaultSSL, + ): ZIO[R, Throwable, ClientResponse] = for { + env <- ZIO.environment[R] + res <- request( + ClientRequest( + url, + Method.GET, + headers, + attribute = Client.Attribute(socketApp = Some(socketApp.provide(env)), ssl = Some(sslOptions)), + ), + ) + } yield res + + /** + * It handles both - Websocket and HTTP requests. + */ + private def unsafeRequest( req: ClientRequest, + jReq: FullHttpRequest, promise: Promise[Throwable, ClientResponse], - sslOption: ClientSSLOptions, - ): Unit = { - val jReq = encodeClientParams(req) + ): JChannelFuture = { + try { - val hand = ClientInboundHandler(rtm, jReq, promise) - val host = req.url.host - val port = req.url.port.getOrElse(80) match { - case -1 => 80 - case port => port - } - val scheme = req.url.kind match { - case Location.Relative => "" - case Location.Absolute(scheme, _, _) => scheme.encode + val uri = new URI(jReq.uri()) + val host = if (uri.getHost == null) jReq.headers().get(HeaderNames.host) else uri.getHost + + assert(host != null, "Host name is required") + + val port = req.url.port.getOrElse(80) + + val isWebSocket = req.url.scheme.exists(_.isWebSocket) + val isSSL = req.url.scheme.exists(_.isSecure) + + val initializer = new ChannelInitializer[Channel]() { + override def initChannel(ch: Channel): Unit = { + + val pipeline = ch.pipeline() + val sslOption: ClientSSLOptions = req.attribute.ssl.getOrElse(ClientSSLOptions.DefaultSSL) + + // If a https or wss request is made we need to add the ssl handler at the starting of the pipeline. + if (isSSL) pipeline.addLast(SSL_HANDLER, ClientSSLHandler.ssl(sslOption).newHandler(ch.alloc)) + + // Adding default client channel handlers + pipeline.addLast(HTTP_CLIENT_CODEC, new HttpClientCodec) + + // ObjectAggregator is used to work with FullHttpRequests and FullHttpResponses + // This is also required to make WebSocketHandlers work + pipeline.addLast(HTTP_OBJECT_AGGREGATOR, new HttpObjectAggregator(Int.MaxValue)) + + // ClientInboundHandler is used to take ClientResponse from FullHttpResponse + pipeline.addLast(CLIENT_INBOUND_HANDLER, new ClientInboundHandler(rtm, jReq, promise, isWebSocket)) + + // Add WebSocketHandlers if it's a `ws` or `wss` request + if (isWebSocket) { + val headers = req.getHeaders.encode + val app = req.attribute.socketApp.getOrElse(Socket.empty.toSocketApp) + val config = app.protocol.clientBuilder + .customHeaders(headers) + .webSocketUri(req.url.encode) + .build() + + // Handles the heavy lifting required to upgrade the connection to a WebSocket connection + pipeline.addLast(WEB_SOCKET_CLIENT_PROTOCOL_HANDLER, new WebSocketClientProtocolHandler(config)) + pipeline.addLast(WEB_SOCKET_HANDLER, new WebSocketAppHandler(rtm, app)) + } + () + } } - val init = ClientChannelInitializer(hand, scheme, sslOption) - val jboo = new Bootstrap().channelFactory(cf).group(el).handler(init) - if (host.isDefined) jboo.remoteAddress(new InetSocketAddress(host.get, port)) + val jBoo = new Bootstrap().channelFactory(cf).group(el).handler(initializer) - jboo.connect(): Unit + jBoo.remoteAddress(new InetSocketAddress(host, port)) + + jBoo.connect() } catch { - case _: Throwable => + case err: Throwable => if (jReq.refCnt() > 0) { jReq.release(jReq.refCnt()): Unit } + throw err } } - } object Client { - def make: ZIO[EventLoopGroup with ChannelFactory, Nothing, Client] = for { - cf <- ZIO.access[ChannelFactory](_.get) - el <- ZIO.access[EventLoopGroup](_.get) - zx <- HttpRuntime.default[Any] + def make[R]: ZIO[R with EventLoopGroup with ChannelFactory, Nothing, Client[R]] = for { + cf <- ZIO.service[JChannelFactory[Channel]] + el <- ZIO.service[JEventLoopGroup] + zx <- HttpRuntime.default[R] } yield service.Client(zx, cf, el) def request( url: String, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = for { - url <- ZIO.fromEither(URL.fromString(url)) - res <- request(Method.GET, url) - } yield res - - def request( - url: String, - sslOptions: ClientSSLOptions, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = for { - url <- ZIO.fromEither(URL.fromString(url)) - res <- request(Method.GET, url, sslOptions) - } yield res - - def request( - url: String, - headers: Headers, - sslOptions: ClientSSLOptions = ClientSSLOptions.DefaultSSL, + method: Method = Method.GET, + headers: Headers = Headers.empty, + content: HttpData = HttpData.empty, + ssl: ClientSSLOptions = ClientSSLOptions.DefaultSSL, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = for { - url <- ZIO.fromEither(URL.fromString(url)) - res <- request(Method.GET, url, headers, sslOptions) + uri <- ZIO.fromEither(URL.fromString(url)) + res <- request(ClientRequest(uri, method, headers, content, attribute = Attribute(ssl = Some(ssl)))) } yield res def request( - url: String, - headers: Headers, - content: HttpData, + request: ClientRequest, ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = for { - url <- ZIO.fromEither(URL.fromString(url)) - res <- request(Method.GET, url, headers, content) + clt <- make[Any] + res <- clt.request(request) } yield res - def request( - method: Method, - url: URL, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method = method, url = url)) - - def request( - method: Method, - url: URL, - sslOptions: ClientSSLOptions, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method = method, url = url), sslOptions) - - def request( - method: Method, - url: URL, - headers: Headers, - sslOptions: ClientSSLOptions, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method = method, url = url, headers = headers), sslOptions) - - def request( - method: Method, - url: URL, - headers: Headers, - content: HttpData, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - request(ClientRequest(method = method, url = url, headers = headers, data = content)) - - def request( - req: ClientRequest, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - make.flatMap(_.request(req)) - - def request( - req: ClientRequest, - sslOptions: ClientSSLOptions, - ): ZIO[EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = - make.flatMap(_.request(req, sslOptions)) + def socket[R]( + url: String, + app: SocketApp[R], + headers: Headers = Headers.empty, + sslOptions: ClientSSLOptions = ClientSSLOptions.DefaultSSL, + ): ZIO[R with EventLoopGroup with ChannelFactory, Throwable, ClientResponse] = { + for { + clt <- make[R] + uri <- ZIO.fromEither(URL.fromString(url)) + res <- clt.socket(uri, headers, app, sslOptions) + } yield res + } final case class ClientRequest( - httpVersion: HttpVersion = HttpVersion.HTTP_1_1, - method: Method, url: URL, + method: Method = Method.GET, headers: Headers = Headers.empty, - data: HttpData = HttpData.empty, + private[zhttp] val data: HttpData = HttpData.empty, + private[zhttp] val version: HttpVersion = HttpVersion.HTTP_1_1, + private[zhttp] val attribute: Attribute = Attribute.empty, private val channelContext: ChannelHandlerContext = null, - ) extends HeaderExtension[ClientRequest] { self => + ) extends HeaderExtension[ClientRequest] { + self => - def getBodyAsString: Option[String] = data match { - case HttpData.Text(text, _) => Some(text) - case HttpData.BinaryChunk(data) => Some(new String(data.toArray, HTTP_CHARSET)) - case HttpData.BinaryByteBuf(data) => Some(data.toString(HTTP_CHARSET)) - case _ => Option.empty - } + def getBodyAsString: Task[String] = getBodyAsByteBuf.map(_.toString(getHeaders.getCharset)) def getHeaders: Headers = headers @@ -177,10 +191,13 @@ object Client { */ override def updateHeaders(update: Headers => Headers): ClientRequest = self.copy(headers = update(self.getHeaders)) + + private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = data.toByteBuf } final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) - extends HeaderExtension[ClientResponse] { self => + extends HeaderExtension[ClientResponse] { + self => def getBody: Task[Chunk[Byte]] = Task(Chunk.fromArray(ByteBufUtil.getBytes(buffer))) @@ -192,4 +209,22 @@ object Client { override def updateHeaders(update: Headers => Headers): ClientResponse = self.copy(headers = update(headers)) } + + case class Attribute(socketApp: Option[SocketApp[Any]] = None, ssl: Option[ClientSSLOptions] = None) { self => + def withSSL(ssl: ClientSSLOptions): Attribute = self.copy(ssl = Some(ssl)) + def withSocketApp(socketApp: SocketApp[Any]): Attribute = self.copy(socketApp = Some(socketApp)) + } + + object ClientResponse { + private[zhttp] def unsafeFromJResponse(jRes: FullHttpResponse): ClientResponse = { + val status = Status.fromHttpResponseStatus(jRes.status()) + val headers = Headers.decode(jRes.headers()) + val content = Unpooled.copiedBuffer(jRes.content()) + Client.ClientResponse(status, headers, content) + } + } + + object Attribute { + def empty: Attribute = Attribute() + } } diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala deleted file mode 100644 index eaed85b437..0000000000 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientParams.scala +++ /dev/null @@ -1,42 +0,0 @@ -package zhttp.service - -import io.netty.buffer.Unpooled -import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames} -import zhttp.http.HTTP_CHARSET -trait EncodeClientParams { - - /** - * Converts client params to JFullHttpRequest - */ - def encodeClientParams(req: Client.ClientRequest): FullHttpRequest = { - val httpVersion = req.httpVersion - val method = req.method.asHttpMethod - val url = req.url - - // As per the spec, the path should contain only the relative path. - // Host and port information should be in the headers. - val path = url.relative.encode - - val content = req.getBodyAsString match { - case Some(text) => Unpooled.copiedBuffer(text, HTTP_CHARSET) - case None => Unpooled.EMPTY_BUFFER - } - - val encodedReqHeaders = req.getHeaders.encode - - val headers = url.host match { - case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) - case None => encodedReqHeaders - } - - val writerIndex = content.writerIndex() - if (writerIndex != 0) { - headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString()) - } - // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. - val jReq = new DefaultFullHttpRequest(httpVersion, method, path, content) - jReq.headers().set(headers) - - jReq - } -} diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala new file mode 100644 index 0000000000..8825ea8b41 --- /dev/null +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala @@ -0,0 +1,38 @@ +package zhttp.service + +import io.netty.handler.codec.http.{DefaultFullHttpRequest, FullHttpRequest, HttpHeaderNames} +import zio.Task + +trait EncodeClientRequest { + + /** + * Converts client params to JFullHttpRequest + */ + def encode(req: Client.ClientRequest): Task[FullHttpRequest] = + req.getBodyAsByteBuf.map { content => + val method = req.method.asHttpMethod + val jVersion = req.version + + // As per the spec, the path should contain only the relative path. + // Host and port information should be in the headers. + val path = req.url.relative.encode + + val encodedReqHeaders = req.getHeaders.encode + + val headers = req.url.host match { + case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) + case None => encodedReqHeaders + } + + val writerIndex = content.writerIndex() + if (writerIndex != 0) { + headers.set(HttpHeaderNames.CONTENT_LENGTH, writerIndex.toString) + } + + // TODO: we should also add a default user-agent req header as some APIs might reject requests without it. + val jReq = new DefaultFullHttpRequest(jVersion, method, path, content) + jReq.headers().set(headers) + + jReq + } +} diff --git a/zio-http/src/main/scala/zhttp/service/HttpMessageCodec.scala b/zio-http/src/main/scala/zhttp/service/HttpMessageCodec.scala index 8ca22d57c4..4054b9338b 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpMessageCodec.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpMessageCodec.scala @@ -1,3 +1,3 @@ package zhttp.service -trait HttpMessageCodec extends EncodeClientParams {} +trait HttpMessageCodec extends EncodeClientRequest {} diff --git a/zio-http/src/main/scala/zhttp/service/server/ServerSocketHandler.scala b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala similarity index 74% rename from zio-http/src/main/scala/zhttp/service/server/ServerSocketHandler.scala rename to zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala index 9e724bd841..35c2ddc458 100644 --- a/zio-http/src/main/scala/zhttp/service/server/ServerSocketHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala @@ -1,37 +1,23 @@ -package zhttp.service.server +package zhttp.service import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} -import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.{ - HandshakeComplete, - ServerHandshakeStateEvent, -} -import io.netty.handler.codec.http.websocketx.{WebSocketFrame => JWebSocketFrame} -import zhttp.service.{ChannelFuture, HttpRuntime} +import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler.ClientHandshakeStateEvent +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.ServerHandshakeStateEvent +import io.netty.handler.codec.http.websocketx.{WebSocketFrame => JWebSocketFrame, WebSocketServerProtocolHandler} import zhttp.socket.SocketApp.Handle import zhttp.socket.{SocketApp, WebSocketFrame} import zio.stream.ZStream /** - * Creates a new websocket handler + * A generic SocketApp handler that can be used on both - the client and the server. */ -final case class ServerSocketHandler[R]( +final class WebSocketAppHandler[R]( zExec: HttpRuntime[R], - ss: SocketApp[R], + app: SocketApp[R], ) extends SimpleChannelInboundHandler[JWebSocketFrame] { - /** - * Unsafe channel reader for WSFrame - */ - - private def writeAndFlush(ctx: ChannelHandlerContext, stream: ZStream[R, Throwable, WebSocketFrame]): Unit = - zExec.unsafeRun(ctx)( - stream - .mapM(frame => ChannelFuture.unit(ctx.writeAndFlush(frame.toWebSocketFrame))) - .runDrain, - ) - override def channelRead0(ctx: ChannelHandlerContext, msg: JWebSocketFrame): Unit = - ss.message match { + app.message match { case Some(v) => WebSocketFrame.fromJFrame(msg) match { case Some(frame) => writeAndFlush(ctx, v(frame)) @@ -40,18 +26,18 @@ final case class ServerSocketHandler[R]( case None => () } - override def exceptionCaught(ctx: ChannelHandlerContext, x: Throwable): Unit = { - ss.error match { - case Some(v) => zExec.unsafeRun(ctx)(v(x).uninterruptible) - case None => ctx.fireExceptionCaught(x) + override def channelUnregistered(ctx: ChannelHandlerContext): Unit = { + app.close match { + case Some(v) => zExec.unsafeRun(ctx)(v(ctx.channel().remoteAddress()).uninterruptible) + case None => ctx.fireChannelUnregistered() } () } - override def channelUnregistered(ctx: ChannelHandlerContext): Unit = { - ss.close match { - case Some(v) => zExec.unsafeRun(ctx)(v(ctx.channel().remoteAddress()).uninterruptible) - case None => ctx.fireChannelUnregistered() + override def exceptionCaught(ctx: ChannelHandlerContext, x: Throwable): Unit = { + app.error match { + case Some(v) => zExec.unsafeRun(ctx)(v(x).uninterruptible) + case None => ctx.fireExceptionCaught(x) } () } @@ -59,8 +45,8 @@ final case class ServerSocketHandler[R]( override def userEventTriggered(ctx: ChannelHandlerContext, event: AnyRef): Unit = { event match { - case _: HandshakeComplete => - ss.open match { + case _: WebSocketServerProtocolHandler.HandshakeComplete | ClientHandshakeStateEvent.HANDSHAKE_COMPLETE => + app.open match { case Some(v) => v match { case Handle.WithEffect(f) => zExec.unsafeRun(ctx)(f(ctx.channel().remoteAddress())) @@ -68,8 +54,8 @@ final case class ServerSocketHandler[R]( } case None => ctx.fireUserEventTriggered(event) } - case m: ServerHandshakeStateEvent if m == ServerHandshakeStateEvent.HANDSHAKE_TIMEOUT => - ss.timeout match { + case ServerHandshakeStateEvent.HANDSHAKE_TIMEOUT | ClientHandshakeStateEvent.HANDSHAKE_TIMEOUT => + app.timeout match { case Some(v) => zExec.unsafeRun(ctx)(v) case None => ctx.fireUserEventTriggered(event) } @@ -77,4 +63,15 @@ final case class ServerSocketHandler[R]( } () } + + /** + * Unsafe channel reader for WSFrame + */ + + private def writeAndFlush(ctx: ChannelHandlerContext, stream: ZStream[R, Throwable, WebSocketFrame]): Unit = + zExec.unsafeRun(ctx)( + stream + .mapM(frame => ChannelFuture.unit(ctx.writeAndFlush(frame.toWebSocketFrame))) + .runDrain, + ) } diff --git a/zio-http/src/main/scala/zhttp/service/client/ClientChannelInitializer.scala b/zio-http/src/main/scala/zhttp/service/client/ClientChannelInitializer.scala deleted file mode 100644 index 0945b0d66f..0000000000 --- a/zio-http/src/main/scala/zhttp/service/client/ClientChannelInitializer.scala +++ /dev/null @@ -1,26 +0,0 @@ -package zhttp.service.client - -import io.netty.channel.{Channel, ChannelHandler, ChannelInitializer, ChannelPipeline} -import io.netty.handler.codec.http.{HttpClientCodec, HttpObjectAggregator} -import zhttp.service.client.ClientSSLHandler.ClientSSLOptions -import zhttp.service.client.content.handlers.ClientResponseHandler - -final case class ClientChannelInitializer[R]( - channelHandler: ChannelHandler, - scheme: String, - sslOption: ClientSSLOptions = ClientSSLOptions.DefaultSSL, -) extends ChannelInitializer[Channel]() { - override def initChannel(ch: Channel): Unit = { - val p: ChannelPipeline = ch - .pipeline() - .addLast(new HttpClientCodec) - .addLast(new HttpObjectAggregator(Int.MaxValue)) - .addLast(new ClientResponseHandler()) - .addLast(channelHandler) - - if (scheme == "https") { - p.addFirst(ClientSSLHandler.ssl(sslOption).newHandler(ch.alloc)) - } - () - } -} diff --git a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala index 1cc87d3c1a..52da0915b9 100644 --- a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala @@ -1,7 +1,7 @@ package zhttp.service.client import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} -import io.netty.handler.codec.http.FullHttpRequest +import io.netty.handler.codec.http.{FullHttpRequest, FullHttpResponse} import zhttp.service.Client.ClientResponse import zhttp.service.HttpRuntime import zio.Promise @@ -9,23 +9,34 @@ import zio.Promise /** * Handles HTTP response */ -final case class ClientInboundHandler[R]( +final class ClientInboundHandler[R]( zExec: HttpRuntime[R], jReq: FullHttpRequest, promise: Promise[Throwable, ClientResponse], -) extends SimpleChannelInboundHandler[ClientResponse](false) { + isWebSocket: Boolean, +) extends SimpleChannelInboundHandler[FullHttpResponse](true) { - override def channelRead0(ctx: ChannelHandlerContext, clientResponse: ClientResponse): Unit = { - zExec.unsafeRun(ctx)(promise.succeed(clientResponse)) + override def channelActive(ctx: ChannelHandlerContext): Unit = { + if (isWebSocket) { + ctx.fireChannelActive(): Unit + } else { + ctx.writeAndFlush(jReq) + releaseRequest() + } } - override def exceptionCaught(ctx: ChannelHandlerContext, error: Throwable): Unit = { - zExec.unsafeRun(ctx)(promise.fail(error)) - releaseRequest() + override def channelRead0(ctx: ChannelHandlerContext, msg: FullHttpResponse): Unit = { + msg.touch("handlers.ClientInboundHandler-channelRead0") + + zExec.unsafeRun(ctx)(promise.succeed(ClientResponse.unsafeFromJResponse(msg))) + if (isWebSocket) { + ctx.fireChannelRead(msg.retain()) + ctx.pipeline().remove(ctx.name()): Unit + } } - override def channelActive(ctx: ChannelHandlerContext): Unit = { - ctx.writeAndFlush(jReq): Unit + override def exceptionCaught(ctx: ChannelHandlerContext, error: Throwable): Unit = { + zExec.unsafeRun(ctx)(promise.fail(error)) releaseRequest() } diff --git a/zio-http/src/main/scala/zhttp/service/client/content/handlers/ClientResponseHandler.scala b/zio-http/src/main/scala/zhttp/service/client/content/handlers/ClientResponseHandler.scala deleted file mode 100644 index a77c3daf2c..0000000000 --- a/zio-http/src/main/scala/zhttp/service/client/content/handlers/ClientResponseHandler.scala +++ /dev/null @@ -1,22 +0,0 @@ -package zhttp.service.client.content.handlers - -import io.netty.buffer.Unpooled -import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} -import io.netty.handler.codec.http.FullHttpResponse -import zhttp.http.{Headers, Status} -import zhttp.service.Client - -/** - * Transforms a Netty FullHttpResponse into a zio-http specific ClientResponse. - */ -final class ClientResponseHandler() extends SimpleChannelInboundHandler[FullHttpResponse](true) { - - override def channelRead0(ctx: ChannelHandlerContext, msg: FullHttpResponse): Unit = { - val status = Status.fromHttpResponseStatus(msg.status()) - val headers = Headers.decode(msg.headers()) - val content = Unpooled.copiedBuffer(msg.content()) - val response = Client.ClientResponse(status, headers, content) - ctx.fireChannelRead(response) - () - } -} diff --git a/zio-http/src/main/scala/zhttp/service/package.scala b/zio-http/src/main/scala/zhttp/service/package.scala index ac3fbcdbe1..fe03605b89 100644 --- a/zio-http/src/main/scala/zhttp/service/package.scala +++ b/zio-http/src/main/scala/zhttp/service/package.scala @@ -4,19 +4,22 @@ import io.netty.channel.{Channel, ChannelFactory => JChannelFactory, EventLoopGr import zio.Has package object service { - private[service] val AUTO_RELEASE_REQUEST = false - private[service] val SERVER_CODEC_HANDLER = "SERVER_CODEC" - private[service] val OBJECT_AGGREGATOR = "OBJECT_AGGREGATOR" - private[service] val HTTP_REQUEST_HANDLER = "HTTP_REQUEST" - private[service] val HTTP_RESPONSE_HANDLER = "HTTP_RESPONSE" - private[service] val HTTP_KEEPALIVE_HANDLER = "HTTP_KEEPALIVE" - private[service] val FLOW_CONTROL_HANDLER = "FLOW_CONTROL_HANDLER" - private[service] val WEB_SOCKET_HANDLER = "WEB_SOCKET_HANDLER" - private[service] val SSL_HANDLER = "SSL_HANDLER" - private[service] val HTTP_ON_HTTPS_HANDLER = "HTTP_ON_HTTPS_HANDLER" - private[service] val HTTP_SERVER_CODEC = "HTTP_SERVER_CODEC" - private[service] val HTTP_SERVER_EXPECT_CONTINUE = "HTTP_SERVER_EXPECT_CONTINUE" - private[service] val HTTP_SERVER_FLUSH_CONSOLIDATION = "HTTP_SERVER_FLUSH_CONSOLIDATION" + private[service] val AUTO_RELEASE_REQUEST = false + private[service] val SERVER_CODEC_HANDLER = "SERVER_CODEC" + private[service] val HTTP_OBJECT_AGGREGATOR = "HTTP_OBJECT_AGGREGATOR" + private[service] val HTTP_REQUEST_HANDLER = "HTTP_REQUEST" + private[service] val HTTP_RESPONSE_HANDLER = "HTTP_RESPONSE" + private[service] val HTTP_KEEPALIVE_HANDLER = "HTTP_KEEPALIVE" + private[service] val FLOW_CONTROL_HANDLER = "FLOW_CONTROL_HANDLER" + private[service] val WEB_SOCKET_HANDLER = "WEB_SOCKET_HANDLER" + private[service] val SSL_HANDLER = "SSL_HANDLER" + private[service] val HTTP_ON_HTTPS_HANDLER = "HTTP_ON_HTTPS_HANDLER" + private[service] val HTTP_SERVER_CODEC = "HTTP_SERVER_CODEC" + private[service] val HTTP_CLIENT_CODEC = "HTTP_CLIENT_CODEC" + private[service] val HTTP_SERVER_EXPECT_CONTINUE = "HTTP_SERVER_EXPECT_CONTINUE" + private[service] val HTTP_SERVER_FLUSH_CONSOLIDATION = "HTTP_SERVER_FLUSH_CONSOLIDATION" + private[service] val CLIENT_INBOUND_HANDLER = "CLIENT_INBOUND_HANDLER" + private[service] val WEB_SOCKET_CLIENT_PROTOCOL_HANDLER = "WEB_SOCKET_CLIENT_PROTOCOL_HANDLER" type ChannelFactory = Has[JChannelFactory[Channel]] type EventLoopGroup = Has[JEventLoopGroup] diff --git a/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala b/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala index e66f840e20..d78ac3ce75 100644 --- a/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala +++ b/zio-http/src/main/scala/zhttp/service/server/ServerChannelInitializer.scala @@ -47,7 +47,7 @@ final case class ServerChannelInitializer[R]( // ObjectAggregator // Always add ObjectAggregator - pipeline.addLast(OBJECT_AGGREGATOR, new HttpObjectAggregator(cfg.maxRequestSize)) + pipeline.addLast(HTTP_OBJECT_AGGREGATOR, new HttpObjectAggregator(cfg.maxRequestSize)) // ExpectContinueHandler // Add expect continue handler is settings is true diff --git a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala index 5ca7cac28d..fea3173516 100644 --- a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala +++ b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala @@ -4,12 +4,14 @@ import io.netty.channel.{ChannelHandler, ChannelHandlerContext} import io.netty.handler.codec.http._ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler import zhttp.http.{Response, Status} -import zhttp.service.{HttpRuntime, WEB_SOCKET_HANDLER} +import zhttp.service.{HttpRuntime, WEB_SOCKET_HANDLER, WebSocketAppHandler} /** * Module to switch protocol to websockets */ trait WebSocketUpgrade[R] { self: ChannelHandler => + val runtime: HttpRuntime[R] + final def isWebSocket(res: Response): Boolean = res.status.asJava.code() == Status.SWITCHING_PROTOCOLS.asJava.code() && res.attribute.socketApp.nonEmpty @@ -22,11 +24,9 @@ trait WebSocketUpgrade[R] { self: ChannelHandler => ctx .channel() .pipeline() - .addLast(new WebSocketServerProtocolHandler(app.get.protocol.javaConfig)) - .addLast(WEB_SOCKET_HANDLER, ServerSocketHandler(runtime, app.get)) + .addLast(new WebSocketServerProtocolHandler(app.get.protocol.serverBuilder.build())) + .addLast(WEB_SOCKET_HANDLER, new WebSocketAppHandler(runtime, app.get)) ctx.channel().eventLoop().submit(() => ctx.fireChannelRead(jReq)): Unit } - - val runtime: HttpRuntime[R] } diff --git a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala index 43dea50673..9a96e96e83 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala @@ -1,6 +1,7 @@ package zhttp.socket import zhttp.http.Response +import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zhttp.socket.SocketApp.Handle.{WithEffect, WithSocket} import zhttp.socket.SocketApp.{Connection, Handle} import zio.stream.ZStream @@ -18,6 +19,12 @@ final case class SocketApp[-R]( protocol: SocketProtocol = SocketProtocol.default, ) { self => + /** + * Creates a socket connection on the provided URL. Typically used to connect as a client. + */ + def connect(url: String): ZIO[R with EventLoopGroup with ChannelFactory, Throwable, Client.ClientResponse] = + Client.socket(url, self) + /** * Called when the websocket connection is closed successfully. */ diff --git a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala index 2a969ec797..598743a980 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala @@ -1,6 +1,10 @@ package zhttp.socket -import io.netty.handler.codec.http.websocketx.{WebSocketCloseStatus, WebSocketServerProtocolConfig} +import io.netty.handler.codec.http.websocketx.{ + WebSocketClientProtocolConfig, + WebSocketCloseStatus, + WebSocketServerProtocolConfig, +} import zio.duration.Duration /** @@ -8,8 +12,32 @@ import zio.duration.Duration */ sealed trait SocketProtocol { self => import SocketProtocol._ + def ++(other: SocketProtocol): SocketProtocol = SocketProtocol.Concat(self, other) - def javaConfig: WebSocketServerProtocolConfig = { + + def clientBuilder: WebSocketClientProtocolConfig.Builder = { + val b = WebSocketClientProtocolConfig.newBuilder() + def loop(protocol: SocketProtocol): Unit = { + protocol match { + case Default => () + case SubProtocol(name) => b.subprotocol(name) + case HandshakeTimeoutMillis(duration) => b.handshakeTimeoutMillis(duration.toMillis) + case ForceCloseTimeoutMillis(duration) => b.forceCloseTimeoutMillis(duration.toMillis) + case ForwardCloseFrames => b.handleCloseFrames(false) + case SendCloseFrame(status) => b.sendCloseFrame(status.asJava) + case SendCloseFrameCode(code, reason) => b.sendCloseFrame(new WebSocketCloseStatus(code, reason)) + case ForwardPongFrames => b.dropPongFrames(false) + case Concat(a, b) => + loop(a) + loop(b) + } + () + } + loop(self) + b + } + + def serverBuilder: WebSocketServerProtocolConfig.Builder = { val b = WebSocketServerProtocolConfig.newBuilder().checkStartsWith(true).websocketPath("") def loop(protocol: SocketProtocol): Unit = { protocol match { @@ -28,31 +56,28 @@ sealed trait SocketProtocol { self => () } loop(self) - b.build() + b } + } object SocketProtocol { - private final case class SubProtocol(name: String) extends SocketProtocol - private final case class HandshakeTimeoutMillis(duration: Duration) extends SocketProtocol - private final case class ForceCloseTimeoutMillis(duration: Duration) extends SocketProtocol - private case object ForwardCloseFrames extends SocketProtocol - private final case class SendCloseFrame(status: CloseStatus) extends SocketProtocol - private final case class SendCloseFrameCode(code: Int, reason: String) extends SocketProtocol - private case object ForwardPongFrames extends SocketProtocol - private final case class Concat(a: SocketProtocol, b: SocketProtocol) extends SocketProtocol - private case object Default extends SocketProtocol /** - * Used to specify the websocket sub-protocol + * Close frame to send, when close frame was not send manually. */ - def subProtocol(name: String): SocketProtocol = SubProtocol(name) + def closeFrame(status: CloseStatus): SocketProtocol = SendCloseFrame(status) /** - * Handshake timeout in mills + * Close frame to send, when close frame was not send manually. */ - def handshakeTimeout(duration: Duration): SocketProtocol = - HandshakeTimeoutMillis(duration) + def closeFrame(code: Int, reason: String): SocketProtocol = + SendCloseFrameCode(code, reason) + + /** + * Creates an default decoder configuration. + */ + def default: SocketProtocol = Default /** * Close the connection if it was not closed by the client after timeout specified @@ -66,23 +91,36 @@ object SocketProtocol { def forwardCloseFrames: SocketProtocol = ForwardCloseFrames /** - * Close frame to send, when close frame was not send manually. + * If pong frames should be forwarded */ - def closeFrame(status: CloseStatus): SocketProtocol = SendCloseFrame(status) + def forwardPongFrames: SocketProtocol = ForwardPongFrames /** - * Close frame to send, when close frame was not send manually. + * Handshake timeout in mills */ - def closeFrame(code: Int, reason: String): SocketProtocol = - SendCloseFrameCode(code, reason) + def handshakeTimeout(duration: Duration): SocketProtocol = + HandshakeTimeoutMillis(duration) /** - * If pong frames should be forwarded + * Used to specify the websocket sub-protocol */ - def forwardPongFrames: SocketProtocol = ForwardPongFrames + def subProtocol(name: String): SocketProtocol = SubProtocol(name) - /** - * Creates an default decoder configuration. - */ - def default: SocketProtocol = Default + private final case class SubProtocol(name: String) extends SocketProtocol + + private final case class SendCloseFrame(status: CloseStatus) extends SocketProtocol + + private final case class HandshakeTimeoutMillis(duration: Duration) extends SocketProtocol + + private final case class ForceCloseTimeoutMillis(duration: Duration) extends SocketProtocol + + private final case class SendCloseFrameCode(code: Int, reason: String) extends SocketProtocol + + private final case class Concat(a: SocketProtocol, b: SocketProtocol) extends SocketProtocol + + private case object Default extends SocketProtocol + + private case object ForwardPongFrames extends SocketProtocol + + private case object ForwardCloseFrames extends SocketProtocol } diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index c3c8610bcb..e8c905a496 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -2,12 +2,12 @@ package zhttp.http import io.netty.handler.codec.http.HttpHeaderNames import zhttp.internal.HttpGen -import zhttp.service.{Client, EncodeClientParams} +import zhttp.service.{Client, EncodeClientRequest} import zio.random.Random import zio.test.Assertion._ import zio.test._ -object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientParams { +object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientRequest { val anyClientParam: Gen[Random with Sized, Client.ClientRequest] = HttpGen.clientRequest( HttpGen.httpData( @@ -31,52 +31,64 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientPara def spec = suite("EncodeClientParams") { testM("method") { - check(anyClientParam) { params => - val req = encodeClientParams(params) - assert(req.method())(equalTo(params.method.asHttpMethod)) + checkM(anyClientParam) { params => + val req = encode(params).map(_.method()) + assertM(req)(equalTo(params.method.asHttpMethod)) } } + testM("method on HttpData.File") { - check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(params) - assert(req.method())(equalTo(params.method.asHttpMethod)) + checkM(HttpGen.clientParamsForFileHttpData()) { params => + val req = encode(params).map(_.method()) + assertM(req)(equalTo(params.method.asHttpMethod)) } } + suite("uri") { testM("uri") { - check(anyClientParam) { params => - val req = encodeClientParams(params) - assert(req.uri())(equalTo(params.url.relative.encode)) + checkM(anyClientParam) { params => + val req = encode(params).map(_.uri()) + assertM(req)(equalTo(params.url.relative.encode)) } } + testM("uri on HttpData.File") { - check(HttpGen.clientParamsForFileHttpData()) { params => - val req = encodeClientParams(params) - assert(req.uri())(equalTo(params.url.relative.encode)) + checkM(HttpGen.clientParamsForFileHttpData()) { params => + val req = encode(params).map(_.uri()) + assertM(req)(equalTo(params.url.relative.encode)) } } } + testM("content-length") { - check(clientParamWithFiniteData(5)) { params => - val req = encodeClientParams(params) - assert(req.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong)(equalTo(5L)) + checkM(clientParamWithFiniteData(5)) { params => + val req = encode(params).map( + _.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong, + ) + assertM(req)(equalTo(5L)) } } + testM("host header") { - check(anyClientParam) { params => - val req = encodeClientParams(params) - val hostHeader = HttpHeaderNames.HOST - assert(Option(req.headers().get(hostHeader)))(equalTo(params.url.host)) + checkM(anyClientParam) { params => + val req = + encode(params).map(i => Option(i.headers().get(HttpHeaderNames.HOST))) + assertM(req)(equalTo(params.url.host)) } } + testM("host header when absolute url") { - check(clientParamWithAbsoluteUrl) { params => - val req = encodeClientParams(params) - val reqHeaders = req.headers() - val hostHeader = HttpHeaderNames.HOST - - assert(reqHeaders.getAll(hostHeader).size)(equalTo(1)) && - assert(Option(reqHeaders.get(hostHeader)))(equalTo(params.url.host)) + checkM(clientParamWithAbsoluteUrl) { params => + val req = encode(params) + .map(i => Option(i.headers().get(HttpHeaderNames.HOST))) + assertM(req)(equalTo(params.url.host)) + } + } + + testM("only one host header exists") { + checkM(clientParamWithAbsoluteUrl) { params => + val req = encode(params) + .map(_.headers().getAll(HttpHeaderNames.HOST).size) + assertM(req)(equalTo(1)) + } + } + + testM("http version") { + checkM(anyClientParam) { params => + val req = encode(params).map(i => i.protocolVersion()) + assertM(req)(equalTo(params.version)) } } } diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index 228d985fc9..c7144aee44 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -1,6 +1,5 @@ package zhttp.http -import io.netty.handler.codec.http.HttpHeaderNames import zhttp.service.Client import zio.Chunk import zio.test.Assertion._ @@ -11,32 +10,32 @@ import java.nio.charset.StandardCharsets._ object GetBodyAsStringSpec extends DefaultRunnableSpec { - def spec = suite("getBodyAsString")( - testM("should map bytes according to charset given") { - val charsetGen: Gen[Any, Charset] = - Gen.fromIterable(List(UTF_8, UTF_16, UTF_16BE, UTF_16LE, US_ASCII, ISO_8859_1)) + def spec = suite("getBodyAsString") { + val charsetGen: Gen[Any, Charset] = + Gen.fromIterable(List(UTF_8, UTF_16, UTF_16BE, UTF_16LE, US_ASCII, ISO_8859_1)) - check(charsetGen) { charset => - val encoded = Client - .ClientRequest( - method = Method.GET, - url = URL(Path("/")), - headers = Headers(HttpHeaderNames.CONTENT_TYPE.toString, s"text/html; charset=$charset"), - data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes())), - ) - .getBodyAsString - val actual = Option(new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset)) + suite("binary chunk") { + testM("should map bytes according to charset given") { - assert(actual)(equalTo(encoded)) - } - } + - test("should map bytes to default utf-8 if no charset given") { - val data = Chunk.fromArray("abc".getBytes()) - val content = HttpData.BinaryChunk(data) - val request = Client.ClientRequest(method = Method.GET, url = URL(Path("/")), data = content) - val encoded = request.getBodyAsString - val actual = Option(new String(data.toArray, HTTP_CHARSET)) - assert(actual)(equalTo(encoded)) - }, - ) + checkM(charsetGen) { charset => + val request = Client + .ClientRequest( + URL(!!), + headers = Headers.contentType(s"text/html; charset=$charset"), + data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes(charset))), + ) + + val encoded = request.getBodyAsString + val expected = new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset) + assertM(encoded)(equalTo(expected)) + } + } + + testM("should map bytes to default utf-8 if no charset given") { + val request = Client.ClientRequest(URL(!!), data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes()))) + val encoded = request.getBodyAsString + val expected = new String(Chunk.fromArray("abc".getBytes()).toArray, HTTP_CHARSET) + assertM(encoded)(equalTo(expected)) + } + } + } } diff --git a/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala b/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala new file mode 100644 index 0000000000..d757074d06 --- /dev/null +++ b/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala @@ -0,0 +1,33 @@ +package zhttp.http + +import io.netty.handler.codec.http.HttpScheme +import io.netty.handler.codec.http.websocketx.WebSocketScheme +import zhttp.internal.HttpGen +import zio.test._ + +object SchemeSpec extends DefaultRunnableSpec { + override def spec = suite("SchemeSpec") { + testM("string") { + checkAll(HttpGen.scheme) { scheme => + assertTrue(Scheme.decode(scheme.encode).get == scheme) + } + } + + testM("java http scheme") { + checkAll(jHttpScheme) { jHttpScheme => + assertTrue(Scheme.fromJScheme(jHttpScheme).flatMap(_.toJHttpScheme).get == jHttpScheme) + } + } + + testM("java websocket scheme") { + checkAll(jWebSocketScheme) { jWebSocketScheme => + assertTrue( + Scheme.fromJScheme(jWebSocketScheme).flatMap(_.toJWebSocketScheme).get == jWebSocketScheme, + ) + } + } + } + + private def jHttpScheme: Gen[Any, HttpScheme] = Gen.fromIterable(List(HttpScheme.HTTP, HttpScheme.HTTPS)) + + private def jWebSocketScheme: Gen[Any, WebSocketScheme] = + Gen.fromIterable(List(WebSocketScheme.WS, WebSocketScheme.WSS)) +} diff --git a/zio-http/src/test/scala/zhttp/http/URLSpec.scala b/zio-http/src/test/scala/zhttp/http/URLSpec.scala index 04d9f6e2e7..4dcd71c1c6 100644 --- a/zio-http/src/test/scala/zhttp/http/URLSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/URLSpec.scala @@ -61,6 +61,12 @@ object URLSpec extends DefaultRunnableSpec { val actual = URL.fromString("/").map(_.encode) assert(actual)(isRight(equalTo("/"))) } + + test("ws scheme") { + roundtrip("ws://yourdomain.com/subscriptions") + } + + test("wss scheme") { + roundtrip("wss://yourdomain.com/subscriptions") + } + test("relative with pathname only") { roundtrip("/users") } + diff --git a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala index 7ee0b23802..3e099be8c0 100644 --- a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala +++ b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala @@ -10,8 +10,10 @@ import java.util.UUID object DynamicServer { - def deploy(app: HttpApp[HttpEnv, Throwable]): ZIO[DynamicServer, Nothing, String] = - ZIO.accessM[DynamicServer](_.get.add(app)) + type Id = String + type HttpEnv = DynamicServer with Console with Blocking + type HttpAppTest = HttpApp[HttpEnv, Throwable] + val APP_ID = "X-APP_ID" def app: HttpApp[HttpEnv, Throwable] = Http .fromOptionFunction[Request] { case req => @@ -28,12 +30,20 @@ object DynamicServer { } yield res } + def baseURL(scheme: Scheme): ZIO[DynamicServer, Nothing, String] = + getPort.map(port => s"${scheme.encode}://localhost:$port") + + def deploy(app: HttpApp[HttpEnv, Throwable]): ZIO[DynamicServer, Nothing, String] = + ZIO.accessM[DynamicServer](_.get.add(app)) + def get(id: Id): ZIO[DynamicServer, Nothing, Option[HttpApp[HttpEnv, Throwable]]] = ZIO.accessM[DynamicServer](_.get.get(id)) - def setStart(s: Start): ZIO[DynamicServer, Nothing, Boolean] = ZIO.accessM[DynamicServer](_.get.setStart(s)) - def getStart: ZIO[DynamicServer, Nothing, Start] = ZIO.accessM[DynamicServer](_.get.getStart) - def getPort: ZIO[DynamicServer, Nothing, Int] = ZIO.accessM[DynamicServer](_.get.getPort) + def getPort: ZIO[DynamicServer, Nothing, Int] = ZIO.accessM[DynamicServer](_.get.getPort) + + def getStart: ZIO[DynamicServer, Nothing, Start] = ZIO.accessM[DynamicServer](_.get.getStart) + + def httpURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.HTTP) def live: ZLayer[Any, Nothing, DynamicServer] = { for { @@ -42,17 +52,19 @@ object DynamicServer { } yield new Live(ref, pr) }.toLayer - type Id = String - type HttpEnv = DynamicServer with Console with Blocking - type HttpAppTest = HttpApp[HttpEnv, Throwable] - val APP_ID = "X-APP_ID" + def setStart(s: Start): ZIO[DynamicServer, Nothing, Boolean] = ZIO.accessM[DynamicServer](_.get.setStart(s)) + + def wsURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.WS) sealed trait Service { def add(app: HttpApp[HttpEnv, Throwable]): UIO[Id] def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] - def setStart(n: Start): UIO[Boolean] - def getStart: IO[Nothing, Start] + def getPort: ZIO[Any, Nothing, Int] + + def getStart: IO[Nothing, Start] + + def setStart(n: Start): UIO[Boolean] } final class Live(ref: Ref[Map[Id, HttpApp[HttpEnv, Throwable]]], pr: Promise[Nothing, Start]) extends Service { @@ -61,8 +73,11 @@ object DynamicServer { _ <- ref.update(map => map + (id -> app)) } yield id def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] = ref.get.map(_.get(id)) - def setStart(s: Start): UIO[Boolean] = pr.complete(ZIO(s).orDie) - def getStart: IO[Nothing, Start] = pr.await - def getPort: ZIO[Any, Nothing, Int] = getStart.map(_.port) + + def getPort: ZIO[Any, Nothing, Int] = getStart.map(_.port) + + def getStart: IO[Nothing, Start] = pr.await + + def setStart(s: Start): UIO[Boolean] = pr.complete(ZIO(s).orDie) } } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 21e7f59927..456abbb2f4 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -1,6 +1,8 @@ package zhttp.internal import io.netty.buffer.Unpooled +import io.netty.handler.codec.http.HttpVersion +import zhttp.http.Scheme.{HTTP, HTTPS, WS, WSS} import zhttp.http.URL.Location import zhttp.http._ import zhttp.service.Client.ClientRequest @@ -12,27 +14,28 @@ import zio.{Chunk, ZIO} import java.io.File object HttpGen { + def clientParamsForFileHttpData(): Gen[Random with Sized, ClientRequest] = { + for { + file <- Gen.fromEffect(ZIO.succeed(new File(getClass.getResource("/TestFile.txt").getPath))) + method <- HttpGen.method + url <- HttpGen.url + headers <- Gen.listOf(HttpGen.header).map(Headers(_)) + } yield ClientRequest(url, method, headers, HttpData.fromFile(file)) + } + def clientRequest[R]( dataGen: Gen[R, HttpData], methodGen: Gen[R, Method] = HttpGen.method, urlGen: Gen[Random with Sized, URL] = HttpGen.url, headerGen: Gen[Random with Sized, Header] = HttpGen.header, - ) = + ): Gen[R with Random with Sized, ClientRequest] = for { method <- methodGen url <- urlGen headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen - } yield ClientRequest(method = method, url = url, headers = headers, data = data) - - def clientParamsForFileHttpData() = { - for { - file <- Gen.fromEffect(ZIO.succeed(new File(getClass.getResource("/TestFile.txt").getPath))) - method <- HttpGen.method - url <- HttpGen.url - headers <- Gen.listOf(HttpGen.header).map(Headers(_)) - } yield ClientRequest(method = method, url = url, headers = headers, data = HttpData.fromFile(file)) - } + version <- Gen.fromIterable(List(HttpVersion.HTTP_1_0, HttpVersion.HTTP_1_1)) + } yield ClientRequest(url, method, headers, data, version) def cookies: Gen[Random with Sized, Cookie] = for { name <- Gen.anyString @@ -47,6 +50,20 @@ object HttpGen { secret <- Gen.option(Gen.anyString) } yield Cookie(name, content, expires, domain, path, secure, httpOnly, maxAge, sameSite, secret) + def genAbsoluteLocation: Gen[Random with Sized, Location.Absolute] = for { + scheme <- Gen.fromIterable(List(Scheme.HTTP, Scheme.HTTPS)) + host <- Gen.alphaNumericStringBounded(1, 5) + port <- Gen.int(0, Int.MaxValue) + } yield URL.Location.Absolute(scheme, host, port) + + def genAbsoluteURL = for { + path <- HttpGen.path + kind <- HttpGen.genAbsoluteLocation + queryParams <- Gen.mapOf(Gen.alphaNumericString, Gen.listOf(Gen.alphaNumericString)) + } yield URL(path, kind, queryParams) + + def genRelativeLocation: Gen[Any, Location.Relative.type] = Gen.const(URL.Location.Relative) + def header: Gen[Random with Sized, Header] = for { key <- Gen.alphaNumericStringBounded(1, 4) value <- Gen.alphaNumericStringBounded(1, 4) @@ -67,14 +84,6 @@ object HttpGen { ) } yield cnt - def genRelativeLocation: Gen[Any, Location.Relative.type] = Gen.const(URL.Location.Relative) - - def genAbsoluteLocation: Gen[Random with Sized, Location.Absolute] = for { - scheme <- Gen.fromIterable(List(Scheme.HTTP, Scheme.HTTPS)) - host <- Gen.alphaNumericStringBounded(1, 5) - port <- Gen.int(0, Int.MaxValue) - } yield URL.Location.Absolute(scheme, host, port) - def location: Gen[Random with Sized, URL.Location] = { Gen.fromIterable(List(genRelativeLocation, genAbsoluteLocation)).flatten } @@ -129,6 +138,8 @@ object HttpGen { } yield Response(status, headers, content) } + def scheme: Gen[Any, Scheme] = Gen.fromIterable(List(HTTP, HTTPS, WS, WSS)) + def status: Gen[Any, Status] = Gen.fromIterable( List( Status.CONTINUE, @@ -196,10 +207,4 @@ object HttpGen { queryParams <- Gen.mapOf(Gen.alphaNumericString, Gen.listOf(Gen.alphaNumericString)) } yield URL(path, kind, queryParams) - def genAbsoluteURL = for { - path <- HttpGen.path - kind <- HttpGen.genAbsoluteLocation - queryParams <- Gen.mapOf(Gen.alphaNumericString, Gen.listOf(Gen.alphaNumericString)) - } yield URL(path, kind, queryParams) - } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index e1895cf5ab..2f10a86ed7 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -1,20 +1,16 @@ package zhttp.internal import io.netty.handler.codec.http.HttpVersion -import io.netty.handler.codec.http.HttpVersion._ -import sttp.client3 -import sttp.client3.asynchttpclient.zio.{SttpClient, send} -import sttp.client3.{UriContext, asWebSocketUnsafe, basicRequest} -import sttp.model.{Header => SHeader} -import sttp.ws.WebSocket import zhttp.http.URL.Location import zhttp.http._ import zhttp.internal.DynamicServer.HttpEnv import zhttp.internal.HttpRunnableSpec.HttpTestClient +import zhttp.service.Client.{ClientRequest, ClientResponse} import zhttp.service._ import zhttp.service.client.ClientSSLHandler.ClientSSLOptions +import zhttp.socket.SocketApp import zio.test.DefaultRunnableSpec -import zio.{Has, Task, ZIO, ZManaged} +import zio.{Has, ZIO, ZManaged} /** * Should be used only when e2e tests needs to be written. Typically we would want to do that when we want to test the @@ -30,19 +26,19 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => * constituents of a ClientRequest. */ def run( - httpVersion: HttpVersion = HTTP_1_1, path: Path = !!, method: Method = Method.GET, content: String = "", headers: Headers = Headers.empty, + version: HttpVersion = HttpVersion.HTTP_1_1, ): ZIO[R, Throwable, A] = app( Client.ClientRequest( - httpVersion, - method, - URL(path, Location.Absolute(Scheme.HTTP, "localhost", 0)), - headers, - HttpData.fromString(content), + url = URL(path), // url set here is overridden later via `deploy` method + method = method, + headers = headers, + data = HttpData.fromString(content), + version = version, ), ).catchAll { case Some(value) => ZIO.fail(value) @@ -58,7 +54,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => * are available on `Http` while writing tests. It also allows us to simply pass a request in the end, to execute, * and resolve it with a response, like a normal HttpApp. */ - def deploy: HttpTestClient[Any, Client.ClientResponse] = + def deploy: HttpTestClient[Any, ClientRequest, ClientResponse] = for { port <- Http.fromZIO(DynamicServer.getPort) id <- Http.fromZIO(DynamicServer.deploy(app)) @@ -67,28 +63,22 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => params .addHeader(DynamicServer.APP_ID, id) .copy(url = URL(params.url.path, Location.Absolute(Scheme.HTTP, "localhost", port))), - ClientSSLOptions.DefaultSSL, ) } } yield response - /** - * Deploys the websocket application on the test server. - */ - def deployWebSocket: HttpTestClient[SttpClient, client3.Response[Either[String, WebSocket[Task]]]] = for { - id <- Http.fromZIO(DynamicServer.deploy(app)) - res <- - Http.fromFunctionZIO[Client.ClientRequest](params => - for { - port <- DynamicServer.getPort - url = s"ws://localhost:$port${params.url.path.encode}" - headerConv = params.addHeader(DynamicServer.APP_ID, id).getHeaders.toList.map(h => SHeader(h._1, h._2)) - res <- send(basicRequest.get(uri"$url").copy(headers = headerConv).response(asWebSocketUnsafe)) - } yield res, - ) - - } yield res - + def deployWS: HttpTestClient[Any, SocketApp[Any], ClientResponse] = + for { + id <- Http.fromZIO(DynamicServer.deploy(app)) + url <- Http.fromZIO(DynamicServer.wsURL) + response <- Http.fromFunctionZIO[SocketApp[Any]] { app => + Client.socket( + url = url, + headers = Headers(DynamicServer.APP_ID, id), + app = app, + ) + } + } yield response } def serve[R <: Has[_]]( @@ -107,9 +97,9 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => port <- DynamicServer.getPort status <- Client .request( + "http://localhost:%d/%s".format(port, path), method, - URL(path, Location.Absolute(Scheme.HTTP, "localhost", port)), - ClientSSLOptions.DefaultSSL, + ssl = ClientSSLOptions.DefaultSSL, ) .map(_.status) } yield status @@ -117,11 +107,11 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => } object HttpRunnableSpec { - type HttpTestClient[-R, +A] = + type HttpTestClient[-R, -A, +B] = Http[ R with EventLoopGroup with ChannelFactory with DynamicServer with ServerChannelFactory, Throwable, - Client.ClientRequest, A, + B, ] } diff --git a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala index 653f602637..103d12e511 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala @@ -34,14 +34,14 @@ object ClientHttpsSpec extends DefaultRunnableSpec { assertM(actual)(anything) } + testM("respond Ok with sslOption") { - val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics", sslOption) + val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics", ssl = sslOption) assertM(actual)(anything) } + testM("should respond as Bad Request") { val actual = Client .request( "https://www.whatissslcertificate.com/google-has-made-the-list-of-untrusted-providers-of-digital-certificates/", - sslOption, + ssl = sslOption, ) .map(_.status) assertM(actual)(equalTo(Status.BAD_REQUEST)) @@ -50,7 +50,7 @@ object ClientHttpsSpec extends DefaultRunnableSpec { val actual = Client .request( "https://untrusted-root.badssl.com/", - sslOption, + ssl = sslOption, ) .run assertM(actual)(fails(isSubtype[DecoderException](anything))) diff --git a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala index 84d8c6b470..496972bed8 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala @@ -5,9 +5,11 @@ import zhttp.internal.{DynamicServer, HttpRunnableSpec} import zhttp.service.server._ import zio.duration.durationInt import zio.test.Assertion._ -import zio.test.TestAspect._ +import zio.test.TestAspect.{sequential, timeout} import zio.test._ +import java.net.ConnectException + object ClientSpec extends HttpRunnableSpec { private val env = @@ -37,6 +39,10 @@ object ClientSpec extends HttpRunnableSpec { val app = Http.text("zio user does not exist") val responseContent = app.deploy.getBodyAsString.run() assertM(responseContent)(containsString("user")) + } + + testM("handle connection failure") { + val res = Client.request("http://localhost:1").either + assertM(res)(isLeft(isSubtype[ConnectException](anything))) } } diff --git a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala index 84f6931758..502c8a6c23 100644 --- a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala @@ -12,6 +12,8 @@ object KeepAliveSpec extends HttpRunnableSpec { val app = Http.ok val connectionCloseHeader = Headers.connection(HttpHeaderValues.CLOSE) val keepAliveHeader = Headers.connection(HttpHeaderValues.KEEP_ALIVE) + private val env = EventLoopGroup.nio() ++ ChannelFactory.nio ++ ServerChannelFactory.nio ++ DynamicServer.live + private val appKeepAliveEnabled = serve(DynamicServer.app) def keepAliveSpec = suite("KeepAlive") { suite("Http 1.1") { @@ -26,21 +28,18 @@ object KeepAliveSpec extends HttpRunnableSpec { } + suite("Http 1.0") { testM("without keep-alive") { - val res = app.deploy.getHeaderValue(HeaderNames.connection).run(httpVersion = HttpVersion.HTTP_1_0) + val res = app.deploy.getHeaderValue(HeaderNames.connection).run(version = HttpVersion.HTTP_1_0) assertM(res)(isSome(equalTo("close"))) } + testM("with keep-alive") { val res = app.deploy .getHeaderValue(HeaderNames.connection) - .run(httpVersion = HttpVersion.HTTP_1_0, headers = keepAliveHeader) + .run(version = HttpVersion.HTTP_1_0, headers = keepAliveHeader) assertM(res)(isNone) } } } - private val env = EventLoopGroup.nio() ++ ChannelFactory.nio ++ ServerChannelFactory.nio ++ DynamicServer.live - private val appKeepAliveEnabled = serve(DynamicServer.app) - override def spec = { suiteM("ServerConfigSpec") { appKeepAliveEnabled.as(List(keepAliveSpec)).useNow diff --git a/zio-http/src/test/scala/zhttp/service/SSLSpec.scala b/zio-http/src/test/scala/zhttp/service/SSLSpec.scala index 16c6cb5ed1..a7bafdc50a 100644 --- a/zio-http/src/test/scala/zhttp/service/SSLSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/SSLSpec.scala @@ -36,27 +36,27 @@ object SSLSpec extends DefaultRunnableSpec { List( testM("succeed when client has the server certificate") { val actual = Client - .request("https://localhost:8073/success", ClientSSLOptions.CustomSSL(clientSSL1)) + .request("https://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL1)) .map(_.status) assertM(actual)(equalTo(Status.OK)) } + testM("fail with DecoderException when client doesn't have the server certificate") { val actual = Client - .request("https://localhost:8073/success", ClientSSLOptions.CustomSSL(clientSSL2)) - .catchSome(_ match { - case _: DecoderException => ZIO.succeed("DecoderException") - }) + .request("https://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL2)) + .catchSome { case _: DecoderException => + ZIO.succeed("DecoderException") + } assertM(actual)(equalTo("DecoderException")) } + testM("succeed when client has default SSL") { val actual = Client - .request("https://localhost:8073/success", ClientSSLOptions.DefaultSSL) + .request("https://localhost:8073/success", ssl = ClientSSLOptions.DefaultSSL) .map(_.status) assertM(actual)(equalTo(Status.OK)) } + testM("Https Redirect when client makes http request") { val actual = Client - .request("http://localhost:8073/success", ClientSSLOptions.CustomSSL(clientSSL1)) + .request("http://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL1)) .map(_.status) assertM(actual)(equalTo(Status.PERMANENT_REDIRECT)) } @@ ignore, diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 2e71eca506..4360a17b04 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -245,7 +245,7 @@ object ServerSpec extends HttpRunnableSpec { override def spec = suiteM("Server") { - app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec)).useNow + app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec, nonZIOSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(30 seconds) def staticAppSpec = suite("StaticAppSpec") { diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index 81721d2410..e950abf505 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -1,10 +1,10 @@ package zhttp.service -import sttp.client3.asynchttpclient.zio.AsyncHttpClientZioBackend -import zhttp.http._ +import zhttp.http.Status import zhttp.internal.{DynamicServer, HttpRunnableSpec} import zhttp.service.server._ import zhttp.socket.{Socket, WebSocketFrame} +import zio.ZIO import zio.duration._ import zio.test.Assertion.equalTo import zio.test.TestAspect.timeout @@ -13,21 +13,22 @@ import zio.test._ object WebSocketServerSpec extends HttpRunnableSpec { private val env = - EventLoopGroup.nio() ++ ServerChannelFactory.nio ++ AsyncHttpClientZioBackend - .layer() - .orDie ++ DynamicServer.live ++ ChannelFactory.nio + EventLoopGroup.nio() ++ ServerChannelFactory.nio ++ DynamicServer.live ++ ChannelFactory.nio private val app = serve { DynamicServer.app } override def spec = suiteM("Server") { app.as(List(websocketSpec)).useNow - }.provideCustomLayerShared(env) @@ timeout(30 seconds) + }.provideCustomLayerShared(env) @@ timeout(10 seconds) def websocketSpec = suite("WebSocket Server") { suite("connections") { testM("Multiple websocket upgrades") { - val response = Socket.succeed(WebSocketFrame.text("BAR")).toResponse - val app = Http.fromZIO(response) - assertM(app.deployWebSocket.map(_.code.code).run(path = !! / "subscriptions").repeatN(1024))(equalTo(101)) + val app = Socket.succeed(WebSocketFrame.text("BAR")).toHttp.deployWS + val codes = ZIO + .foreach(1 to 1024)(_ => app(Socket.empty.toSocketApp).map(_.status)) + .map(_.count(_ == Status.SWITCHING_PROTOCOLS)) + + assertM(codes)(equalTo(1024)) } } } From ef63c239b759ef6f6eac651fa291d393ed1b03e9 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Fri, 4 Feb 2022 18:11:43 +0530 Subject: [PATCH 67/95] Documentation: Request (#926) * docs: request * doc: added client request docs * added query param section * doc: refactoring * WIP * fix: doc * fix: doc * request * request * example fixed --- docs/website/docs/v1.x/dsl/request/index.md | 92 ++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/docs/website/docs/v1.x/dsl/request/index.md b/docs/website/docs/v1.x/dsl/request/index.md index acfff8c574..347140634c 100644 --- a/docs/website/docs/v1.x/dsl/request/index.md +++ b/docs/website/docs/v1.x/dsl/request/index.md @@ -1 +1,91 @@ -# Work in progress \ No newline at end of file +# Request + +**ZIO HTTP** `Request` is designed in the simplest way possible to decode HTTP Request into a ZIO HTTP request. + It supports all HTTP request methods (as defined in [RFC2616](https://datatracker.ietf.org/doc/html/rfc2616) ) and headers along with custom methods and headers. + +## Creating a Request + +`Request` can be created with `method`, `url`, `headers`, `remoteAddress` and `data`. +Creating requests using `Request` is useful while writing unit tests. + +The below snippet creates a request with default params, `method` as `Method.GET`, `url` as `URL.root`, `headers` as `Headers.empty`, `data` as `HttpData.Empty`, `remoteAddress` as `None` +```scala +val request: Request = Request() +``` + +## Matching and Extracting Requests + +`Request` can be extracted into an HTTP Method and Path via `->`. On the left side is the `Method`, and on the right side, the `Path`. + +```scala +Method.GET -> !! / "text" +``` +### Method + `Method` represents HTTP methods like POST, GET, PUT, PATCH, and DELETE. +You can create existing HTTP methods such as `Method.GET`, `Method.POST` etc or create a custom one. + + +### Path + `Path` can be created using + - `!!` which represents the root + - `/` which represents the path delimiter and starts the extraction from the left-hand side of the expression + - `/:` which represents the path delimiter and starts the extraction from the right-hand side of the expression and can match paths partially + +The below snippet creates an `HttpApp` that accepts an input of type `Request` and output of type `Response` with two paths. +According to the request path, it will respond with the corresponding response: +- if the request has path `/name` it will match the first route. +- if the request has path `/name/joe/wilson` it will match the second route as `/:` matches the path partially as well. + + ```scala + val app: HttpApp[Any, Nothing] = Http.collect[Request] { + case Method.GET -> !! / a => Response.text(s"$a") + case Method.GET -> "name" /: a => Response.text(s"$a") + } +``` + +## Accessing the Request + +- `getBody` to access the content of request as a Chunk[Byte] +```scala + val app = Http.collectZIO[Request] { case req => req.getBody.as(Response.ok) } +``` +- `getBodyAsString` to access the content of request as string +```scala + val app = Http.collectZIO[Request] { case req => req.getBodyAsString.as(Response.ok) } +``` +- `getHeaders` to get all the headers in the Request +```scala + val app = Http.collect[Request] { case req => Response.text(req.getHeaders.toList.mkString("")) } +``` +- `method` to access request method +```scala +val app = Http.collect[Request] { case req => Response.text(req.method.toString())} +``` +- `path` to access request path +```scala + val app = Http.collect[Request] { case req => Response.text(req.path.toString())} +``` +- `remoteAddress` to access request's remote address if available +```scala + val app = Http.collect[Request] { case req => Response.text(req.remoteAddress.toString())} +``` +- `url` to access the complete url +```scala + val app = Http.collect[Request] { case req => Response.text(req.url.toString())} +``` + +## Creating and reading a Request with query params + +Query params can be added in the request using `url` in `Request`, `URL` stores query params as `Map[String, List[String]]`. + +The below snippet creates a request with query params: `?q=a&q=b&q=c` +```scala + val request: Request = Request(url = URL(!!, queryParams = Map("q" -> List("a","b","c")))) +``` + +`url.queryParams` can be used to read query params from the request + +The below snippet shows how to read query params from request +```scala + val app = Http.collect[Request] { case req => Response.text(req.url.queryParams.mkString(""))} +``` From f396f1718ea2cc01340ebad7512cc6f02273f229 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sat, 5 Feb 2022 07:56:48 +0530 Subject: [PATCH 68/95] Fix ssl issue due to missing peer host port hint (#952) --- zio-http/src/main/scala/zhttp/service/Client.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index d8ce33f9cb..fd868c01fd 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -80,7 +80,7 @@ final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el val sslOption: ClientSSLOptions = req.attribute.ssl.getOrElse(ClientSSLOptions.DefaultSSL) // If a https or wss request is made we need to add the ssl handler at the starting of the pipeline. - if (isSSL) pipeline.addLast(SSL_HANDLER, ClientSSLHandler.ssl(sslOption).newHandler(ch.alloc)) + if (isSSL) pipeline.addLast(SSL_HANDLER, ClientSSLHandler.ssl(sslOption).newHandler(ch.alloc, host, port)) // Adding default client channel handlers pipeline.addLast(HTTP_CLIENT_CODEC, new HttpClientCodec) From e51448424782888be8ef1d2cade6bd34755cc401 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Sat, 5 Feb 2022 13:34:51 +0530 Subject: [PATCH 69/95] feature: add connect operator on Socket (#955) --- zio-http/src/main/scala/zhttp/socket/Socket.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 0cf086c7af..1555f94a13 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -1,6 +1,7 @@ package zhttp.socket import zhttp.http.{Http, Response} +import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio.stream.ZStream import zio.{Cause, NeedsEnv, ZIO} @@ -24,6 +25,11 @@ sealed trait Socket[-R, +E, -A, +B] { self => case Empty => ZStream.empty } + def connect(url: String)(implicit + ev: IsWebSocket[R, E, A, B], + ): ZIO[R with EventLoopGroup with ChannelFactory, Throwable, Client.ClientResponse] = + self.toSocketApp.connect(url) + def contramap[Z](za: Z => A): Socket[R, E, Z, B] = Socket.FCMap(self, za) def contramapZIO[R1 <: R, E1 >: E, Z](za: Z => ZIO[R1, E1, A]): Socket[R1, E1, Z, B] = Socket.FCMapZIO(self, za) From 6e9c007b1bb4a65bc04c5d20765c6720b86c4459 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Sat, 5 Feb 2022 20:19:44 +0530 Subject: [PATCH 70/95] Style: Update scala doc wrapping (#959) * chore: update scalafmt config * style(*): apply scala fmt --- .scalafmt.conf | 1 + .../main/scala/example/HttpsHelloWorld.scala | 8 ++- zio-http/src/main/scala/zhttp/html/Dom.scala | 6 +- .../src/main/scala/zhttp/http/Cookie.scala | 3 +- .../src/main/scala/zhttp/http/HExit.scala | 5 +- .../src/main/scala/zhttp/http/Headers.scala | 10 ++-- zio-http/src/main/scala/zhttp/http/Http.scala | 55 ++++++++++++------- .../main/scala/zhttp/http/Middleware.scala | 29 ++++++---- .../src/main/scala/zhttp/http/Response.scala | 20 ++++--- .../scala/zhttp/http/RouteDecoderModule.scala | 9 +-- .../zhttp/http/headers/HeaderChecks.scala | 7 ++- .../http/headers/HeaderConstructors.scala | 3 +- .../zhttp/http/headers/HeaderExtension.scala | 7 ++- .../zhttp/http/headers/HeaderGetters.scala | 3 +- .../zhttp/http/headers/HeaderModifier.scala | 13 +++-- .../zhttp/http/headers/HeaderNames.scala | 5 +- .../zhttp/http/headers/HeaderValues.scala | 5 +- .../scala/zhttp/http/middleware/Auth.scala | 6 +- .../scala/zhttp/http/middleware/Csrf.scala | 17 +++--- .../scala/zhttp/http/middleware/Web.scala | 15 +++-- .../scala/zhttp/service/ChannelFuture.scala | 7 ++- .../scala/zhttp/service/HttpRuntime.scala | 5 +- .../src/main/scala/zhttp/service/Server.scala | 17 +++--- .../zhttp/service/WebSocketAppHandler.scala | 3 +- .../service/server/WebSocketUpgrade.scala | 3 +- .../handlers/ServerResponseHandler.scala | 5 +- .../src/main/scala/zhttp/socket/Socket.scala | 5 +- .../main/scala/zhttp/socket/SocketApp.scala | 25 +++++---- .../scala/zhttp/socket/SocketDecoder.scala | 12 ++-- .../scala/zhttp/socket/SocketProtocol.scala | 3 +- .../zhttp/internal/HttpRunnableSpec.scala | 21 ++++--- 31 files changed, 203 insertions(+), 130 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 43acb10301..bf5051b45e 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -24,3 +24,4 @@ newlines.afterInfix = keep rewrite.rules = [RedundantParens] trailingCommas = "always" runner.dialect = Scala213Source3 +docstrings.wrapMaxColumn = 80 diff --git a/example/src/main/scala/example/HttpsHelloWorld.scala b/example/src/main/scala/example/HttpsHelloWorld.scala index 2128de0fb4..f26145e763 100644 --- a/example/src/main/scala/example/HttpsHelloWorld.scala +++ b/example/src/main/scala/example/HttpsHelloWorld.scala @@ -14,9 +14,11 @@ object HttpsHelloWorld extends App { } /** - * sslcontext can be created using SslContexBuilder. In this example an inbuilt API using keystore is used. For - * testing this example using curl, setup the certificate named "server.crt" from resources for the OS. Alternatively - * you can create the keystore and certificate using the following link + * sslcontext can be created using SslContexBuilder. In this example an + * inbuilt API using keystore is used. For testing this example using curl, + * setup the certificate named "server.crt" from resources for the OS. + * Alternatively you can create the keystore and certificate using the + * following link * https://medium.com/@maanadev/netty-with-https-tls-9bf699e07f01 */ val sslctx = ctxFromCert( diff --git a/zio-http/src/main/scala/zhttp/html/Dom.scala b/zio-http/src/main/scala/zhttp/html/Dom.scala index ff11ef023b..04408600f2 100644 --- a/zio-http/src/main/scala/zhttp/html/Dom.scala +++ b/zio-http/src/main/scala/zhttp/html/Dom.scala @@ -4,8 +4,10 @@ package zhttp.html * Light weight DOM implementation that can be rendered as a html string. * * @see - *
Void elements only have a start tag; - * end tags must not be specified for void elements. + * Void + * elements only have a start tag; end tags must not be specified for void + * elements. */ sealed trait Dom { self => def encode: String = self match { diff --git a/zio-http/src/main/scala/zhttp/http/Cookie.scala b/zio-http/src/main/scala/zhttp/http/Cookie.scala index bc30b097a1..4d7dc61b42 100644 --- a/zio-http/src/main/scala/zhttp/http/Cookie.scala +++ b/zio-http/src/main/scala/zhttp/http/Cookie.scala @@ -23,7 +23,8 @@ final case class Cookie( ) { self => /** - * Creates a new cookie that can be used to clear the original cookie on the client. + * Creates a new cookie that can be used to clear the original cookie on the + * client. */ def clear: Cookie = copy(content = "", expires = Some(Instant.ofEpochSecond(0))) diff --git a/zio-http/src/main/scala/zhttp/http/HExit.scala b/zio-http/src/main/scala/zhttp/http/HExit.scala index aad51d8264..811066a449 100644 --- a/zio-http/src/main/scala/zhttp/http/HExit.scala +++ b/zio-http/src/main/scala/zhttp/http/HExit.scala @@ -4,8 +4,9 @@ import zhttp.http.HExit.Effect import zio.ZIO /** - * Every `HttpApp` evaluates to an `HExit`. This domain is needed for improved performance. This ensures that a `ZIO` - * effect is created only when it is required. `HExit.Effect` wraps a ZIO effect, otherwise `HExits` are evaluated + * Every `HttpApp` evaluates to an `HExit`. This domain is needed for improved + * performance. This ensures that a `ZIO` effect is created only when it is + * required. `HExit.Effect` wraps a ZIO effect, otherwise `HExits` are evaluated * without `ZIO` */ private[zhttp] sealed trait HExit[-R, +E, +A] { self => diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index fb03c41b10..24b74092f6 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -7,11 +7,13 @@ import zio.Chunk import scala.jdk.CollectionConverters._ /** - * Represents an immutable collection of headers i.e. essentially a Chunk[(String, String)]. It extends HeaderExtensions - * and has a ton of powerful operators that can be used to add, remove and modify headers. + * Represents an immutable collection of headers i.e. essentially a + * Chunk[(String, String)]. It extends HeaderExtensions and has a ton of + * powerful operators that can be used to add, remove and modify headers. * - * NOTE: Generic operators that are not specific to `Headers` should not be defined here. A better place would be one of - * the traits extended by `HeaderExtension`. + * NOTE: Generic operators that are not specific to `Headers` should not be + * defined here. A better place would be one of the traits extended by + * `HeaderExtension`. */ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers] { self => diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 116f388fe4..40d3ceb82d 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -14,7 +14,8 @@ import java.nio.charset.Charset import scala.annotation.unused /** - * A functional domain to model Http apps using ZIO and that can work over any kind of request and response types. + * A functional domain to model Http apps using ZIO and that can work over any + * kind of request and response types. */ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => @@ -100,7 +101,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => self >>> Http.collectManaged(pf) /** - * Collects some of the results of the http and effectfully converts it to another type. + * Collects some of the results of the http and effectfully converts it to + * another type. */ final def collectZIO[R1 <: R, E1 >: E, A1 <: A, B1 >: B, C]( pf: PartialFunction[B1, ZIO[R1, E1, C]], @@ -168,7 +170,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => } /** - * Folds over the http app by taking in two functions one for success and one for failure respectively. + * Folds over the http app by taking in two functions one for success and one + * for failure respectively. */ final def foldHttp[R1 <: R, A1 <: A, E1, B1]( ee: E => Http[R1, E1, A1, B1], @@ -283,7 +286,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => Http.Race(self, other) /** - * Converts a failing Http into a non-failing one by handling the failure and converting it to a result if possible. + * Converts a failing Http into a non-failing one by handling the failure and + * converting it to a result if possible. */ final def silent[E1 >: E, B1 >: B](implicit s: CanBeSilenced[E1, B1]): Http[R, Nothing, A, B1] = self.catchAll(e => Http.succeed(s.silent(e))) @@ -295,7 +299,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => self.flatMap(v => f(v).as(v)) /** - * Returns an Http that peeks at the success, failed or empty value of this Http. + * Returns an Http that peeks at the success, failed or empty value of this + * Http. */ final def tapAll[R1 <: R, E1 >: E]( f: E => Http[R1, E1, Any, Any], @@ -309,7 +314,8 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => ) /** - * Returns an Http that effectfully peeks at the success, failed or empty value of this Http. + * Returns an Http that effectfully peeks at the success, failed or empty + * value of this Http. */ final def tapAllZIO[R1 <: R, E1 >: E]( f: E => ZIO[R1, E1, Any], @@ -365,9 +371,10 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Evaluates the app and returns an HExit that can be resolved further * - * NOTE: `execute` is not a stack-safe method for performance reasons. Unlike ZIO, there is no reason why the execute - * should be stack safe. The performance improves quite significantly if no additional heap allocations are required - * this way. + * NOTE: `execute` is not a stack-safe method for performance reasons. Unlike + * ZIO, there is no reason why the execute should be stack safe. The + * performance improves quite significantly if no additional heap allocations + * are required this way. */ final private[zhttp] def execute(a: A): HExit[R, E, B] = self match { @@ -433,8 +440,8 @@ object Http { def setUrl(url: URL): HttpApp[R, E] = http.contramap[Request](_.setUrl(url)) /** - * Converts a failing Http app into a non-failing one by handling the failure and converting it to a result if - * possible. + * Converts a failing Http app into a non-failing one by handling the + * failure and converting it to a result if possible. */ def silent[R1 <: R, E1 >: E](implicit s: CanBeSilenced[E1, Response]): HttpApp[R1, E1] = http.catchAll(e => Http.succeed(s.silent(e))) @@ -471,12 +478,14 @@ object Http { def collectHttp[A]: Http.PartialCollectHttp[A] = Http.PartialCollectHttp(()) /** - * Creates an Http app which accepts a request and produces response from a managed resource + * Creates an Http app which accepts a request and produces response from a + * managed resource */ def collectManaged[A]: Http.PartialCollectManaged[A] = Http.PartialCollectManaged(()) /** - * Creates an HTTP app which accepts a request and produces response effectfully. + * Creates an HTTP app which accepts a request and produces response + * effectfully. */ def collectZIO[A]: Http.PartialCollectZIO[A] = Http.PartialCollectZIO(()) @@ -524,7 +533,8 @@ object Http { def forbidden(msg: String): HttpApp[Any, Nothing] = Http.error(HttpError.Forbidden(msg)) /** - * Creates an Http app which always responds the provided data and a 200 status code + * Creates an Http app which always responds the provided data and a 200 + * status code */ def fromData(data: HttpData): HttpApp[Any, Nothing] = response(Response(data = data)) @@ -544,19 +554,22 @@ object Http { def fromFunctionZIO[A]: PartialFromFunctionZIO[A] = new PartialFromFunctionZIO[A](()) /** - * Creates an `Http` from a function that takes a value of type `A` and returns with a `ZIO[R, Option[E], B]`. The - * returned effect can fail with a `None` to signal "not found" to the backend. + * Creates an `Http` from a function that takes a value of type `A` and + * returns with a `ZIO[R, Option[E], B]`. The returned effect can fail with a + * `None` to signal "not found" to the backend. */ def fromOptionFunction[A]: PartialFromOptionFunction[A] = new PartialFromOptionFunction(()) /** - * Creates a Http that always succeeds with a 200 status code and the provided ZStream as the body + * Creates a Http that always succeeds with a 200 status code and the provided + * ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, String], charset: Charset = HTTP_CHARSET): HttpApp[R, Nothing] = Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r), charset)))).flatten /** - * Creates a Http that always succeeds with a 200 status code and the provided ZStream as the body + * Creates a Http that always succeeds with a 200 status code and the provided + * ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, Byte]): HttpApp[R, Nothing] = Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r))))).flatten @@ -603,7 +616,8 @@ object Http { def route[A]: Http.PartialRoute[A] = Http.PartialRoute(()) /** - * Creates an HTTP app which always responds with the same status code and empty data. + * Creates an HTTP app which always responds with the same status code and + * empty data. */ def status(code: Status): HttpApp[Any, Nothing] = Http.succeed(Response(code)) @@ -619,7 +633,8 @@ object Http { Http.succeed(Response.text(str, charset)) /** - * Creates an Http app that responds with a 408 status code after the provided time duration + * Creates an Http app that responds with a 408 status code after the provided + * time duration */ def timeout(duration: Duration): HttpApp[Clock, Nothing] = Http.status(Status.REQUEST_TIMEOUT).delay(duration) diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index 831d1f8afd..99c3038886 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -6,8 +6,9 @@ import zio.duration.Duration import zio.{UIO, ZIO} /** - * Middlewares are essentially transformations that one can apply on any Http to produce a new one. They can modify - * requests and responses and also transform them into more concrete domain entities. + * Middlewares are essentially transformations that one can apply on any Http to + * produce a new one. They can modify requests and responses and also transform + * them into more concrete domain entities. * * You can think of middlewares as a functions — * @@ -15,14 +16,15 @@ import zio.{UIO, ZIO} * type Middleware[R, E, AIn, BIn, AOut, BOut] = Http[R, E, AIn, BIn] => Http[R, E, AOut, BOut] * }}} * - * The `AIn` and `BIn` type params represent the type params of the input Http. The `AOut` and `BOut` type params - * represent the type params of the output Http. + * The `AIn` and `BIn` type params represent the type params of the input Http. + * The `AOut` and `BOut` type params represent the type params of the output + * Http. */ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => /** - * Creates a new middleware that passes the output Http of the current middleware as the input to the provided - * middleware. + * Creates a new middleware that passes the output Http of the current + * middleware as the input to the provided middleware. */ final def >>>[R1 <: R, E1 >: E, AIn1 <: AOut, BIn1 >: BOut, AOut1, BOut1]( other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], @@ -64,7 +66,8 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => self.map(_ => bout) /** - * Combines two middleware that operate on the same input and output types, into one. + * Combines two middleware that operate on the same input and output types, + * into one. */ final def combine[R1 <: R, E1 >: E, A0 >: AIn <: AOut, B0 >: BOut <: BIn]( other: Middleware[R1, E1, A0, B0, A0, B0], @@ -126,7 +129,8 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => Middleware.OrElse(self, other) /** - * Race between current and other, cancels other when execution of one completes + * Race between current and other, cancels other when execution of one + * completes */ final def race[R1 <: R, E1 >: E, AIn1 >: AIn, BIn1 <: BIn, AOut1 <: AOut, BOut1 >: BOut]( other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], @@ -146,7 +150,8 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => whenZIO(a => UIO(cond(a))) /** - * Applies Middleware based only if the condition effectful function evaluates to true + * Applies Middleware based only if the condition effectful function evaluates + * to true */ final def whenZIO[R1 <: R, E1 >: E, AOut0 <: AOut]( cond: AOut0 => ZIO[R1, E1, Boolean], @@ -201,12 +206,14 @@ object Middleware extends Web { def identity: Middleware[Any, Nothing, Nothing, Any, Any, Nothing] = Middleware.Identity /** - * Logical operator to decide which middleware to select based on the predicate. + * Logical operator to decide which middleware to select based on the + * predicate. */ def ifThenElse[A]: PartialIfThenElse[A] = new PartialIfThenElse(()) /** - * Logical operator to decide which middleware to select based on the predicate effect. + * Logical operator to decide which middleware to select based on the + * predicate effect. */ def ifThenElseZIO[A]: PartialIfThenElseZIO[A] = new PartialIfThenElseZIO(()) diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index a0174befec..1662624d62 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -27,11 +27,13 @@ final case class Response private ( self.copy(headers = self.getHeaders ++ Headers(HttpHeaderNames.SET_COOKIE.toString, cookie.encode)) /** - * A micro-optimizations that ignores all further modifications to the response and encodes the current version into a - * Netty response. The netty response is cached and reused for subsequent requests. This allows the server to reduce - * memory utilization under load by not having to encode the response for each request. In case the response is - * modified the server will detect the changes and encode the response again, however it will turn out to be counter - * productive. + * A micro-optimizations that ignores all further modifications to the + * response and encodes the current version into a Netty response. The netty + * response is cached and reused for subsequent requests. This allows the + * server to reduce memory utilization under load by not having to encode the + * response for each request. In case the response is modified the server will + * detect the changes and encode the response again, however it will turn out + * to be counter productive. */ def freeze: UIO[Response] = UIO(self.copy(attribute = self.attribute.withEncodedResponse(unsafeEncode(), self))) @@ -67,8 +69,9 @@ final case class Response private ( private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = self.data.toByteBuf /** - * Encodes the Response into a Netty HttpResponse. Sets default headers such as `content-length`. For performance - * reasons, it is possible that it uses a FullHttpResponse if the complete data is available. Otherwise, it would + * Encodes the Response into a Netty HttpResponse. Sets default headers such + * as `content-length`. For performance reasons, it is possible that it uses a + * FullHttpResponse if the complete data is available. Otherwise, it would * create a DefaultHttpResponse without any content. */ private[zhttp] def unsafeEncode(): HttpResponse = { @@ -187,7 +190,8 @@ object Response { def ok: Response = Response(Status.OK) /** - * Creates an empty response with status 301 or 302 depending on if it's permanent or not. + * Creates an empty response with status 301 or 302 depending on if it's + * permanent or not. */ def redirect(location: String, isPermanent: Boolean = false): Response = { val status = if (isPermanent) Status.PERMANENT_REDIRECT else Status.TEMPORARY_REDIRECT diff --git a/zio-http/src/main/scala/zhttp/http/RouteDecoderModule.scala b/zio-http/src/main/scala/zhttp/http/RouteDecoderModule.scala index 99bf746d09..ca55f162b0 100644 --- a/zio-http/src/main/scala/zhttp/http/RouteDecoderModule.scala +++ b/zio-http/src/main/scala/zhttp/http/RouteDecoderModule.scala @@ -4,8 +4,8 @@ import java.time.{LocalDate, LocalDateTime} import java.util.UUID /** - * Instead of using just `String` as path params, using the RouteDecoderModule we can extract and converted params into - * a specific type also. + * Instead of using just `String` as path params, using the RouteDecoderModule + * we can extract and converted params into a specific type also. * * ```scala * Http.collect[Request] { @@ -14,8 +14,9 @@ import java.util.UUID * } * ``` * - * If the request looks like `GET /user/100` then it would match the first case. This is because internally the `id` - * param can be decoded into an `Int`. If a request of the form `GET /user/zio` is made, in that case the second case is + * If the request looks like `GET /user/100` then it would match the first case. + * This is because internally the `id` param can be decoded into an `Int`. If a + * request of the form `GET /user/zio` is made, in that case the second case is * matched. */ diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala index bee353ed92..abf12a2845 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala @@ -4,10 +4,11 @@ import io.netty.util.AsciiString.contentEqualsIgnoreCase import zhttp.http.HeaderValues /** - * Maintains a list of operators that checks if the Headers meet the give constraints. + * Maintains a list of operators that checks if the Headers meet the give + * constraints. * - * NOTE: Add methods here, if it tests the Headers for something, and returns a true or false based on if the conditions - * are met or not. + * NOTE: Add methods here, if it tests the Headers for something, and returns a + * true or false based on if the conditions are met or not. */ trait HeaderChecks[+A] { self: HeaderExtension[A] with A => final def hasContentType(value: CharSequence): Boolean = diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala index d5bee1a1ed..c75c55dd12 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala @@ -10,7 +10,8 @@ import java.util.Base64 /** * Contains a list of helpful methods that can create `Headers`. * - * NOTE: Add methods here if it provides an alternative succinct way to create `Headers`. + * NOTE: Add methods here if it provides an alternative succinct way to create + * `Headers`. */ trait HeaderConstructors { final def accept(value: CharSequence): Headers = diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderExtension.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderExtension.scala index c077e41432..d641ea43e4 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderExtension.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderExtension.scala @@ -1,9 +1,10 @@ package zhttp.http.headers /** - * A trait that provides a ton of powerful operators when extended. Any type that extends HeaderExtension needs to - * implement the two methods viz. `getHeaders` and `updateHeaders`. All other operators are built on top these two - * methods. + * A trait that provides a ton of powerful operators when extended. Any type + * that extends HeaderExtension needs to implement the two methods viz. + * `getHeaders` and `updateHeaders`. All other operators are built on top these + * two methods. */ private[zhttp] trait HeaderExtension[+A] extends HeaderModifier[A] with HeaderGetters[A] with HeaderChecks[A] { self: A => diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala index 72bab03352..90494b6a8f 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala @@ -12,7 +12,8 @@ import scala.util.control.NonFatal /** * Maintains a list of operators that parse and extract data from the headers. * - * NOTE: Add methods here if it performs some kind of processing on the header and returns the result. + * NOTE: Add methods here if it performs some kind of processing on the header + * and returns the result. */ trait HeaderGetters[+A] { self => diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala index e7d342fd86..fecf4336c8 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala @@ -4,11 +4,13 @@ import zhttp.http.{Cookie, Header, Headers, Method} import zio.duration.Duration /** - * Maintains a list of operators that modify the current Headers. Once modified, a new instance of the same type is - * returned. So or eg: `request.addHeader("A", "B")` should return a new `Request` and similarly `headers.add("A", "B")` - * should return a new `Headers` instance. + * Maintains a list of operators that modify the current Headers. Once modified, + * a new instance of the same type is returned. So or eg: + * `request.addHeader("A", "B")` should return a new `Request` and similarly + * `headers.add("A", "B")` should return a new `Headers` instance. * - * NOTE: Add methods here that modify the current headers and returns an instance of the same type. + * NOTE: Add methods here that modify the current headers and returns an + * instance of the same type. */ trait HeaderModifier[+A] { self => @@ -26,7 +28,8 @@ trait HeaderModifier[+A] { self => final def setHeaders(headers: Headers): A = self.updateHeaders(_ => headers) /** - * Updates the current Headers with new one, using the provided update function passed. + * Updates the current Headers with new one, using the provided update + * function passed. */ def updateHeaders(update: Headers => Headers): A diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderNames.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderNames.scala index 01b9a77307..ff4d07d0fc 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderNames.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderNames.scala @@ -3,8 +3,9 @@ package zhttp.http.headers import io.netty.handler.codec.http.HttpHeaderNames /** - * List of commonly use HeaderNames. They are provided to reduce bugs caused by typos and also to improve performance. - * `HeaderNames` arent encoded everytime one needs to send them over the wire. + * List of commonly use HeaderNames. They are provided to reduce bugs caused by + * typos and also to improve performance. `HeaderNames` arent encoded everytime + * one needs to send them over the wire. */ trait HeaderNames { final val accept: CharSequence = HttpHeaderNames.ACCEPT diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderValues.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderValues.scala index 9a678b40b9..48bb28b370 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderValues.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderValues.scala @@ -3,8 +3,9 @@ package zhttp.http.headers import io.netty.handler.codec.http.HttpHeaderValues /** - * List of commonly use HeaderValues. They are provided to reduce bugs caused by typos and also to improve performance. - * `HeaderValues` arent encoded everytime one needs to send them over the wire. + * List of commonly use HeaderValues. They are provided to reduce bugs caused by + * typos and also to improve performance. `HeaderValues` arent encoded everytime + * one needs to send them over the wire. */ trait HeaderValues { final val applicationJson: CharSequence = HttpHeaderValues.APPLICATION_JSON diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala index 1cd9bc5551..d76849b022 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala @@ -19,13 +19,15 @@ private[zhttp] trait Auth { ) /** - * Creates a middleware for basic authentication that checks if the credentials are same as the ones given + * Creates a middleware for basic authentication that checks if the + * credentials are same as the ones given */ final def basicAuth(u: String, p: String): HttpMiddleware[Any, Nothing] = basicAuth { case (user, password) => (user == u) && (password == p) } /** - * Creates an authentication middleware that only allows authenticated requests to be passed on to the app. + * Creates an authentication middleware that only allows authenticated + * requests to be passed on to the app. */ final def customAuth( verify: Headers => Boolean, diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala index 6935699780..e667222284 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala @@ -8,10 +8,12 @@ import java.util.UUID private[zhttp] trait Csrf { /** - * Generates a new CSRF token that can be validated using the csrfValidate middleware. + * Generates a new CSRF token that can be validated using the csrfValidate + * middleware. * - * CSRF middlewares: To prevent Cross-site request forgery attacks. This middleware is modeled after the double submit - * cookie pattern. Used in conjunction with [[#csrfValidate]] middleware. + * CSRF middlewares: To prevent Cross-site request forgery attacks. This + * middleware is modeled after the double submit cookie pattern. Used in + * conjunction with [[#csrfValidate]] middleware. * * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie */ @@ -22,11 +24,12 @@ private[zhttp] trait Csrf { Middleware.addCookieZIO(tokenGen.map(Cookie(tokenName, _))) /** - * Validates the CSRF token appearing in the request headers. Typically the token should be set using the - * `csrfGenerate` middleware. + * Validates the CSRF token appearing in the request headers. Typically the + * token should be set using the `csrfGenerate` middleware. * - * CSRF middlewares : To prevent Cross-site request forgery attacks. This middleware is modeled after the double - * submit cookie pattern. Used in conjunction with [[#csrfGenerate]] middleware + * CSRF middlewares : To prevent Cross-site request forgery attacks. This + * middleware is modeled after the double submit cookie pattern. Used in + * conjunction with [[#csrfGenerate]] middleware * * https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie */ diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala index d457861cb4..8239114e14 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala @@ -62,7 +62,8 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht Middleware.ifThenElse[Request](req => cond(req.method))(_ => left, _ => right) /** - * Logical operator to decide which middleware to select based on the predicate. + * Logical operator to decide which middleware to select based on the + * predicate. */ final def ifRequestThenElse[R, E]( cond: Request => Boolean, @@ -70,7 +71,8 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht Middleware.ifThenElse[Request](cond)(_ => left, _ => right) /** - * Logical operator to decide which middleware to select based on the predicate. + * Logical operator to decide which middleware to select based on the + * predicate. */ final def ifRequestThenElseZIO[R, E]( cond: Request => ZIO[R, E, Boolean], @@ -107,13 +109,15 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht Middleware.interceptZIO[Request, Response](_ => ZIO.unit)((res, _) => effect.mapBoth(Option(_), _ => res)) /** - * Runs the effect before the request is passed on to the HttpApp on which the middleware is applied. + * Runs the effect before the request is passed on to the HttpApp on which the + * middleware is applied. */ final def runBefore[R, E](effect: ZIO[R, E, Any]): HttpMiddleware[R, E] = Middleware.interceptZIOPatch(_ => effect.mapError(Option(_)).unit)((_, _) => UIO(Patch.empty)) /** - * Creates a new middleware that always sets the response status to the provided value + * Creates a new middleware that always sets the response status to the + * provided value */ final def setStatus(status: Status): HttpMiddleware[Any, Nothing] = patch(_ => Patch.setStatus(status)) @@ -157,7 +161,8 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht middleware.when[Request](cond) /** - * Applies the middleware only if the condition function effectfully evaluates to true + * Applies the middleware only if the condition function effectfully evaluates + * to true */ final def whenRequestZIO[R, E]( cond: Request => ZIO[R, E, Boolean], diff --git a/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala b/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala index 51ba921494..20d9be940a 100644 --- a/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala +++ b/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala @@ -8,9 +8,10 @@ import java.util.concurrent.CancellationException final class ChannelFuture[A] private (jFuture: Future[A]) { /** - * Resolves when the underlying future resolves and removes the handler (output: A) - if the future is resolved - * successfully (cause: None) - if the future fails with a CancellationException (cause: Throwable) - if the future - * fails with any other Exception + * Resolves when the underlying future resolves and removes the handler + * (output: A) - if the future is resolved successfully (cause: None) - if the + * future fails with a CancellationException (cause: Throwable) - if the + * future fails with any other Exception */ def execute: Task[Option[A]] = { var handler: GenericFutureListener[Future[A]] = { _ => {} } diff --git a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala index 2d3e0888ab..800fcf00bb 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala @@ -10,8 +10,9 @@ import scala.concurrent.{ExecutionContext => JExecutionContext} import scala.jdk.CollectionConverters._ /** - * Provides basic ZIO based utilities for any ZIO based program to execute in a channel's context. It will automatically - * cancel the execution when the channel closes. + * Provides basic ZIO based utilities for any ZIO based program to execute in a + * channel's context. It will automatically cancel the execution when the + * channel closes. */ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { def unsafeRun(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 23f43e34ca..f833043979 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -41,13 +41,15 @@ sealed trait Server[-R, +E] { self => make.useForever /** - * Launches the app with current settings: default EventLoopGroup (nThreads = 0) and ServerChannelFactory.auto. + * Launches the app with current settings: default EventLoopGroup (nThreads = + * 0) and ServerChannelFactory.auto. */ def startDefault[R1 <: Has[_] with R](implicit ev: E <:< Throwable): ZIO[R1, Throwable, Nothing] = start.provideSomeLayer[R1](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) /** - * Creates a new server with the maximum size of the request specified in bytes. + * Creates a new server with the maximum size of the request specified in + * bytes. */ def withMaxRequestSize(size: Int): Server[R, E] = Concat(self, Server.MaxRequestSize(size)) @@ -85,7 +87,8 @@ sealed trait Server[-R, +E] { self => def withSsl(sslOptions: ServerSSLOptions): Server[R, E] = Concat(self, Server.Ssl(sslOptions)) /** - * Creates a new server using a HttpServerExpectContinueHandler to send a 100 HttpResponse if necessary. + * Creates a new server using a HttpServerExpectContinueHandler to send a 100 + * HttpResponse if necessary. */ def withAcceptContinue(enable: Boolean): Server[R, E] = Concat(self, Server.AcceptContinue(enable)) @@ -102,15 +105,15 @@ sealed trait Server[-R, +E] { self => def withLeakDetection(level: LeakDetectionLevel): Server[R, E] = Concat(self, LeakDetection(level)) /** - * Creates a new server with netty's HttpServerKeepAliveHandler to close persistent connections when enable is true - * (@see HttpServerKeepAliveHandler). */ def withKeepAlive(enable: Boolean): Server[R, E] = Concat(self, KeepAlive(enable)) /** - * Creates a new server with FlushConsolidationHandler to control the flush operations in a more efficient way if - * enabled (@see FlushConsolidationHandler). */ def withConsolidateFlush(enable: Boolean): Server[R, E] = Concat(self, ConsolidateFlush(enable)) diff --git a/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala index 35c2ddc458..09880f957d 100644 --- a/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala @@ -9,7 +9,8 @@ import zhttp.socket.{SocketApp, WebSocketFrame} import zio.stream.ZStream /** - * A generic SocketApp handler that can be used on both - the client and the server. + * A generic SocketApp handler that can be used on both - the client and the + * server. */ final class WebSocketAppHandler[R]( zExec: HttpRuntime[R], diff --git a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala index fea3173516..2d02e6431b 100644 --- a/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala +++ b/zio-http/src/main/scala/zhttp/service/server/WebSocketUpgrade.scala @@ -16,7 +16,8 @@ trait WebSocketUpgrade[R] { self: ChannelHandler => res.status.asJava.code() == Status.SWITCHING_PROTOCOLS.asJava.code() && res.attribute.socketApp.nonEmpty /** - * Checks if the response requires to switch protocol to websocket. Returns true if it can, otherwise returns false + * Checks if the response requires to switch protocol to websocket. Returns + * true if it can, otherwise returns false */ final def upgradeToWebSocket(ctx: ChannelHandlerContext, jReq: FullHttpRequest, res: Response): Unit = { val app = res.attribute.socketApp diff --git a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala index fe53a3c501..4352eeb9a9 100644 --- a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala @@ -53,8 +53,9 @@ private[zhttp] case class ServerResponseHandler[R]( } /** - * Checks if an encoded version of the response exists, uses it if it does. Otherwise, it will return a fresh - * response. It will also set the server time if requested by the client. + * Checks if an encoded version of the response exists, uses it if it does. + * Otherwise, it will return a fresh response. It will also set the server + * time if requested by the client. */ private def encodeResponse(res: Response): HttpResponse = { diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 1555f94a13..5215fa6d3f 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -45,8 +45,9 @@ sealed trait Socket[-R, +E, -A, +B] { self => Socket.FOrElse(self, other) /** - * Provides the socket with its required environment, which eliminates its dependency on R. This operation assumes - * that your socket requires an environment. + * Provides the socket with its required environment, which eliminates its + * dependency on R. This operation assumes that your socket requires an + * environment. */ def provide(r: R)(implicit env: NeedsEnv[R]): Socket[Any, E, A, B] = Provide(self, r) diff --git a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala index 9a96e96e83..ca365aefe2 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala @@ -20,7 +20,8 @@ final case class SocketApp[-R]( ) { self => /** - * Creates a socket connection on the provided URL. Typically used to connect as a client. + * Creates a socket connection on the provided URL. Typically used to connect + * as a client. */ def connect(url: String): ZIO[R with EventLoopGroup with ChannelFactory, Throwable, Client.ClientResponse] = Client.socket(url, self) @@ -35,7 +36,8 @@ final case class SocketApp[-R]( }) /** - * Called whenever there is an error on the channel after a successful upgrade to websocket. + * Called whenever there is an error on the channel after a successful upgrade + * to websocket. */ def onError[R1 <: R](error: Throwable => ZIO[R1, Nothing, Any]): SocketApp[R1] = copy(error = self.error match { @@ -44,8 +46,8 @@ final case class SocketApp[-R]( }) /** - * Called on every incoming WebSocketFrame. In case of a failure on the returned stream, the socket is forcefully - * closed. + * Called on every incoming WebSocketFrame. In case of a failure on the + * returned stream, the socket is forcefully closed. */ def onMessage[R1 <: R](message: Socket[R1, Throwable, WebSocketFrame, WebSocketFrame]): SocketApp[R1] = copy(message = self.message match { @@ -54,15 +56,15 @@ final case class SocketApp[-R]( }) /** - * Called when the connection is successfully upgraded to a websocket one. In case of a failure, the socket is - * forcefully closed. + * Called when the connection is successfully upgraded to a websocket one. In + * case of a failure, the socket is forcefully closed. */ def onOpen[R1 <: R](open: Socket[R1, Throwable, Connection, WebSocketFrame]): SocketApp[R1] = onOpen(Handle(open)) /** - * Called when the connection is successfully upgraded to a websocket one. In case of a failure, the socket is - * forcefully closed. + * Called when the connection is successfully upgraded to a websocket one. In + * case of a failure, the socket is forcefully closed. */ def onOpen[R1 <: R](open: Connection => ZIO[R1, Throwable, Any]): SocketApp[R1] = onOpen(Handle(open)) @@ -77,7 +79,8 @@ final case class SocketApp[-R]( }) /** - * Provides the socket app with its required environment, which eliminates its dependency on `R`. + * Provides the socket app with its required environment, which eliminates its + * dependency on `R`. */ def provide(env: R)(implicit ev: NeedsEnv[R]): SocketApp[Any] = self.copy( @@ -109,8 +112,8 @@ final case class SocketApp[-R]( copy(protocol = self.protocol ++ protocol) /** - * Called when the connection is successfully upgraded to a websocket one. In case of a failure, the socket is - * forcefully closed. + * Called when the connection is successfully upgraded to a websocket one. In + * case of a failure, the socket is forcefully closed. */ private def onOpen[R1 <: R](open: Handle[R1]): SocketApp[R1] = copy(open = self.open.fold(Some(open))(other => Some(other merge open))) diff --git a/zio-http/src/main/scala/zhttp/socket/SocketDecoder.scala b/zio-http/src/main/scala/zhttp/socket/SocketDecoder.scala index cb0afd9a6b..cd819f2cd3 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketDecoder.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketDecoder.scala @@ -41,8 +41,8 @@ object SocketDecoder { private case object Default extends SocketDecoder /** - * Sets Maximum length of a frame's payload. Setting this to an appropriate value for you application helps check for - * denial of services attacks. + * Sets Maximum length of a frame's payload. Setting this to an appropriate + * value for you application helps check for denial of services attacks. */ def maxFramePayloadLength(length: Int): SocketDecoder = MaxFramePayloadLength(length) @@ -52,7 +52,8 @@ object SocketDecoder { def rejectMaskedFrames: SocketDecoder = RejectMaskedFrames /** - * When set to true, frames which are not masked properly according to the standard will still be accepted. + * When set to true, frames which are not masked properly according to the + * standard will still be accepted. */ def allowMaskMismatch: SocketDecoder = AllowMaskMismatch @@ -67,8 +68,9 @@ object SocketDecoder { def allowProtocolViolation: SocketDecoder = AllowProtocolViolation /** - * Allows you to avoid adding of Utf8FrameValidator to the pipeline on the WebSocketServerProtocolHandler creation. - * This is useful (less overhead) when you use only BinaryWebSocketFrame within your web socket connection. + * Allows you to avoid adding of Utf8FrameValidator to the pipeline on the + * WebSocketServerProtocolHandler creation. This is useful (less overhead) + * when you use only BinaryWebSocketFrame within your web socket connection. */ def skipUTF8Validation: SocketDecoder = SkipUTF8Validation diff --git a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala index 598743a980..a5706048fd 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala @@ -80,7 +80,8 @@ object SocketProtocol { def default: SocketProtocol = Default /** - * Close the connection if it was not closed by the client after timeout specified + * Close the connection if it was not closed by the client after timeout + * specified */ def forceCloseTimeout(duration: Duration): SocketProtocol = ForceCloseTimeoutMillis(duration) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 2f10a86ed7..b9231826bd 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -13,17 +13,19 @@ import zio.test.DefaultRunnableSpec import zio.{Has, ZIO, ZManaged} /** - * Should be used only when e2e tests needs to be written. Typically we would want to do that when we want to test the - * logic that is part of the netty based backend. For most of the other use cases directly running the HttpApp should - * suffice. HttpRunnableSpec spins of an actual Http server and makes requests. + * Should be used only when e2e tests needs to be written. Typically we would + * want to do that when we want to test the logic that is part of the netty + * based backend. For most of the other use cases directly running the HttpApp + * should suffice. HttpRunnableSpec spins of an actual Http server and makes + * requests. */ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => implicit class RunnableClientHttpSyntax[R, A](app: Http[R, Throwable, Client.ClientRequest, A]) { /** - * Runs the deployed Http app by making a real http request to it. The method allows us to configure individual - * constituents of a ClientRequest. + * Runs the deployed Http app by making a real http request to it. The + * method allows us to configure individual constituents of a ClientRequest. */ def run( path: Path = !!, @@ -49,10 +51,11 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => implicit class RunnableHttpClientAppSyntax(app: HttpApp[HttpEnv, Throwable]) { /** - * Deploys the http application on the test server and returns a Http of type - * {{{Http[R, E, ClientRequest, ClientResponse}}}. This allows us to assert using all the powerful operators that - * are available on `Http` while writing tests. It also allows us to simply pass a request in the end, to execute, - * and resolve it with a response, like a normal HttpApp. + * Deploys the http application on the test server and returns a Http of + * type {{{Http[R, E, ClientRequest, ClientResponse}}}. This allows us to + * assert using all the powerful operators that are available on `Http` + * while writing tests. It also allows us to simply pass a request in the + * end, to execute, and resolve it with a response, like a normal HttpApp. */ def deploy: HttpTestClient[Any, ClientRequest, ClientResponse] = for { From b67931850ed22662c547045444398e36e0a345ff Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Sat, 5 Feb 2022 20:22:27 +0530 Subject: [PATCH 71/95] remove get prefix (#958) --- .../main/scala/example/Authentication.scala | 2 +- .../src/main/scala/example/HttpsClient.scala | 2 +- .../src/main/scala/example/SimpleClient.scala | 2 +- .../src/main/scala/zhttp/http/Headers.scala | 2 +- zio-http/src/main/scala/zhttp/http/Http.scala | 24 +- .../main/scala/zhttp/http/IsResponse.scala | 18 +- .../src/main/scala/zhttp/http/Request.scala | 40 +- .../src/main/scala/zhttp/http/Response.scala | 10 +- .../zhttp/http/headers/HeaderChecks.scala | 6 +- .../zhttp/http/headers/HeaderGetters.scala | 350 +++++++++--------- .../scala/zhttp/http/middleware/Auth.scala | 4 +- .../scala/zhttp/http/middleware/Cors.scala | 4 +- .../scala/zhttp/http/middleware/Csrf.scala | 2 +- .../scala/zhttp/http/middleware/Web.scala | 10 +- .../src/main/scala/zhttp/service/Client.scala | 16 +- .../zhttp/service/EncodeClientRequest.scala | 2 +- .../main/scala/zhttp/service/Handler.scala | 4 +- .../scala/zhttp/service/HttpRuntime.scala | 10 +- .../zhttp/http/GetBodyAsStringSpec.scala | 4 +- .../test/scala/zhttp/http/HeaderSpec.scala | 52 +-- .../test/scala/zhttp/http/ResponseSpec.scala | 8 +- .../zhttp/http/middleware/AuthSpec.scala | 6 +- .../zhttp/http/middleware/CorsSpec.scala | 4 +- .../zhttp/http/middleware/CsrfSpec.scala | 2 +- .../scala/zhttp/http/middleware/WebSpec.scala | 36 +- .../scala/zhttp/internal/DynamicServer.scala | 20 +- .../internal/HttpAppTestExtensions.scala | 14 +- .../zhttp/internal/HttpRunnableSpec.scala | 4 +- .../test/scala/zhttp/service/ClientSpec.scala | 12 +- .../scala/zhttp/service/KeepAliveSpec.scala | 8 +- .../test/scala/zhttp/service/ServerSpec.scala | 68 ++-- 31 files changed, 370 insertions(+), 376 deletions(-) diff --git a/example/src/main/scala/example/Authentication.scala b/example/src/main/scala/example/Authentication.scala index 9dead8229e..afd1b3619d 100644 --- a/example/src/main/scala/example/Authentication.scala +++ b/example/src/main/scala/example/Authentication.scala @@ -32,7 +32,7 @@ object Authentication extends App { def authenticate[R, E](fail: HttpApp[R, E], success: JwtClaim => HttpApp[R, E]): HttpApp[R, E] = Http .fromFunction[Request] { - _.getHeader("X-ACCESS-TOKEN") + _.header("X-ACCESS-TOKEN") .flatMap(header => jwtDecode(header._2.toString)) .fold[HttpApp[R, E]](fail)(success) } diff --git a/example/src/main/scala/example/HttpsClient.scala b/example/src/main/scala/example/HttpsClient.scala index 12b98c47c1..f604987675 100644 --- a/example/src/main/scala/example/HttpsClient.scala +++ b/example/src/main/scala/example/HttpsClient.scala @@ -30,7 +30,7 @@ object HttpsClient extends App { val program = for { res <- Client.request(url, headers = headers, ssl = sslOption) - data <- res.getBodyAsString + data <- res.bodyAsString _ <- console.putStrLn { data } } yield () diff --git a/example/src/main/scala/example/SimpleClient.scala b/example/src/main/scala/example/SimpleClient.scala index da885c0a50..6f7b7e697d 100644 --- a/example/src/main/scala/example/SimpleClient.scala +++ b/example/src/main/scala/example/SimpleClient.scala @@ -9,7 +9,7 @@ object SimpleClient extends App { val program = for { res <- Client.request(url) - data <- res.getBodyAsString + data <- res.bodyAsString _ <- console.putStrLn { data } } yield () diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index 24b74092f6..f6677aa4eb 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -24,7 +24,7 @@ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers def combineIf(cond: Boolean)(other: Headers): Headers = if (cond) Headers(self.toChunk ++ other.toChunk) else self - override def getHeaders: Headers = self + override def headers: Headers = self def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 40d3ceb82d..da295eccfe 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -182,36 +182,36 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Extracts body */ - final def getBody(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, Chunk[Byte]] = - self.getBodyAsByteBuf.mapZIO(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) + final def body(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, Chunk[Byte]] = + self.bodyAsByteBuf.mapZIO(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) /** * Extracts body as a string */ - final def getBodyAsString(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, String] = - self.getBodyAsByteBuf.mapZIO(bytes => Task(bytes.toString(HTTP_CHARSET))) + final def bodyAsString(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, String] = + self.bodyAsByteBuf.mapZIO(bytes => Task(bytes.toString(HTTP_CHARSET))) /** * Extracts content-length from the response if available */ - final def getContentLength(implicit eb: IsResponse[B]): Http[R, E, A, Option[Long]] = - getHeaders.map(_.getContentLength) + final def contentLength(implicit eb: IsResponse[B]): Http[R, E, A, Option[Long]] = + headers.map(_.contentLength) /** * Extracts the value of the provided header name. */ - final def getHeaderValue(name: CharSequence)(implicit eb: IsResponse[B]): Http[R, E, A, Option[CharSequence]] = - getHeaders.map(_.getHeaderValue(name)) + final def headerValue(name: CharSequence)(implicit eb: IsResponse[B]): Http[R, E, A, Option[CharSequence]] = + headers.map(_.headerValue(name)) /** * Extracts the `Headers` from the type `B` if possible */ - final def getHeaders(implicit eb: IsResponse[B]): Http[R, E, A, Headers] = self.map(eb.getHeaders) + final def headers(implicit eb: IsResponse[B]): Http[R, E, A, Headers] = self.map(eb.headers) /** * Extracts `Status` from the type `B` is possible. */ - final def getStatus(implicit ev: IsResponse[B]): Http[R, E, A, Status] = self.map(ev.getStatus) + final def status(implicit ev: IsResponse[B]): Http[R, E, A, Status] = self.map(ev.status) /** * Transforms the output of the http app @@ -402,11 +402,11 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Extracts body as a ByteBuf */ - private[zhttp] final def getBodyAsByteBuf(implicit + private[zhttp] final def bodyAsByteBuf(implicit eb: IsResponse[B], ee: E <:< Throwable, ): Http[R, Throwable, A, ByteBuf] = - self.widen[Throwable, B].mapZIO(eb.getBodyAsByteBuf) + self.widen[Throwable, B].mapZIO(eb.bodyAsByteBuf) } object Http { diff --git a/zio-http/src/main/scala/zhttp/http/IsResponse.scala b/zio-http/src/main/scala/zhttp/http/IsResponse.scala index 8f68acf23c..e142b03bf5 100644 --- a/zio-http/src/main/scala/zhttp/http/IsResponse.scala +++ b/zio-http/src/main/scala/zhttp/http/IsResponse.scala @@ -5,21 +5,21 @@ import zhttp.service.Client.ClientResponse import zio.Task sealed trait IsResponse[-A] { - def getBodyAsByteBuf(a: A): Task[ByteBuf] - def getHeaders(a: A): Headers - def getStatus(a: A): Status + def bodyAsByteBuf(a: A): Task[ByteBuf] + def headers(a: A): Headers + def status(a: A): Status } object IsResponse { implicit object serverResponse extends IsResponse[Response] { - def getBodyAsByteBuf(a: Response): Task[ByteBuf] = a.getBodyAsByteBuf - def getHeaders(a: Response): Headers = a.headers - def getStatus(a: Response): Status = a.status + def bodyAsByteBuf(a: Response): Task[ByteBuf] = a.bodyAsByteBuf + def headers(a: Response): Headers = a.headers + def status(a: Response): Status = a.status } implicit object clientResponse extends IsResponse[ClientResponse] { - def getBodyAsByteBuf(a: ClientResponse): Task[ByteBuf] = a.getBodyAsByteBuf - def getHeaders(a: ClientResponse): Headers = a.headers - def getStatus(a: ClientResponse): Status = a.status + def bodyAsByteBuf(a: ClientResponse): Task[ByteBuf] = a.bodyAsByteBuf + def headers(a: ClientResponse): Headers = a.headers + def status(a: ClientResponse): Status = a.status } } diff --git a/zio-http/src/main/scala/zhttp/http/Request.scala b/zio-http/src/main/scala/zhttp/http/Request.scala index a930ea5ed5..68c79d664d 100644 --- a/zio-http/src/main/scala/zhttp/http/Request.scala +++ b/zio-http/src/main/scala/zhttp/http/Request.scala @@ -11,37 +11,37 @@ trait Request extends HeaderExtension[Request] { self => /** * Updates the headers using the provided function */ - final override def updateHeaders(update: Headers => Headers): Request = self.copy(headers = update(self.getHeaders)) + final override def updateHeaders(update: Headers => Headers): Request = self.copy(headers = update(self.headers)) - def copy(method: Method = self.method, url: URL = self.url, headers: Headers = self.getHeaders): Request = { + def copy(method: Method = self.method, url: URL = self.url, headers: Headers = self.headers): Request = { val m = method val u = url val h = headers new Request { override def method: Method = m override def url: URL = u - override def getHeaders: Headers = h + override def headers: Headers = h override def remoteAddress: Option[InetAddress] = self.remoteAddress - override private[zhttp] def getBodyAsByteBuf = self.getBodyAsByteBuf + override private[zhttp] def bodyAsByteBuf = self.bodyAsByteBuf } } /** * Decodes the content of request as a Chunk of Bytes */ - def getBody: Task[Chunk[Byte]] = - getBodyAsByteBuf.flatMap(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) + def body: Task[Chunk[Byte]] = + bodyAsByteBuf.flatMap(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) /** * Decodes the content of request as string */ - def getBodyAsString: Task[String] = - getBodyAsByteBuf.flatMap(buf => Task(buf.toString(getCharset))) + def bodyAsString: Task[String] = + bodyAsByteBuf.flatMap(buf => Task(buf.toString(charset))) /** * Gets all the headers in the Request */ - def getHeaders: Headers + def headers: Headers /** * Checks is the request is a pre-flight request or not @@ -83,7 +83,7 @@ trait Request extends HeaderExtension[Request] { self => */ def url: URL - private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] + private[zhttp] def bodyAsByteBuf: Task[ByteBuf] } object Request { @@ -103,11 +103,11 @@ object Request { val h = headers val ra = remoteAddress new Request { - override def method: Method = m - override def url: URL = u - override def getHeaders: Headers = h - override def remoteAddress: Option[InetAddress] = ra - override private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = data.toByteBuf + override def method: Method = m + override def url: URL = u + override def headers: Headers = h + override def remoteAddress: Option[InetAddress] = ra + override private[zhttp] def bodyAsByteBuf: Task[ByteBuf] = data.toByteBuf } } @@ -127,11 +127,11 @@ object Request { * Lift request to TypedRequest with option to extract params */ final class ParameterizedRequest[A](req: Request, val params: A) extends Request { - override def getHeaders: Headers = req.getHeaders - override def method: Method = req.method - override def remoteAddress: Option[InetAddress] = req.remoteAddress - override def url: URL = req.url - override private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = req.getBodyAsByteBuf + override def headers: Headers = req.headers + override def method: Method = req.method + override def remoteAddress: Option[InetAddress] = req.remoteAddress + override def url: URL = req.url + override private[zhttp] def bodyAsByteBuf: Task[ByteBuf] = req.bodyAsByteBuf } object ParameterizedRequest { diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index 1662624d62..d400ac7275 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -24,7 +24,7 @@ final case class Response private ( * Adds cookies in the response headers. */ def addCookie(cookie: Cookie): Response = - self.copy(headers = self.getHeaders ++ Headers(HttpHeaderNames.SET_COOKIE.toString, cookie.encode)) + self.copy(headers = self.headers ++ Headers(HttpHeaderNames.SET_COOKIE.toString, cookie.encode)) /** * A micro-optimizations that ignores all further modifications to the @@ -38,8 +38,6 @@ final case class Response private ( def freeze: UIO[Response] = UIO(self.copy(attribute = self.attribute.withEncodedResponse(unsafeEncode(), self))) - override def getHeaders: Headers = headers - /** * Sets the response attributes */ @@ -56,7 +54,7 @@ final case class Response private ( * Updates the headers using the provided function */ override def updateHeaders(update: Headers => Headers): Response = - self.copy(headers = update(self.getHeaders)) + self.copy(headers = update(self.headers)) /** * A more efficient way to append server-time to the response headers. @@ -66,7 +64,7 @@ final case class Response private ( /** * Extracts the body as ByteBuf */ - private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = self.data.toByteBuf + private[zhttp] def bodyAsByteBuf: Task[ByteBuf] = self.data.toByteBuf /** * Encodes the Response into a Netty HttpResponse. Sets default headers such @@ -77,7 +75,7 @@ final case class Response private ( private[zhttp] def unsafeEncode(): HttpResponse = { import io.netty.handler.codec.http._ - val jHeaders = self.getHeaders.encode + val jHeaders = self.headers.encode val jContent = self.data match { case HttpData.Text(text, charset) => Unpooled.wrappedBuffer(text.getBytes(charset)) case HttpData.BinaryChunk(data) => Unpooled.copiedBuffer(data.toArray) diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala index abf12a2845..36b5c7a49f 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderChecks.scala @@ -12,19 +12,19 @@ import zhttp.http.HeaderValues */ trait HeaderChecks[+A] { self: HeaderExtension[A] with A => final def hasContentType(value: CharSequence): Boolean = - getContentType.exists(contentEqualsIgnoreCase(value, _)) + contentType.exists(contentEqualsIgnoreCase(value, _)) final def hasFormUrlencodedContentType: Boolean = hasContentType(HeaderValues.applicationXWWWFormUrlencoded) final def hasHeader(name: CharSequence, value: CharSequence): Boolean = - getHeaderValue(name) match { + headerValue(name) match { case Some(v1) => v1.contentEquals(value) case None => false } final def hasHeader(name: CharSequence): Boolean = - getHeaderValue(name).nonEmpty + headerValue(name).nonEmpty final def hasJsonContentType: Boolean = hasContentType(HeaderValues.applicationJson) diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala index 90494b6a8f..3fedd1f7b4 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderGetters.scala @@ -3,7 +3,7 @@ package zhttp.http.headers import io.netty.handler.codec.http.HttpUtil import io.netty.util.AsciiString.contentEqualsIgnoreCase import zhttp.http.Headers.{BasicSchemeName, BearerSchemeName} -import zhttp.http.{Cookie, HTTP_CHARSET, Header, HeaderNames, Headers} +import zhttp.http._ import java.nio.charset.Charset import java.util.Base64 @@ -17,64 +17,64 @@ import scala.util.control.NonFatal */ trait HeaderGetters[+A] { self => - final def getAccept: Option[CharSequence] = - getHeaderValue(HeaderNames.accept) + final def accept: Option[CharSequence] = + headerValue(HeaderNames.accept) - final def getAcceptCharset: Option[CharSequence] = - getHeaderValue(HeaderNames.acceptCharset) + final def acceptCharset: Option[CharSequence] = + headerValue(HeaderNames.acceptCharset) - final def getAcceptEncoding: Option[CharSequence] = - getHeaderValue(HeaderNames.acceptEncoding) + final def acceptEncoding: Option[CharSequence] = + headerValue(HeaderNames.acceptEncoding) - final def getAcceptLanguage: Option[CharSequence] = - getHeaderValue(HeaderNames.acceptLanguage) + final def acceptLanguage: Option[CharSequence] = + headerValue(HeaderNames.acceptLanguage) - final def getAcceptPatch: Option[CharSequence] = - getHeaderValue(HeaderNames.acceptPatch) + final def acceptPatch: Option[CharSequence] = + headerValue(HeaderNames.acceptPatch) - final def getAcceptRanges: Option[CharSequence] = - getHeaderValue(HeaderNames.acceptRanges) + final def acceptRanges: Option[CharSequence] = + headerValue(HeaderNames.acceptRanges) - final def getAccessControlAllowCredentials: Option[Boolean] = - getHeaderValue(HeaderNames.accessControlAllowCredentials) match { + final def accessControlAllowCredentials: Option[Boolean] = + headerValue(HeaderNames.accessControlAllowCredentials) match { case Some(string) => try Some(string.toBoolean) catch { case _: Throwable => None } case None => None } - final def getAccessControlAllowHeaders: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlAllowHeaders) + final def accessControlAllowHeaders: Option[CharSequence] = + headerValue(HeaderNames.accessControlAllowHeaders) - final def getAccessControlAllowMethods: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlAllowMethods) + final def accessControlAllowMethods: Option[CharSequence] = + headerValue(HeaderNames.accessControlAllowMethods) - final def getAccessControlAllowOrigin: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlAllowOrigin) + final def accessControlAllowOrigin: Option[CharSequence] = + headerValue(HeaderNames.accessControlAllowOrigin) - final def getAccessControlExposeHeaders: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlExposeHeaders) + final def accessControlExposeHeaders: Option[CharSequence] = + headerValue(HeaderNames.accessControlExposeHeaders) - final def getAccessControlMaxAge: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlMaxAge) + final def accessControlMaxAge: Option[CharSequence] = + headerValue(HeaderNames.accessControlMaxAge) - final def getAccessControlRequestHeaders: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlRequestHeaders) + final def accessControlRequestHeaders: Option[CharSequence] = + headerValue(HeaderNames.accessControlRequestHeaders) - final def getAccessControlRequestMethod: Option[CharSequence] = - getHeaderValue(HeaderNames.accessControlRequestMethod) + final def accessControlRequestMethod: Option[CharSequence] = + headerValue(HeaderNames.accessControlRequestMethod) - final def getAge: Option[CharSequence] = - getHeaderValue(HeaderNames.age) + final def age: Option[CharSequence] = + headerValue(HeaderNames.age) - final def getAllow: Option[CharSequence] = - getHeaderValue(HeaderNames.allow) + final def allow: Option[CharSequence] = + headerValue(HeaderNames.allow) - final def getAuthorization: Option[CharSequence] = - getHeaderValue(HeaderNames.authorization) + final def authorization: Option[CharSequence] = + headerValue(HeaderNames.authorization) - final def getBasicAuthorizationCredentials: Option[Header] = { - getAuthorization + final def basicAuthorizationCredentials: Option[Header] = { + authorization .map(_.toString) .flatMap(v => { val indexOfBasic = v.indexOf(BasicSchemeName) @@ -91,7 +91,7 @@ trait HeaderGetters[+A] { self => }) } - final def getBearerToken: Option[String] = getAuthorization + final def bearerToken: Option[String] = authorization .map(_.toString) .flatMap(v => { val indexOfBearer = v.indexOf(BearerSchemeName) @@ -101,32 +101,32 @@ trait HeaderGetters[+A] { self => Some(v.substring(BearerSchemeName.length + 1)) }) - final def getCacheControl: Option[CharSequence] = - getHeaderValue(HeaderNames.cacheControl) + final def cacheControl: Option[CharSequence] = + headerValue(HeaderNames.cacheControl) - final def getCharset: Charset = - getHeaderValue(HeaderNames.contentType) match { + final def charset: Charset = + headerValue(HeaderNames.contentType) match { case Some(value) => HttpUtil.getCharset(value, HTTP_CHARSET) case None => HTTP_CHARSET } - final def getConnection: Option[CharSequence] = - getHeaderValue(HeaderNames.connection) + final def connection: Option[CharSequence] = + headerValue(HeaderNames.connection) - final def getContentBase: Option[CharSequence] = - getHeaderValue(HeaderNames.contentBase) + final def contentBase: Option[CharSequence] = + headerValue(HeaderNames.contentBase) - final def getContentDisposition: Option[CharSequence] = - getHeaderValue(HeaderNames.contentDisposition) + final def contentDisposition: Option[CharSequence] = + headerValue(HeaderNames.contentDisposition) - final def getContentEncoding: Option[CharSequence] = - getHeaderValue(HeaderNames.contentEncoding) + final def contentEncoding: Option[CharSequence] = + headerValue(HeaderNames.contentEncoding) - final def getContentLanguage: Option[CharSequence] = - getHeaderValue(HeaderNames.contentLanguage) + final def contentLanguage: Option[CharSequence] = + headerValue(HeaderNames.contentLanguage) - final def getContentLength: Option[Long] = - getHeaderValue(HeaderNames.contentLength) match { + final def contentLength: Option[Long] = + headerValue(HeaderNames.contentLength) match { case Some(str) => try Some(str.toString.toLong) catch { @@ -135,197 +135,197 @@ trait HeaderGetters[+A] { self => case None => None } - final def getContentLocation: Option[CharSequence] = - getHeaderValue(HeaderNames.contentLocation) + final def contentLocation: Option[CharSequence] = + headerValue(HeaderNames.contentLocation) - final def getContentMd5: Option[CharSequence] = - getHeaderValue(HeaderNames.contentMd5) + final def contentMd5: Option[CharSequence] = + headerValue(HeaderNames.contentMd5) - final def getContentRange: Option[CharSequence] = - getHeaderValue(HeaderNames.contentRange) + final def contentRange: Option[CharSequence] = + headerValue(HeaderNames.contentRange) - final def getContentSecurityPolicy: Option[CharSequence] = - getHeaderValue(HeaderNames.contentSecurityPolicy) + final def contentSecurityPolicy: Option[CharSequence] = + headerValue(HeaderNames.contentSecurityPolicy) - final def getContentTransferEncoding: Option[CharSequence] = - getHeaderValue(HeaderNames.contentTransferEncoding) + final def contentTransferEncoding: Option[CharSequence] = + headerValue(HeaderNames.contentTransferEncoding) - final def getContentType: Option[CharSequence] = - getHeaderValue(HeaderNames.contentType) + final def contentType: Option[CharSequence] = + headerValue(HeaderNames.contentType) - final def getCookie: Option[CharSequence] = - getHeaderValue(HeaderNames.cookie) + final def cookie: Option[CharSequence] = + headerValue(HeaderNames.cookie) - final def getCookiesDecoded: List[Cookie] = - getHeaderValues(HeaderNames.cookie).flatMap { header => + final def cookieValue(name: CharSequence): Option[CharSequence] = + cookiesDecoded.find(_.name == name).map(_.content) + + final def cookiesDecoded: List[Cookie] = + headerValues(HeaderNames.cookie).flatMap { header => Cookie.decodeRequestCookie(header) match { case None => Nil case Some(list) => list } } - final def getCookieValue(name: CharSequence): Option[CharSequence] = - getCookiesDecoded.find(_.name == name).map(_.content) - - final def getDate: Option[CharSequence] = - getHeaderValue(HeaderNames.date) + final def date: Option[CharSequence] = + headerValue(HeaderNames.date) - final def getDnt: Option[CharSequence] = - getHeaderValue(HeaderNames.dnt) + final def dnt: Option[CharSequence] = + headerValue(HeaderNames.dnt) - final def getEtag: Option[CharSequence] = - getHeaderValue(HeaderNames.etag) + final def etag: Option[CharSequence] = + headerValue(HeaderNames.etag) - final def getExpect: Option[CharSequence] = - getHeaderValue(HeaderNames.expect) + final def expect: Option[CharSequence] = + headerValue(HeaderNames.expect) - final def getExpires: Option[CharSequence] = - getHeaderValue(HeaderNames.expires) + final def expires: Option[CharSequence] = + headerValue(HeaderNames.expires) - final def getFrom: Option[CharSequence] = - getHeaderValue(HeaderNames.from) + final def from: Option[CharSequence] = + headerValue(HeaderNames.from) - final def getHeader(headerName: CharSequence): Option[Header] = - getHeaders.toList + final def header(headerName: CharSequence): Option[Header] = + headers.toList .find(h => contentEqualsIgnoreCase(h._1, headerName)) - final def getHeaderValue(headerName: CharSequence): Option[String] = - getHeader(headerName).map(_._2.toString) + final def headerValue(headerName: CharSequence): Option[String] = + header(headerName).map(_._2.toString) - final def getHeaderValues(headerName: CharSequence): List[String] = - getHeaders.toList.collect { case h if contentEqualsIgnoreCase(h._1, headerName) => h._2.toString } + final def headerValues(headerName: CharSequence): List[String] = + headers.toList.collect { case h if contentEqualsIgnoreCase(h._1, headerName) => h._2.toString } /** * Returns the Headers object on the current type A */ - def getHeaders: Headers + def headers: Headers - final def getHeadersAsList: List[(String, String)] = self.getHeaders.toList + final def headersAsList: List[(String, String)] = self.headers.toList - final def getHost: Option[CharSequence] = - getHeaderValue(HeaderNames.host) + final def host: Option[CharSequence] = + headerValue(HeaderNames.host) - final def getIfMatch: Option[CharSequence] = - getHeaderValue(HeaderNames.ifMatch) + final def ifMatch: Option[CharSequence] = + headerValue(HeaderNames.ifMatch) - final def getIfModifiedSince: Option[CharSequence] = - getHeaderValue(HeaderNames.ifModifiedSince) + final def ifModifiedSince: Option[CharSequence] = + headerValue(HeaderNames.ifModifiedSince) - final def getIfNoneMatch: Option[CharSequence] = - getHeaderValue(HeaderNames.ifNoneMatch) + final def ifNoneMatch: Option[CharSequence] = + headerValue(HeaderNames.ifNoneMatch) - final def getIfRange: Option[CharSequence] = - getHeaderValue(HeaderNames.ifRange) + final def ifRange: Option[CharSequence] = + headerValue(HeaderNames.ifRange) - final def getIfUnmodifiedSince: Option[CharSequence] = - getHeaderValue(HeaderNames.ifUnmodifiedSince) + final def ifUnmodifiedSince: Option[CharSequence] = + headerValue(HeaderNames.ifUnmodifiedSince) - final def getLastModified: Option[CharSequence] = - getHeaderValue(HeaderNames.lastModified) + final def lastModified: Option[CharSequence] = + headerValue(HeaderNames.lastModified) - final def getLocation: Option[CharSequence] = - getHeaderValue(HeaderNames.location) + final def location: Option[CharSequence] = + headerValue(HeaderNames.location) - final def getMaxForwards: Option[CharSequence] = - getHeaderValue(HeaderNames.maxForwards) + final def maxForwards: Option[CharSequence] = + headerValue(HeaderNames.maxForwards) - final def getOrigin: Option[CharSequence] = - getHeaderValue(HeaderNames.origin) + final def origin: Option[CharSequence] = + headerValue(HeaderNames.origin) - final def getPragma: Option[CharSequence] = - getHeaderValue(HeaderNames.pragma) + final def pragma: Option[CharSequence] = + headerValue(HeaderNames.pragma) - final def getProxyAuthenticate: Option[CharSequence] = - getHeaderValue(HeaderNames.proxyAuthenticate) + final def proxyAuthenticate: Option[CharSequence] = + headerValue(HeaderNames.proxyAuthenticate) - final def getProxyAuthorization: Option[CharSequence] = - getHeaderValue(HeaderNames.proxyAuthorization) + final def proxyAuthorization: Option[CharSequence] = + headerValue(HeaderNames.proxyAuthorization) - final def getRange: Option[CharSequence] = - getHeaderValue(HeaderNames.range) + final def range: Option[CharSequence] = + headerValue(HeaderNames.range) - final def getReferer: Option[CharSequence] = - getHeaderValue(HeaderNames.referer) + final def referer: Option[CharSequence] = + headerValue(HeaderNames.referer) - final def getRetryAfter: Option[CharSequence] = - getHeaderValue(HeaderNames.retryAfter) + final def retryAfter: Option[CharSequence] = + headerValue(HeaderNames.retryAfter) - final def getSecWebSocketAccept: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketAccept) + final def secWebSocketAccept: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketAccept) - final def getSecWebSocketExtensions: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketExtensions) + final def secWebSocketExtensions: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketExtensions) - final def getSecWebSocketKey: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketKey) + final def secWebSocketKey: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketKey) - final def getSecWebSocketLocation: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketLocation) + final def secWebSocketLocation: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketLocation) - final def getSecWebSocketOrigin: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketOrigin) + final def secWebSocketOrigin: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketOrigin) - final def getSecWebSocketProtocol: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketProtocol) + final def secWebSocketProtocol: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketProtocol) - final def getSecWebSocketVersion: Option[CharSequence] = - getHeaderValue(HeaderNames.secWebSocketVersion) + final def secWebSocketVersion: Option[CharSequence] = + headerValue(HeaderNames.secWebSocketVersion) - final def getServer: Option[CharSequence] = - getHeaderValue(HeaderNames.server) + final def server: Option[CharSequence] = + headerValue(HeaderNames.server) - final def getSetCookie: Option[CharSequence] = - getHeaderValue(HeaderNames.setCookie) + final def setCookie: Option[CharSequence] = + headerValue(HeaderNames.setCookie) - final def getSetCookiesDecoded(secret: Option[String] = None): List[Cookie] = - getHeaderValues(HeaderNames.setCookie) + final def setCookiesDecoded(secret: Option[String] = None): List[Cookie] = + headerValues(HeaderNames.setCookie) .map(Cookie.decodeResponseCookie(_, secret)) .collect { case Some(cookie) => cookie } - final def getTe: Option[CharSequence] = - getHeaderValue(HeaderNames.te) + final def te: Option[CharSequence] = + headerValue(HeaderNames.te) - final def getTrailer: Option[CharSequence] = - getHeaderValue(HeaderNames.trailer) + final def trailer: Option[CharSequence] = + headerValue(HeaderNames.trailer) - final def getTransferEncoding: Option[CharSequence] = - getHeaderValue(HeaderNames.transferEncoding) + final def transferEncoding: Option[CharSequence] = + headerValue(HeaderNames.transferEncoding) - final def getUpgrade: Option[CharSequence] = - getHeaderValue(HeaderNames.upgrade) + final def upgrade: Option[CharSequence] = + headerValue(HeaderNames.upgrade) - final def getUpgradeInsecureRequests: Option[CharSequence] = - getHeaderValue(HeaderNames.upgradeInsecureRequests) + final def upgradeInsecureRequests: Option[CharSequence] = + headerValue(HeaderNames.upgradeInsecureRequests) - final def getUserAgent: Option[CharSequence] = - getHeaderValue(HeaderNames.userAgent) + final def userAgent: Option[CharSequence] = + headerValue(HeaderNames.userAgent) - final def getVary: Option[CharSequence] = - getHeaderValue(HeaderNames.vary) + final def vary: Option[CharSequence] = + headerValue(HeaderNames.vary) - final def getVia: Option[CharSequence] = - getHeaderValue(HeaderNames.via) + final def via: Option[CharSequence] = + headerValue(HeaderNames.via) - final def getWarning: Option[CharSequence] = - getHeaderValue(HeaderNames.warning) + final def warning: Option[CharSequence] = + headerValue(HeaderNames.warning) - final def getWebSocketLocation: Option[CharSequence] = - getHeaderValue(HeaderNames.webSocketLocation) + final def webSocketLocation: Option[CharSequence] = + headerValue(HeaderNames.webSocketLocation) - final def getWebSocketOrigin: Option[CharSequence] = - getHeaderValue(HeaderNames.webSocketOrigin) + final def webSocketOrigin: Option[CharSequence] = + headerValue(HeaderNames.webSocketOrigin) - final def getWebSocketProtocol: Option[CharSequence] = - getHeaderValue(HeaderNames.webSocketProtocol) + final def webSocketProtocol: Option[CharSequence] = + headerValue(HeaderNames.webSocketProtocol) - final def getWwwAuthenticate: Option[CharSequence] = - getHeaderValue(HeaderNames.wwwAuthenticate) + final def wwwAuthenticate: Option[CharSequence] = + headerValue(HeaderNames.wwwAuthenticate) - final def getXFrameOptions: Option[CharSequence] = - getHeaderValue(HeaderNames.xFrameOptions) + final def xFrameOptions: Option[CharSequence] = + headerValue(HeaderNames.xFrameOptions) - final def getXRequestedWith: Option[CharSequence] = - getHeaderValue(HeaderNames.xRequestedWith) + final def xRequestedWith: Option[CharSequence] = + headerValue(HeaderNames.xRequestedWith) private def decodeHttpBasic(encoded: String): Option[Header] = { val decoded = new String(Base64.getDecoder.decode(encoded)) diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala index d76849b022..4136ce8a85 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Auth.scala @@ -11,7 +11,7 @@ private[zhttp] trait Auth { */ final def basicAuth(f: Header => Boolean): HttpMiddleware[Any, Nothing] = customAuth( - _.getBasicAuthorizationCredentials match { + _.basicAuthorizationCredentials match { case Some(header) => f(header) case None => false }, @@ -33,7 +33,7 @@ private[zhttp] trait Auth { verify: Headers => Boolean, responseHeaders: Headers = Headers.empty, ): HttpMiddleware[Any, Nothing] = - Middleware.ifThenElse[Request](req => verify(req.getHeaders))( + Middleware.ifThenElse[Request](req => verify(req.headers))( _ => Middleware.identity, _ => Middleware.fromHttp(Http.status(Status.FORBIDDEN).addHeaders(responseHeaders)), ) diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala b/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala index 22ced6ab15..6797f45a71 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Cors.scala @@ -43,8 +43,8 @@ private[zhttp] trait Cors { Middleware.collect[Request] { case req => ( req.method, - req.getHeaders.getHeader(HttpHeaderNames.ORIGIN), - req.getHeaders.getHeader(HttpHeaderNames.ACCESS_CONTROL_REQUEST_METHOD), + req.headers.header(HttpHeaderNames.ORIGIN), + req.headers.header(HttpHeaderNames.ACCESS_CONTROL_REQUEST_METHOD), ) match { case (Method.OPTIONS, Some(origin), Some(acrm)) if allowCORS(origin, Method.fromString(acrm._2.toString)) => Middleware.succeed( diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala index e667222284..b5f0af20d5 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Csrf.scala @@ -36,7 +36,7 @@ private[zhttp] trait Csrf { def csrfValidate(tokenName: String = "x-csrf-token"): HttpMiddleware[Any, Nothing] = { Middleware.whenHeader( headers => { - (headers.getHeaderValue(tokenName), headers.getCookieValue(tokenName)) match { + (headers.headerValue(tokenName), headers.cookieValue(tokenName)) match { case (Some(headerValue), Some(cookieValue)) => headerValue != cookieValue case _ => true } diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala index 8239114e14..e828bb4c26 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala @@ -51,7 +51,7 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht final def ifHeaderThenElse[R, E]( cond: Headers => Boolean, )(left: HttpMiddleware[R, E], right: HttpMiddleware[R, E]): HttpMiddleware[R, E] = - Middleware.ifThenElse[Request](req => cond(req.getHeaders))(_ => left, _ => right) + Middleware.ifThenElse[Request](req => cond(req.headers))(_ => left, _ => right) /** * Logical operator to decide which middleware to select based on the method. @@ -126,12 +126,12 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht */ final def signCookies(secret: String): HttpMiddleware[Any, Nothing] = updateHeaders { - case h if h.getHeader(HeaderNames.setCookie).isDefined => + case h if h.header(HeaderNames.setCookie).isDefined => Headers( HeaderNames.setCookie, - Cookie.decodeResponseCookie(h.getHeader(HeaderNames.setCookie).get._2.toString).get.sign(secret).encode, + Cookie.decodeResponseCookie(h.header(HeaderNames.setCookie).get._2.toString).get.sign(secret).encode, ) - case h => h + case h => h } /** @@ -150,7 +150,7 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht * Applies the middleware only when the condition for the headers are true */ final def whenHeader[R, E](cond: Headers => Boolean, middleware: HttpMiddleware[R, E]): HttpMiddleware[R, E] = - middleware.when[Request](req => cond(req.getHeaders)) + middleware.when[Request](req => cond(req.headers)) /** * Applies the middleware only if the condition function evaluates to true diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index fd868c01fd..8e9e02f422 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -94,7 +94,7 @@ final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el // Add WebSocketHandlers if it's a `ws` or `wss` request if (isWebSocket) { - val headers = req.getHeaders.encode + val headers = req.headers.encode val app = req.attribute.socketApp.getOrElse(Socket.empty.toSocketApp) val config = app.protocol.clientBuilder .customHeaders(headers) @@ -175,9 +175,7 @@ object Client { ) extends HeaderExtension[ClientRequest] { self => - def getBodyAsString: Task[String] = getBodyAsByteBuf.map(_.toString(getHeaders.getCharset)) - - def getHeaders: Headers = headers + def bodyAsString: Task[String] = getBodyAsByteBuf.map(_.toString(headers.charset)) def remoteAddress: Option[InetAddress] = { if (channelContext != null && channelContext.channel().remoteAddress().isInstanceOf[InetSocketAddress]) @@ -190,7 +188,7 @@ object Client { * Updates the headers using the provided function */ override def updateHeaders(update: Headers => Headers): ClientRequest = - self.copy(headers = update(self.getHeaders)) + self.copy(headers = update(self.headers)) private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = data.toByteBuf } @@ -199,13 +197,11 @@ object Client { extends HeaderExtension[ClientResponse] { self => - def getBody: Task[Chunk[Byte]] = Task(Chunk.fromArray(ByteBufUtil.getBytes(buffer))) - - def getBodyAsByteBuf: Task[ByteBuf] = Task(buffer) + def body: Task[Chunk[Byte]] = Task(Chunk.fromArray(ByteBufUtil.getBytes(buffer))) - def getBodyAsString: Task[String] = Task(buffer.toString(self.getCharset)) + def bodyAsByteBuf: Task[ByteBuf] = Task(buffer) - override def getHeaders: Headers = headers + def bodyAsString: Task[String] = Task(buffer.toString(self.charset)) override def updateHeaders(update: Headers => Headers): ClientResponse = self.copy(headers = update(headers)) } diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala index 8825ea8b41..eb96dff2ef 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala @@ -17,7 +17,7 @@ trait EncodeClientRequest { // Host and port information should be in the headers. val path = req.url.relative.encode - val encodedReqHeaders = req.getHeaders.encode + val encodedReqHeaders = req.headers.encode val headers = req.url.host match { case Some(value) => encodedReqHeaders.set(HttpHeaderNames.HOST, value) diff --git a/zio-http/src/main/scala/zhttp/service/Handler.scala b/zio-http/src/main/scala/zhttp/service/Handler.scala index 51075398d6..739e7f8e7b 100644 --- a/zio-http/src/main/scala/zhttp/service/Handler.scala +++ b/zio-http/src/main/scala/zhttp/service/Handler.scala @@ -31,9 +31,9 @@ private[zhttp] final case class Handler[R]( override def url: URL = URL.fromString(jReq.uri()).getOrElse(null) - override def getHeaders: Headers = Headers.make(jReq.headers()) + override def headers: Headers = Headers.make(jReq.headers()) - override private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = Task(jReq.content()) + override private[zhttp] def bodyAsByteBuf: Task[ByteBuf] = Task(jReq.content()) override def remoteAddress: Option[InetAddress] = { ctx.channel().remoteAddress() match { diff --git a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala index 800fcf00bb..dac6632af4 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala @@ -17,7 +17,7 @@ import scala.jdk.CollectionConverters._ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { def unsafeRun(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { - val rtm = strategy.getRuntime(ctx) + val rtm = strategy.runtime(ctx) // Close the connection if the program fails // When connection closes, interrupt the program @@ -58,7 +58,7 @@ object HttpRuntime { Strategy.sticky(group).map(runtime => new HttpRuntime[R](runtime)) sealed trait Strategy[R] { - def getRuntime(ctx: ChannelHandlerContext): Runtime[R] + def runtime(ctx: ChannelHandlerContext): Runtime[R] } object Strategy { @@ -73,7 +73,7 @@ object HttpRuntime { ZIO.runtime[R].map(runtime => Group(runtime, group)) case class Default[R](runtime: Runtime[R]) extends Strategy[R] { - override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = runtime + override def runtime(ctx: ChannelHandlerContext): Runtime[R] = runtime } case class Dedicated[R](runtime: Runtime[R], group: JEventLoopGroup) extends Strategy[R] { @@ -83,7 +83,7 @@ object HttpRuntime { } } - override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime + override def runtime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime } case class Group[R](runtime: Runtime[R], group: JEventLoopGroup) extends Strategy[R] { @@ -99,7 +99,7 @@ object HttpRuntime { map } - override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = + override def runtime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime.getOrElse(ctx.executor(), runtime) } } diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index c7144aee44..1747aeaa33 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -25,14 +25,14 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes(charset))), ) - val encoded = request.getBodyAsString + val encoded = request.bodyAsString val expected = new String(Chunk.fromArray("abc".getBytes(charset)).toArray, charset) assertM(encoded)(equalTo(expected)) } } + testM("should map bytes to default utf-8 if no charset given") { val request = Client.ClientRequest(URL(!!), data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes()))) - val encoded = request.getBodyAsString + val encoded = request.bodyAsString val expected = new String(Chunk.fromArray("abc".getBytes()).toArray, HTTP_CHARSET) assertM(encoded)(equalTo(expected)) } diff --git a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala index 87731c4375..b164c5512a 100644 --- a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala @@ -10,54 +10,54 @@ object HeaderSpec extends DefaultRunnableSpec { def spec = suite("Header") { suite("getHeader")( test("should not return header that doesn't exist in list") { - val actual = predefinedHeaders.getHeader("dummyHeaderName") + val actual = predefinedHeaders.header("dummyHeaderName") assert(actual)(isNone) } + test("should return header from predefined headers list by String") { - val actual = predefinedHeaders.getHeaderValue(HttpHeaderNames.CONTENT_TYPE) + val actual = predefinedHeaders.headerValue(HttpHeaderNames.CONTENT_TYPE) assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) } + test("should return header from predefined headers list by String of another case") { - val actual = predefinedHeaders.getHeaderValue("Content-Type") + val actual = predefinedHeaders.headerValue("Content-Type") assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) } + test("should return header from predefined headers list by AsciiString") { - val actual = predefinedHeaders.getHeaderValue(HttpHeaderNames.CONTENT_TYPE) + val actual = predefinedHeaders.headerValue(HttpHeaderNames.CONTENT_TYPE) assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) } + test("should return header from custom headers list by String") { - val actual = customHeaders.getHeader(HttpHeaderNames.CONTENT_TYPE) + val actual = customHeaders.header(HttpHeaderNames.CONTENT_TYPE) assert(actual)(isSome(equalTo(customContentJsonHeader))) } + test("should return header from custom headers list by AsciiString") { - val actual = customHeaders.getHeader(HttpHeaderNames.CONTENT_TYPE) + val actual = customHeaders.header(HttpHeaderNames.CONTENT_TYPE) assert(actual)(isSome(equalTo(customContentJsonHeader))) }, ) + suite("getHeaderValue") { test("should return header value") { - val actual = predefinedHeaders.getHeaderValue(HttpHeaderNames.CONTENT_TYPE) + val actual = predefinedHeaders.headerValue(HttpHeaderNames.CONTENT_TYPE) assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) } } + suite("getContentType")( test("should return content-type value") { - val actual = predefinedHeaders.getContentType + val actual = predefinedHeaders.contentType assert(actual)(isSome(equalTo(HttpHeaderValues.APPLICATION_JSON.toString))) } + test("should not return content-type value if it doesn't exist") { - val actual = acceptJson.getContentType + val actual = acceptJson.contentType assert(actual)(isNone) }, ) + suite("getAuthorizationHeader")( test("should return authorization value") { val authorizationValue = "dummyValue" - val actual = Headers.authorization(authorizationValue).getAuthorization + val actual = Headers.authorization(authorizationValue).authorization assert(actual)(isSome(equalTo(authorizationValue))) } + test("should not return authorization value if it doesn't exist") { - val actual = acceptJson.getContentType + val actual = acceptJson.contentType assert(actual)(isNone) }, ) + @@ -142,33 +142,33 @@ object HeaderSpec extends DefaultRunnableSpec { ) + suite("getBasicAuthorizationCredentials")( test("should decode proper basic http authorization header") { - val actual = Headers.authorization("Basic dXNlcjpwYXNzd29yZCAxMQ==").getBasicAuthorizationCredentials + val actual = Headers.authorization("Basic dXNlcjpwYXNzd29yZCAxMQ==").basicAuthorizationCredentials assert(actual)(isSome(equalTo(("user", "password 11")))) } + test("should decode basic http authorization header with empty name and password") { - val actual = Headers.authorization("Basic Og==").getBasicAuthorizationCredentials + val actual = Headers.authorization("Basic Og==").basicAuthorizationCredentials assert(actual)(isSome(equalTo(("", "")))) } + test("should not decode improper base64") { - val actual = Headers.authorization("Basic Og=").getBasicAuthorizationCredentials + val actual = Headers.authorization("Basic Og=").basicAuthorizationCredentials assert(actual)(isNone) } + test("should not decode only basic") { - val actual = Headers.authorization("Basic").getBasicAuthorizationCredentials + val actual = Headers.authorization("Basic").basicAuthorizationCredentials assert(actual)(isNone) } + test("should not decode basic contained header value") { - val actual = Headers.authorization("wrongBasic Og==").getBasicAuthorizationCredentials + val actual = Headers.authorization("wrongBasic Og==").basicAuthorizationCredentials assert(actual)(isNone) } + test("should get credentials for nonbasic schema") { - val actual = Headers.authorization("DummySchema Og==").getBasicAuthorizationCredentials + val actual = Headers.authorization("DummySchema Og==").basicAuthorizationCredentials assert(actual)(isNone) } + test("should decode header from Header.basicHttpAuthorization") { val username = "username" val password = "password" - val actual = Headers.basicAuthorizationHeader(username, password).getBasicAuthorizationCredentials + val actual = Headers.basicAuthorizationHeader(username, password).basicAuthorizationCredentials assert(actual)(isSome(equalTo((username, password)))) } + test("should decode value from Header.basicHttpAuthorization") { @@ -176,7 +176,7 @@ object HeaderSpec extends DefaultRunnableSpec { val password = "password" val actual = Headers .basicAuthorizationHeader(username, password) - .getHeaderValue(HeaderNames.authorization) + .headerValue(HeaderNames.authorization) val expected = "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" assert(actual)(isSome(equalTo(expected))) }, @@ -184,36 +184,36 @@ object HeaderSpec extends DefaultRunnableSpec { suite("getBearerToken")( test("should get bearer token") { val token = "token" - val actual = Headers.authorization(String.format("%s %s", BearerSchemeName, token)).getBearerToken + val actual = Headers.authorization(String.format("%s %s", BearerSchemeName, token)).bearerToken assert(actual)(isSome(equalTo(token))) } + test("should get empty bearer token") { - val actual = Headers.authorization(String.format("%s %s", BearerSchemeName, "")).getBearerToken + val actual = Headers.authorization(String.format("%s %s", BearerSchemeName, "")).bearerToken assert(actual)(isSome(equalTo(""))) } + test("should not get bearer token for nonbearer schema") { - val actual = Headers.authorization("DummySchema token").getBearerToken + val actual = Headers.authorization("DummySchema token").bearerToken assert(actual)(isNone) } + test("should not get bearer token for bearer contained header") { - val actual = Headers.authorization("wrongBearer token").getBearerToken + val actual = Headers.authorization("wrongBearer token").bearerToken assert(actual)(isNone) }, ) + suite("getContentLength") { testM("should get content-length") { check(Gen.anyLong) { c => - val actual = Headers.contentLength(c).getContentLength + val actual = Headers.contentLength(c).contentLength assert(actual)(isSome(equalTo(c))) } } + test("should not return content-length value if it doesn't exist") { - val actual = Headers.empty.getContentType + val actual = Headers.empty.contentType assert(actual)(isNone) } + testM("should get content-length") { check(Gen.anyChar) { c => - val actual = Headers(HttpHeaderNames.CONTENT_LENGTH, c.toString).getContentLength + val actual = Headers(HttpHeaderNames.CONTENT_LENGTH, c.toString).contentLength assert(actual)(isNone) } } diff --git a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala index c24ad0b339..47fc405dcf 100644 --- a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala @@ -10,11 +10,11 @@ object ResponseSpec extends DefaultRunnableSpec { test("Temporary redirect should produce a response with a TEMPORARY_REDIRECT") { val x = Response.redirect(location) assertTrue(x.status == Status.TEMPORARY_REDIRECT) && - assertTrue(x.getHeaderValue(HeaderNames.location).contains(location)) + assertTrue(x.headerValue(HeaderNames.location).contains(location)) } + test("Temporary redirect should produce a response with a location") { val x = Response.redirect(location) - assertTrue(x.getHeaderValue(HeaderNames.location).contains(location)) + assertTrue(x.headerValue(HeaderNames.location).contains(location)) } + test("Permanent redirect should produce a response with a PERMANENT_REDIRECT") { val x = Response.redirect(location, true) @@ -22,13 +22,13 @@ object ResponseSpec extends DefaultRunnableSpec { } + test("Permanent redirect should produce a response with a location") { val x = Response.redirect(location, true) - assertTrue(x.getHeaderValue(HeaderNames.location).contains(location)) + assertTrue(x.headerValue(HeaderNames.location).contains(location)) } } + suite("json")( test("Json should set content type to ApplicationJson") { val x = Response.json("""{"message": "Hello"}""") - assertTrue(x.getHeaderValue(HeaderNames.contentType).contains(HeaderValues.applicationJson.toString)) + assertTrue(x.headerValue(HeaderNames.contentType).contains(HeaderValues.applicationJson.toString)) }, ) + suite("toHttp")( diff --git a/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala index eb61885a9e..965efc1dc9 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala @@ -13,15 +13,15 @@ object AuthSpec extends DefaultRunnableSpec with HttpAppTestExtensions { def spec = suite("AuthSpec") { suite("basicAuth") { testM("HttpApp is accepted if the basic authentication succeeds") { - val app = (Http.ok @@ basicAuthM).getStatus + val app = (Http.ok @@ basicAuthM).status assertM(app(Request().addHeaders(basicHS)))(equalTo(Status.OK)) } + testM("Uses forbidden app if the basic authentication fails") { - val app = (Http.ok @@ basicAuthM).getStatus + val app = (Http.ok @@ basicAuthM).status assertM(app(Request().addHeaders(basicHF)))(equalTo(Status.FORBIDDEN)) } + testM("Responses should have WWW-Authentication header if Basic Auth failed") { - val app = Http.ok @@ basicAuthM getHeader "WWW-AUTHENTICATE" + val app = Http.ok @@ basicAuthM header "WWW-AUTHENTICATE" assertM(app(Request().addHeaders(basicHF)))(isSome) } } diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala index b15d2ea34e..b168596233 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala @@ -28,7 +28,7 @@ object CorsSpec extends DefaultRunnableSpec with HttpAppTestExtensions { for { res <- app(request) - } yield assert(res.getHeadersAsList)(hasSubset(expected)) && + } yield assert(res.headersAsList)(hasSubset(expected)) && assertTrue(res.status == Status.NO_CONTENT) } + testM("GET request") { @@ -48,7 +48,7 @@ object CorsSpec extends DefaultRunnableSpec with HttpAppTestExtensions { for { res <- app(request) - } yield assert(res.getHeadersAsList)(hasSubset(expected)) + } yield assert(res.headersAsList)(hasSubset(expected)) } } } diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala index dbdb078e37..4cf706171d 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala @@ -9,7 +9,7 @@ import zio.test._ object CsrfSpec extends DefaultRunnableSpec with HttpAppTestExtensions { override def spec = suite("CSRF Middlewares") { - val app = (Http.ok @@ csrfValidate("x-token")).getStatus + val app = (Http.ok @@ csrfValidate("x-token")).status val setCookie = Headers.cookie(Cookie("x-token", "secret")) val invalidXToken = Headers("x-token", "secret1") val validXToken = Headers("x-token", "secret") diff --git a/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala index 02c995bc59..c462668ff3 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala @@ -20,22 +20,22 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { suite("headers suite") { testM("addHeaders") { val middleware = addHeaders(Headers("KeyA", "ValueA") ++ Headers("KeyB", "ValueB")) - val headers = (Http.ok @@ middleware).getHeaderValues + val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) } + testM("addHeader") { val middleware = addHeader("KeyA", "ValueA") - val headers = (Http.ok @@ middleware).getHeaderValues + val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA")) } + testM("updateHeaders") { val middleware = updateHeaders(_ => Headers("KeyA", "ValueA")) - val headers = (Http.ok @@ middleware).getHeaderValues + val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA")) } + testM("removeHeader") { val middleware = removeHeader("KeyA") - val headers = (Http.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware) getHeader "KeyA" + val headers = (Http.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware) header "KeyA" assertM(headers(Request()))(isNone) } } + @@ -87,60 +87,60 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { } + testM("add headers twice") { val middleware = addHeader("KeyA", "ValueA") ++ addHeader("KeyB", "ValueB") - val headers = (Http.ok @@ middleware).getHeaderValues + val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) } + testM("add and remove header") { val middleware = addHeader("KeyA", "ValueA") ++ removeHeader("KeyA") - val program = (Http.ok @@ middleware) getHeader "KeyA" + val program = (Http.ok @@ middleware) header "KeyA" assertM(program(Request()))(isNone) } } + suite("ifRequestThenElseZIO") { testM("if the condition is true take first") { - val app = (Http.ok @@ ifRequestThenElseZIO(condM(true))(midA, midB)) getHeader "X-Custom" + val app = (Http.ok @@ ifRequestThenElseZIO(condM(true))(midA, midB)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + testM("if the condition is false take 2nd") { val app = - (Http.ok @@ ifRequestThenElseZIO(condM(false))(midA, midB)) getHeader "X-Custom" + (Http.ok @@ ifRequestThenElseZIO(condM(false))(midA, midB)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("B"))) } } + suite("ifRequestThenElse") { testM("if the condition is true take first") { - val app = Http.ok @@ ifRequestThenElse(cond(true))(midA, midB) getHeader "X-Custom" + val app = Http.ok @@ ifRequestThenElse(cond(true))(midA, midB) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + testM("if the condition is false take 2nd") { - val app = Http.ok @@ ifRequestThenElse(cond(false))(midA, midB) getHeader "X-Custom" + val app = Http.ok @@ ifRequestThenElse(cond(false))(midA, midB) header "X-Custom" assertM(app(Request()))(isSome(equalTo("B"))) } } + suite("whenRequestZIO") { testM("if the condition is true apply middleware") { - val app = (Http.ok @@ whenRequestZIO(condM(true))(midA)) getHeader "X-Custom" + val app = (Http.ok @@ whenRequestZIO(condM(true))(midA)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + testM("if the condition is false don't apply any middleware") { - val app = (Http.ok @@ whenRequestZIO(condM(false))(midA)) getHeader "X-Custom" + val app = (Http.ok @@ whenRequestZIO(condM(false))(midA)) header "X-Custom" assertM(app(Request()))(isNone) } } + suite("whenRequest") { testM("if the condition is true apple middleware") { - val app = Http.ok @@ Middleware.whenRequest(cond(true))(midA) getHeader "X-Custom" + val app = Http.ok @@ Middleware.whenRequest(cond(true))(midA) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + testM("if the condition is false don't apply the middleware") { - val app = Http.ok @@ Middleware.whenRequest(cond(false))(midA) getHeader "X-Custom" + val app = Http.ok @@ Middleware.whenRequest(cond(false))(midA) header "X-Custom" assertM(app(Request()))(isNone) } } + suite("cookie") { testM("addCookie") { val cookie = Cookie("test", "testValue") - val app = (Http.ok @@ addCookie(cookie)).getHeader("set-cookie") + val app = (Http.ok @@ addCookie(cookie)).header("set-cookie") assertM(app(Request()))( equalTo(Some(cookie.encode)), ) @@ -148,7 +148,7 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { testM("addCookieM") { val cookie = Cookie("test", "testValue") val app = - (Http.ok @@ addCookieZIO(UIO(cookie))).getHeader("set-cookie") + (Http.ok @@ addCookieZIO(UIO(cookie))).header("set-cookie") assertM(app(Request()))( equalTo(Some(cookie.encode)), ) @@ -157,11 +157,11 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { suite("signCookies") { testM("should sign cookies") { val cookie = Cookie("key", "value").withHttpOnly - val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") getHeader "set-cookie" + val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") header "set-cookie" assertM(app(Request()))(isSome(equalTo(cookie.sign("secret").encode))) } + testM("sign cookies no cookie header") { - val app = (Http.ok.addHeader("keyA", "ValueA") @@ signCookies("secret")).getHeaderValues + val app = (Http.ok.addHeader("keyA", "ValueA") @@ signCookies("secret")).headerValues assertM(app(Request()))(contains("ValueA")) } } diff --git a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala index 3e099be8c0..176140064e 100644 --- a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala +++ b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala @@ -18,7 +18,7 @@ object DynamicServer { def app: HttpApp[HttpEnv, Throwable] = Http .fromOptionFunction[Request] { case req => for { - id <- req.getHeaderValue(APP_ID) match { + id <- req.headerValue(APP_ID) match { case Some(id) => UIO(id) case None => ZIO.fail(None) } @@ -31,7 +31,7 @@ object DynamicServer { } def baseURL(scheme: Scheme): ZIO[DynamicServer, Nothing, String] = - getPort.map(port => s"${scheme.encode}://localhost:$port") + port.map(port => s"${scheme.encode}://localhost:$port") def deploy(app: HttpApp[HttpEnv, Throwable]): ZIO[DynamicServer, Nothing, String] = ZIO.accessM[DynamicServer](_.get.add(app)) @@ -39,10 +39,6 @@ object DynamicServer { def get(id: Id): ZIO[DynamicServer, Nothing, Option[HttpApp[HttpEnv, Throwable]]] = ZIO.accessM[DynamicServer](_.get.get(id)) - def getPort: ZIO[DynamicServer, Nothing, Int] = ZIO.accessM[DynamicServer](_.get.getPort) - - def getStart: ZIO[DynamicServer, Nothing, Start] = ZIO.accessM[DynamicServer](_.get.getStart) - def httpURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.HTTP) def live: ZLayer[Any, Nothing, DynamicServer] = { @@ -52,17 +48,21 @@ object DynamicServer { } yield new Live(ref, pr) }.toLayer + def port: ZIO[DynamicServer, Nothing, Int] = ZIO.accessM[DynamicServer](_.get.port) + def setStart(s: Start): ZIO[DynamicServer, Nothing, Boolean] = ZIO.accessM[DynamicServer](_.get.setStart(s)) + def start: ZIO[DynamicServer, Nothing, Start] = ZIO.accessM[DynamicServer](_.get.start) + def wsURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.WS) sealed trait Service { def add(app: HttpApp[HttpEnv, Throwable]): UIO[Id] def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] - def getPort: ZIO[Any, Nothing, Int] + def port: ZIO[Any, Nothing, Int] - def getStart: IO[Nothing, Start] + def start: IO[Nothing, Start] def setStart(n: Start): UIO[Boolean] } @@ -74,9 +74,9 @@ object DynamicServer { } yield id def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] = ref.get.map(_.get(id)) - def getPort: ZIO[Any, Nothing, Int] = getStart.map(_.port) + def port: ZIO[Any, Nothing, Int] = start.map(_.port) - def getStart: IO[Nothing, Start] = pr.await + def start: IO[Nothing, Start] = pr.await def setStart(s: Start): UIO[Boolean] = pr.complete(ZIO(s).orDie) } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpAppTestExtensions.scala b/zio-http/src/test/scala/zhttp/internal/HttpAppTestExtensions.scala index 378f1f3b38..cfbefd153d 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpAppTestExtensions.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpAppTestExtensions.scala @@ -4,16 +4,16 @@ import zhttp.http._ trait HttpAppTestExtensions { implicit class HttpAppSyntax[R, E](app: HttpApp[R, E]) { - def getHeader(name: String): Http[R, E, Request, Option[String]] = - app.map(res => res.getHeaderValue(name)) + def header(name: String): Http[R, E, Request, Option[String]] = + app.map(res => res.headerValue(name)) - def getHeaders: Http[R, E, Request, Headers] = - app.map(res => res.getHeaders) + def headerValues: Http[R, E, Request, List[String]] = + app.map(res => res.headers.toList.map(_._2.toString)) - def getHeaderValues: Http[R, E, Request, List[String]] = - app.map(res => res.getHeaders.toList.map(_._2.toString)) + def headers: Http[R, E, Request, Headers] = + app.map(res => res.headers) - def getStatus: Http[R, E, Request, Status] = + def status: Http[R, E, Request, Status] = app.map(res => res.status) } } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index b9231826bd..4624ca9729 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -59,7 +59,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => */ def deploy: HttpTestClient[Any, ClientRequest, ClientResponse] = for { - port <- Http.fromZIO(DynamicServer.getPort) + port <- Http.fromZIO(DynamicServer.port) id <- Http.fromZIO(DynamicServer.deploy(app)) response <- Http.fromFunctionZIO[Client.ClientRequest] { params => Client.request( @@ -97,7 +97,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => path: Path, ): ZIO[EventLoopGroup with ChannelFactory with DynamicServer, Throwable, Status] = { for { - port <- DynamicServer.getPort + port <- DynamicServer.port status <- Client .request( "http://localhost:%d/%s".format(port, path), diff --git a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala index 496972bed8..85ffc70174 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala @@ -17,27 +17,27 @@ object ClientSpec extends HttpRunnableSpec { def clientSpec = suite("ClientSpec") { testM("respond Ok") { - val app = Http.ok.deploy.getStatus.run() + val app = Http.ok.deploy.status.run() assertM(app)(equalTo(Status.OK)) } + testM("non empty content") { val app = Http.text("abc") - val responseContent = app.deploy.getBody.run() + val responseContent = app.deploy.body.run() assertM(responseContent)(isNonEmpty) } + testM("echo POST request content") { - val app = Http.collectZIO[Request] { case req => req.getBodyAsString.map(Response.text(_)) } - val res = app.deploy.getBodyAsString.run(method = Method.POST, content = "ZIO user") + val app = Http.collectZIO[Request] { case req => req.bodyAsString.map(Response.text(_)) } + val res = app.deploy.bodyAsString.run(method = Method.POST, content = "ZIO user") assertM(res)(equalTo("ZIO user")) } + testM("empty content") { val app = Http.empty - val responseContent = app.deploy.getBody.run() + val responseContent = app.deploy.body.run() assertM(responseContent)(isEmpty) } + testM("text content") { val app = Http.text("zio user does not exist") - val responseContent = app.deploy.getBodyAsString.run() + val responseContent = app.deploy.bodyAsString.run() assertM(responseContent)(containsString("user")) } + testM("handle connection failure") { diff --git a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala index 502c8a6c23..572608906d 100644 --- a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala @@ -18,22 +18,22 @@ object KeepAliveSpec extends HttpRunnableSpec { def keepAliveSpec = suite("KeepAlive") { suite("Http 1.1") { testM("without connection close") { - val res = app.deploy.getHeaderValue(HeaderNames.connection).run() + val res = app.deploy.headerValue(HeaderNames.connection).run() assertM(res)(isNone) } + testM("with connection close") { - val res = app.deploy.getHeaderValue(HeaderNames.connection).run(headers = connectionCloseHeader) + val res = app.deploy.headerValue(HeaderNames.connection).run(headers = connectionCloseHeader) assertM(res)(isSome(equalTo("close"))) } } + suite("Http 1.0") { testM("without keep-alive") { - val res = app.deploy.getHeaderValue(HeaderNames.connection).run(version = HttpVersion.HTTP_1_0) + val res = app.deploy.headerValue(HeaderNames.connection).run(version = HttpVersion.HTTP_1_0) assertM(res)(isSome(equalTo("close"))) } + testM("with keep-alive") { val res = app.deploy - .getHeaderValue(HeaderNames.connection) + .headerValue(HeaderNames.connection) .run(version = HttpVersion.HTTP_1_0, headers = keepAliveHeader) assertM(res)(isNone) } diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 4360a17b04..7ffe2e453b 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -41,76 +41,76 @@ object ServerSpec extends HttpRunnableSpec { def dynamicAppSpec = suite("DynamicAppSpec") { suite("success") { testM("status is 200") { - val status = Http.ok.deploy.getStatus.run() + val status = Http.ok.deploy.status.run() assertM(status)(equalTo(Status.OK)) } + testM("status is 200") { - val res = Http.text("ABC").deploy.getStatus.run() + val res = Http.text("ABC").deploy.status.run() assertM(res)(equalTo(Status.OK)) } + testM("content is set") { - val res = Http.text("ABC").deploy.getBodyAsString.run() + val res = Http.text("ABC").deploy.bodyAsString.run() assertM(res)(containsString("ABC")) } } + suite("not found") { val app = Http.empty testM("status is 404") { - val res = app.deploy.getStatus.run() + val res = app.deploy.status.run() assertM(res)(equalTo(Status.NOT_FOUND)) } + testM("header is set") { - val res = app.deploy.getHeaderValue(HeaderNames.contentLength).run() + val res = app.deploy.headerValue(HeaderNames.contentLength).run() assertM(res)(isSome(equalTo("0"))) } } + suite("error") { val app = Http.fail(new Error("SERVER_ERROR")) testM("status is 500") { - val res = app.deploy.getStatus.run() + val res = app.deploy.status.run() assertM(res)(equalTo(Status.INTERNAL_SERVER_ERROR)) } + testM("content is set") { - val res = app.deploy.getBodyAsString.run() + val res = app.deploy.bodyAsString.run() assertM(res)(containsString("SERVER_ERROR")) } + testM("header is set") { - val res = app.deploy.getHeaderValue(HeaderNames.contentLength).run() + val res = app.deploy.headerValue(HeaderNames.contentLength).run() assertM(res)(isSome(anything)) } } + suite("echo content") { val app = Http.collectZIO[Request] { case req => - req.getBodyAsString.map(text => Response.text(text)) + req.bodyAsString.map(text => Response.text(text)) } testM("status is 200") { - val res = app.deploy.getStatus.run() + val res = app.deploy.status.run() assertM(res)(equalTo(Status.OK)) } + testM("body is ok") { - val res = app.deploy.getBodyAsString.run(content = "ABC") + val res = app.deploy.bodyAsString.run(content = "ABC") assertM(res)(equalTo("ABC")) } + testM("empty string") { - val res = app.deploy.getBodyAsString.run(content = "") + val res = app.deploy.bodyAsString.run(content = "") assertM(res)(equalTo("")) } + testM("one char") { - val res = app.deploy.getBodyAsString.run(content = "1") + val res = app.deploy.bodyAsString.run(content = "1") assertM(res)(equalTo("1")) } } + suite("headers") { val app = Http.ok.addHeader("Foo", "Bar") testM("headers are set") { - val res = app.deploy.getHeaderValue("Foo").run() + val res = app.deploy.headerValue("Foo").run() assertM(res)(isSome(equalTo("Bar"))) } } + suite("response") { val app = Http.response(Response(status = Status.OK, data = HttpData.fromString("abc"))) testM("body is set") { - val res = app.deploy.getBodyAsString.run() + val res = app.deploy.bodyAsString.run() assertM(res)(equalTo("abc")) } } @@ -118,17 +118,17 @@ object ServerSpec extends HttpRunnableSpec { def requestSpec = suite("RequestSpec") { val app: HttpApp[Any, Nothing] = Http.collect[Request] { case req => - Response.text(req.getContentLength.getOrElse(-1).toString) + Response.text(req.contentLength.getOrElse(-1).toString) } testM("has content-length") { checkAllM(Gen.alphaNumericString) { string => - val res = app.deploy.getBodyAsString.run(content = string) + val res = app.deploy.bodyAsString.run(content = string) assertM(res)(equalTo(string.length.toString)) } } + testM("POST Request.getBody") { - val app = Http.collectZIO[Request] { case req => req.getBody.as(Response.ok) } - val res = app.deploy.getStatus.run(path = !!, method = Method.POST, content = "some text") + val app = Http.collectZIO[Request] { case req => req.body.as(Response.ok) } + val res = app.deploy.status.run(path = !!, method = Method.POST, content = "some text") assertM(res)(equalTo(Status.OK)) } } @@ -136,13 +136,13 @@ object ServerSpec extends HttpRunnableSpec { def responseSpec = suite("ResponseSpec") { testM("data") { checkAllM(nonEmptyContent) { case (string, data) => - val res = Http.fromData(data).deploy.getBodyAsString.run() + val res = Http.fromData(data).deploy.bodyAsString.run() assertM(res)(equalTo(string)) } } + testM("data from file") { val file = new File(getClass.getResource("/TestFile.txt").getPath) - val res = Http.fromFile(file).deploy.getBodyAsString.run() + val res = Http.fromFile(file).deploy.bodyAsString.run() assertM(res)(equalTo("abc\nfoo")) } + testM("content-type header on file response") { @@ -151,61 +151,61 @@ object ServerSpec extends HttpRunnableSpec { Http .fromFile(file) .deploy - .getHeaderValue(HeaderNames.contentType) + .headerValue(HeaderNames.contentType) .run() .map(_.getOrElse("Content type header not found.")) assertM(res)(equalTo("text/plain")) } + testM("status") { checkAllM(HttpGen.status) { case status => - val res = Http.status(status).deploy.getStatus.run() + val res = Http.status(status).deploy.status.run() assertM(res)(equalTo(status)) } } + testM("header") { checkAllM(HttpGen.header) { case header @ (name, value) => - val res = Http.ok.addHeader(header).deploy.getHeaderValue(name).run() + val res = Http.ok.addHeader(header).deploy.headerValue(name).run() assertM(res)(isSome(equalTo(value))) } } + testM("text streaming") { - val res = Http.fromStream(ZStream("a", "b", "c")).deploy.getBodyAsString.run() + val res = Http.fromStream(ZStream("a", "b", "c")).deploy.bodyAsString.run() assertM(res)(equalTo("abc")) } + testM("echo streaming") { val res = Http .collectHttp[Request] { case req => - Http.fromStream(ZStream.fromEffect(req.getBody).flattenChunks) + Http.fromStream(ZStream.fromEffect(req.body).flattenChunks) } .deploy - .getBodyAsString + .bodyAsString .run(content = "abc") assertM(res)(equalTo("abc")) } + testM("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath - val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).deploy.getBodyAsString.run() + val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).deploy.bodyAsString.run() assertM(res)(equalTo("abc\nfoo")) } + suite("html") { testM("body") { - val res = Http.html(html(body(div(id := "foo", "bar")))).deploy.getBodyAsString.run() + val res = Http.html(html(body(div(id := "foo", "bar")))).deploy.bodyAsString.run() assertM(res)(equalTo("""
bar
""")) } + testM("content-type") { val app = Http.html(html(body(div(id := "foo", "bar")))) - val res = app.deploy.getHeaderValue(HeaderNames.contentType).run() + val res = app.deploy.headerValue(HeaderNames.contentType).run() assertM(res)(isSome(equalTo(HeaderValues.textHtml.toString))) } } + suite("content-length") { suite("string") { testM("unicode text") { - val res = Http.text("äöü").deploy.getContentLength.run() + val res = Http.text("äöü").deploy.contentLength.run() assertM(res)(isSome(equalTo(6L))) } + testM("already set") { - val res = Http.text("1234567890").withContentLength(4L).deploy.getContentLength.run() + val res = Http.text("1234567890").withContentLength(4L).deploy.contentLength.run() assertM(res)(isSome(equalTo(4L))) } } @@ -216,14 +216,14 @@ object ServerSpec extends HttpRunnableSpec { val expected = (0 to size) map (_ => Status.OK) for { response <- Response.text("abc").freeze - actual <- ZIO.foreachPar(0 to size)(_ => Http.response(response).deploy.getStatus.run()) + actual <- ZIO.foreachPar(0 to size)(_ => Http.response(response).deploy.status.run()) } yield assert(actual)(equalTo(expected)) } + testM("update after cache") { val server = "ZIO-Http" for { res <- Response.text("abc").freeze - actual <- Http.response(res).withServer(server).deploy.getHeaderValue(HeaderNames.server).run() + actual <- Http.response(res).withServer(server).deploy.headerValue(HeaderNames.server).run() } yield assert(actual)(isSome(equalTo(server))) } } From 136de3e9678ec4185fbda80ad6e571bc3a33c5cd Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sun, 6 Feb 2022 02:43:25 +0100 Subject: [PATCH 72/95] Update scalafmt-core to 3.4.1 (#960) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index bf5051b45e..74518f8fc0 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.4.0 +version = 3.4.1 maxColumn = 120 align.preset = more From 2455df1afd970cd75371e55d1830727e0ce73739 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sun, 6 Feb 2022 12:37:31 +0100 Subject: [PATCH 73/95] Update scalafmt-core to 3.4.2 (#962) --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 74518f8fc0..58f5a048f4 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.4.1 +version = 3.4.2 maxColumn = 120 align.preset = more From e6925b21923c7700663ff9f0bed69cad1d2b7c42 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sun, 6 Feb 2022 17:08:28 +0530 Subject: [PATCH 74/95] Update scalafmt-core to 3.4.2 (#961) From c2ed52eb1b5edbc8e04b1a8a7aa621ce42be1c5e Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Mon, 7 Feb 2022 10:02:46 +0530 Subject: [PATCH 75/95] remove declarative API (#957) --- .../main/scala/zhttp/http/Middleware.scala | 124 +++++++----------- 1 file changed, 47 insertions(+), 77 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index 99c3038886..c6364f020b 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -13,7 +13,7 @@ import zio.{UIO, ZIO} * You can think of middlewares as a functions — * * {{{ - * type Middleware[R, E, AIn, BIn, AOut, BOut] = Http[R, E, AIn, BIn] => Http[R, E, AOut, BOut] + * type Middleware[R, E, AIn, BIn, AOut, BOut] = Http[R, E, AIn, BIn] => Http[R, E, AOut, BOut] * }}} * * The `AIn` and `BIn` type params represent the type params of the input Http. @@ -50,12 +50,16 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => */ final def andThen[R1 <: R, E1 >: E, AIn1 <: AOut, BIn1 >: BOut, AOut1, BOut1]( other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], - ): Middleware[R1, E1, AIn, BIn, AOut1, BOut1] = Middleware.AndThen(self, other) + ): Middleware[R1, E1, AIn, BIn, AOut1, BOut1] = + new Middleware[R1, E1, AIn, BIn, AOut1, BOut1] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, AIn, BIn]): Http[R2, E2, AOut1, BOut1] = + other(self(http)) + } /** * Applies middleware on Http and returns new Http. */ - final def apply[R1 <: R, E1 >: E](http: Http[R1, E1, AIn, BIn]): Http[R1, E1, AOut, BOut] = execute(http) + def apply[R1 <: R, E1 >: E](http: Http[R1, E1, AIn, BIn]): Http[R1, E1, AOut, BOut] /** * Makes the middleware resolve with a constant Middleware @@ -98,7 +102,10 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => final def flatMap[R1 <: R, E1 >: E, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0]( f: BOut => Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = - Middleware.FlatMap(self, f) + new Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, AIn0, BIn0]): Http[R2, E2, AOut0, BOut0] = + self(http).flatMap(f(_)(http)) + } /** * Flattens an Middleware of a Middleware @@ -126,7 +133,10 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => final def orElse[R1 <: R, E1, AIn0 >: AIn, BIn0 <: BIn, AOut0 <: AOut, BOut0 >: BOut]( other: Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0], ): Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] = - Middleware.OrElse(self, other) + new Middleware[R1, E1, AIn0, BIn0, AOut0, BOut0] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, AIn0, BIn0]): Http[R2, E2, AOut0, BOut0] = + self(http) <> other(http) + } /** * Race between current and other, cancels other when execution of one @@ -135,7 +145,10 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => final def race[R1 <: R, E1 >: E, AIn1 >: AIn, BIn1 <: BIn, AOut1 <: AOut, BOut1 >: BOut]( other: Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1], ): Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1] = - Middleware.Race(self, other) + new Middleware[R1, E1, AIn1, BIn1, AOut1, BOut1] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, AIn1, BIn1]): Http[R2, E2, AOut1, BOut1] = + self(http) race other(http) + } final def runAfter[R1 <: R, E1 >: E](effect: ZIO[R1, E1, Any]): Middleware[R1, E1, AIn, BIn, AOut, BOut] = self.mapZIO(bOut => effect.as(bOut)) @@ -160,12 +173,6 @@ sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => isTrue = _ => self, isFalse = _ => Middleware.identity, ) - - /** - * Applies Middleware and returns a transformed Http app - */ - private[zhttp] final def execute[R1 <: R, E1 >: E](http: Http[R1, E1, AIn, BIn]): Http[R1, E1, AOut, BOut] = - Middleware.execute(http, self) } object Middleware extends Web { @@ -193,17 +200,28 @@ object Middleware extends Web { /** * Creates a middleware which always fail with specified error */ - def fail[E](e: E): Middleware[Any, E, Nothing, Any, Any, Nothing] = Fail(e) + def fail[E](e: E): Middleware[Any, E, Nothing, Any, Any, Nothing] = + new Middleware[Any, E, Nothing, Any, Any, Nothing] { + override def apply[R1 <: Any, E1 >: E](http: Http[R1, E1, Nothing, Any]): Http[R1, E1, Any, Nothing] = + Http.fail(e) + } /** * Creates a middleware with specified http App */ - def fromHttp[R, E, A, B](http: Http[R, E, A, B]): Middleware[R, E, Nothing, Any, A, B] = Constant(http) + def fromHttp[R, E, A, B](http: Http[R, E, A, B]): Middleware[R, E, Nothing, Any, A, B] = + new Middleware[R, E, Nothing, Any, A, B] { + override def apply[R1 <: R, E1 >: E](other: Http[R1, E1, Nothing, Any]): Http[R1, E1, A, B] = http + } /** * An empty middleware that doesn't do anything */ - def identity: Middleware[Any, Nothing, Nothing, Any, Any, Nothing] = Middleware.Identity + def identity: Middleware[Any, Nothing, Nothing, Any, Any, Nothing] = + new Middleware[Any, Nothing, Nothing, Any, Any, Nothing] { + override def apply[R1 <: Any, E1 >: Nothing](http: Http[R1, E1, Nothing, Any]): Http[R1, E1, Any, Nothing] = + http.asInstanceOf[Http[R1, E1, Any, Nothing]] + } /** * Logical operator to decide which middleware to select based on the @@ -232,29 +250,6 @@ object Middleware extends Web { */ def succeed[B](b: B): Middleware[Any, Nothing, Nothing, Any, Any, B] = fromHttp(Http.succeed(b)) - private[zhttp] def execute[R, E, AIn, BIn, AOut, BOut]( - http: Http[R, E, AIn, BIn], - self: Middleware[R, E, AIn, BIn, AOut, BOut], - ): Http[R, E, AOut, BOut] = - self match { - case Identity => http.asInstanceOf[Http[R, E, AOut, BOut]] - case Constant(http) => http - case OrElse(self, other) => self.execute(http).orElse(other.execute(http)) - case Fail(error) => Http.fail(error) - case AndThen(self, other) => other.execute(self.execute(http)) - case FlatMap(self, f) => self.execute(http).flatMap(f(_).execute(http)) - case ContraMapZIO(self, f) => self.execute(http).contramapZIO(a => f(a)) - case Race(self, other) => self.execute(http) race other.execute(http) - case Intercept(incoming, outgoing) => - Http.fromOptionFunction[AOut] { a => - for { - s <- incoming(a) - b <- http(a.asInstanceOf[AIn]) - c <- outgoing(b, s) - } yield c.asInstanceOf[BOut] - } - } - final class PartialCollect[AOut](val unit: Unit) extends AnyVal { def apply[R, E, AIn, BIn, BOut]( f: PartialFunction[AOut, Middleware[R, E, AIn, BIn, AOut, BOut]], @@ -285,7 +280,16 @@ object Middleware extends Web { def apply[R1 <: R, E1 >: E, BOut]( outgoing: (B, S) => ZIO[R1, Option[E1], BOut], ): Middleware[R1, E1, A, B, A, BOut] = - Intercept(incoming, outgoing) + new Middleware[R1, E1, A, B, A, BOut] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, A, B]): Http[R2, E2, A, BOut] = + Http.fromOptionFunction[A] { a => + for { + s <- incoming(a) + b <- http(a) + c <- outgoing(b, s) + } yield c + } + } } final class PartialCodec[AOut, BIn](val unit: Unit) extends AnyVal { @@ -328,43 +332,9 @@ object Middleware extends Web { val self: Middleware[R, E, AIn, BIn, AOut, BOut], ) extends AnyVal { def apply[R1 <: R, E1 >: E](f: AOut0 => ZIO[R1, E1, AOut]): Middleware[R1, E1, AIn, BIn, AOut0, BOut] = - ContraMapZIO[R1, E1, AIn, BIn, AOut, BOut, AOut0](self, f) + new Middleware[R1, E1, AIn, BIn, AOut0, BOut] { + override def apply[R2 <: R1, E2 >: E1](http: Http[R2, E2, AIn, BIn]): Http[R2, E2, AOut0, BOut] = + self(http).contramapZIO(a => f(a)) + } } - - private final case class Fail[E](error: E) extends Middleware[Any, E, Nothing, Any, Any, Nothing] - - private final case class OrElse[R, E0, E1, AIn, BIn, AOut, BOut]( - self: Middleware[R, E0, AIn, BIn, AOut, BOut], - other: Middleware[R, E1, AIn, BIn, AOut, BOut], - ) extends Middleware[R, E1, AIn, BIn, AOut, BOut] - - private final case class Constant[R, E, AOut, BOut](http: Http[R, E, AOut, BOut]) - extends Middleware[R, E, Nothing, Any, AOut, BOut] - - private final case class Intercept[R, E, A, B, S, BOut]( - incoming: A => ZIO[R, Option[E], S], - outgoing: (B, S) => ZIO[R, Option[E], BOut], - ) extends Middleware[R, E, A, B, A, BOut] - - private final case class AndThen[R, E, A0, B0, A1, B1, A2, B2]( - self: Middleware[R, E, A0, B0, A1, B1], - other: Middleware[R, E, A1, B1, A2, B2], - ) extends Middleware[R, E, A0, B0, A2, B2] - - private final case class FlatMap[R, E, AIn, BIn, AOut, BOut, BOut0]( - self: Middleware[R, E, AIn, BIn, AOut, BOut0], - f: BOut0 => Middleware[R, E, AIn, BIn, AOut, BOut], - ) extends Middleware[R, E, AIn, BIn, AOut, BOut] - - private final case class ContraMapZIO[R, E, AIn, BIn, AOut, BOut, AOut0]( - self: Middleware[R, E, AIn, BIn, AOut, BOut], - f: AOut0 => ZIO[R, E, AOut], - ) extends Middleware[R, E, AIn, BIn, AOut0, BOut] - - private final case class Race[R, E, AIn, BIn, AOut, BOut]( - self: Middleware[R, E, AIn, BIn, AOut, BOut], - other: Middleware[R, E, AIn, BIn, AOut, BOut], - ) extends Middleware[R, E, AIn, BIn, AOut, BOut] - - private case object Identity extends Middleware[Any, Nothing, Nothing, Any, Any, Nothing] } From 88e2c7018e47c3ef00f81fdb834e184aeea14a4c Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Tue, 8 Feb 2022 02:44:07 +0100 Subject: [PATCH 76/95] Update sbt-updates to 0.6.2 (#966) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 440aa80ac0..65f155fc47 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.12") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.34") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3") -addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.1") +addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.2") addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1") addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.14.2") addSbtPlugin("ch.epfl.scala" % "sbt-scala3-migrate" % "0.5.0") From 047944fcaa026d73d9c9d6f913e52c267f7e76a2 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Tue, 8 Feb 2022 10:39:10 +0530 Subject: [PATCH 77/95] Doc: Readme (#970) * fix: readme * changed note --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b388eaf246..633683becd 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ import zhttp.service.Server object HelloWorld extends App { val app = Http.collect[Request] { - case Method.GET -> Root / "text" => Response.text("Hello World!") + case Method.GET -> !! / "text" => Response.text("Hello World!") } override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = @@ -68,7 +68,7 @@ libraryDependencies += "io.d11" %% "zhttp" % "[version]" libraryDependencies += "io.d11" %% "zhttp-test" % "[version]" % Test ``` -**NOTE:** Currently ZIO Http is compatible with `ZIO 1.x` only. The library will migrate to `ZIO 2.x` as soon as a stable release is published. +**NOTE:** ZIO Http is compatible with `ZIO 1.x` and `ZIO 2.x`. # Watch Mode From d3fa639bc7387cca6b86d51561801b2463f82d44 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 8 Feb 2022 10:57:53 +0530 Subject: [PATCH 78/95] style: rearrange methods in files (#963) --- .../src/main/scala/zhttp/http/Headers.scala | 4 +- zio-http/src/main/scala/zhttp/http/Http.scala | 64 +++++++++---------- .../src/main/scala/zhttp/http/Method.scala | 3 +- .../main/scala/zhttp/http/PathModule.scala | 4 +- .../http/headers/HeaderConstructors.scala | 2 +- 5 files changed, 38 insertions(+), 39 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index f6677aa4eb..92c9ac5eb5 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -26,10 +26,10 @@ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers override def headers: Headers = self - def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList - def modify(f: Header => Header): Headers = Headers(toChunk.map(f(_))) + def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList + override def updateHeaders(update: Headers => Headers): Headers = update(self) def when(cond: Boolean): Headers = if (cond) self else Headers.empty diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index da295eccfe..cd76c3af27 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -81,6 +81,18 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def as[C](c: C): Http[R, E, A, C] = self *> Http.succeed(c) + /** + * Extracts body + */ + final def body(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, Chunk[Byte]] = + self.bodyAsByteBuf.mapZIO(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) + + /** + * Extracts body as a string + */ + final def bodyAsString(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, String] = + self.bodyAsByteBuf.mapZIO(bytes => Task(bytes.toString(HTTP_CHARSET))) + /** * Catches all the exceptions that the http app can fail with */ @@ -115,6 +127,12 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def compose[R1 <: R, E1 >: E, A1 <: A, C1](other: Http[R1, E1, C1, A1]): Http[R1, E1, C1, B] = other andThen self + /** + * Extracts content-length from the response if available + */ + final def contentLength(implicit eb: IsResponse[B]): Http[R, E, A, Option[Long]] = + headers.map(_.contentLength) + /** * Transforms the input of the http before passing it on to the current Http */ @@ -179,24 +197,6 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => dd: Http[R1, E1, A1, B1], ): Http[R1, E1, A1, B1] = Http.FoldHttp(self, ee, bb, dd) - /** - * Extracts body - */ - final def body(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, Chunk[Byte]] = - self.bodyAsByteBuf.mapZIO(buf => Task(Chunk.fromArray(ByteBufUtil.getBytes(buf)))) - - /** - * Extracts body as a string - */ - final def bodyAsString(implicit eb: IsResponse[B], ee: E <:< Throwable): Http[R, Throwable, A, String] = - self.bodyAsByteBuf.mapZIO(bytes => Task(bytes.toString(HTTP_CHARSET))) - - /** - * Extracts content-length from the response if available - */ - final def contentLength(implicit eb: IsResponse[B]): Http[R, E, A, Option[Long]] = - headers.map(_.contentLength) - /** * Extracts the value of the provided header name. */ @@ -208,11 +208,6 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => */ final def headers(implicit eb: IsResponse[B]): Http[R, E, A, Headers] = self.map(eb.headers) - /** - * Extracts `Status` from the type `B` is possible. - */ - final def status(implicit ev: IsResponse[B]): Http[R, E, A, Status] = self.map(ev.status) - /** * Transforms the output of the http app */ @@ -292,6 +287,11 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def silent[E1 >: E, B1 >: B](implicit s: CanBeSilenced[E1, B1]): Http[R, Nothing, A, B1] = self.catchAll(e => Http.succeed(s.silent(e))) + /** + * Extracts `Status` from the type `B` is possible. + */ + final def status(implicit ev: IsResponse[B]): Http[R, E, A, Status] = self.map(ev.status) + /** * Returns an Http that peeks at the success of this Http. */ @@ -368,6 +368,15 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def zipRight[R1 <: R, E1 >: E, A1 <: A, C1](other: Http[R1, E1, A1, C1]): Http[R1, E1, A1, C1] = self.flatMap(_ => other) + /** + * Extracts body as a ByteBuf + */ + private[zhttp] final def bodyAsByteBuf(implicit + eb: IsResponse[B], + ee: E <:< Throwable, + ): Http[R, Throwable, A, ByteBuf] = + self.widen[Throwable, B].mapZIO(eb.bodyAsByteBuf) + /** * Evaluates the app and returns an HExit that can be resolved further * @@ -398,15 +407,6 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => case RunMiddleware(app, mid) => mid(app).execute(a) } - - /** - * Extracts body as a ByteBuf - */ - private[zhttp] final def bodyAsByteBuf(implicit - eb: IsResponse[B], - ee: E <:< Throwable, - ): Http[R, Throwable, A, ByteBuf] = - self.widen[Throwable, B].mapZIO(eb.bodyAsByteBuf) } object Http { diff --git a/zio-http/src/main/scala/zhttp/http/Method.scala b/zio-http/src/main/scala/zhttp/http/Method.scala index b69f6d1fc0..7c784a408e 100644 --- a/zio-http/src/main/scala/zhttp/http/Method.scala +++ b/zio-http/src/main/scala/zhttp/http/Method.scala @@ -3,8 +3,9 @@ package zhttp.http import io.netty.handler.codec.http.HttpMethod sealed trait Method { self => - override def toString(): String = Method.asHttpMethod(self).name() lazy val asHttpMethod: HttpMethod = Method.asHttpMethod(self) + + override def toString(): String = Method.asHttpMethod(self).name() } object Method { diff --git a/zio-http/src/main/scala/zhttp/http/PathModule.scala b/zio-http/src/main/scala/zhttp/http/PathModule.scala index 5dae4e1b5b..9189fc029c 100644 --- a/zio-http/src/main/scala/zhttp/http/PathModule.scala +++ b/zio-http/src/main/scala/zhttp/http/PathModule.scala @@ -3,9 +3,7 @@ package zhttp.http import scala.annotation.tailrec private[zhttp] trait PathModule { module => - val !! = Path.End - @deprecated("Use `!!` operator instead.", "23-Aug-2021") - val Root = !! + val !! : Path = Path.End sealed trait Path { self => final override def toString: String = this.encode diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala index c75c55dd12..a265d438cf 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala @@ -2,7 +2,7 @@ package zhttp.http.headers import io.netty.handler.codec.http.HttpHeaderNames import zhttp.http.Headers.BasicSchemeName -import zhttp.http.{Cookie, HTTP_CHARSET, HeaderNames, Headers, Method} +import zhttp.http._ import zio.duration.Duration import java.util.Base64 From 5e4a0cfba29aa0f55ef9b60e51c04ffdff012fd8 Mon Sep 17 00:00:00 2001 From: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Date: Tue, 8 Feb 2022 11:01:27 +0530 Subject: [PATCH 79/95] Doc: Cookie (#974) * doc: cookie * doc: cookie * cookie: changes --- docs/website/docs/v1.x/dsl/cookies/index.md | 111 +++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/docs/website/docs/v1.x/dsl/cookies/index.md b/docs/website/docs/v1.x/dsl/cookies/index.md index acfff8c574..2bf45e3d55 100644 --- a/docs/website/docs/v1.x/dsl/cookies/index.md +++ b/docs/website/docs/v1.x/dsl/cookies/index.md @@ -1 +1,110 @@ -# Work in progress \ No newline at end of file +# Cookie + +**ZIO HTTP** has special support for Cookie headers using the `Cookie` Domain to add and invalidate cookies. Adding a cookie will generate the correct [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) headers + +## Create a Cookie + +`Cookie` can be created with params `name`, `content`, `expires`, `domain`, `path`, `isSecure`, `isHttpOnly`, `maxAge`, `sameSite` and `secret` according to HTTP [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie) + +The below snippet creates a cookie `name` as `id` and `content` as `abc` with default params. +```scala + val cookie: Cookie = Cookie("id", "abc") +``` +### Update a Cookie + +- `withContent` updates the content of cookie +```scala + val newCookie = cookie.withContent("def") +``` +- `withExpiry` updates the expiration date of cookie +```scala + val newCookie = cookie.withExpiry(Instant.MAX) +``` +- `withMaxAge` updates the max-age of the cookie +```scala + val newCookie = cookie.withMaxAge(5 days) +``` +- `withDomain` updates the host to which the cookie will be sent +```scala + val newCookie = cookie.withDomain("example.com") +``` +- `withPath` updates the path of the cookie +```scala + val newCookie = cookie.withPath(!! / "cookie") +``` +- `withSecure` enables cookie only on https server +```scala + val newCookie = cookie.withSecure +``` +- `withHttpOnly` forbids JavaScript from accessing the cookie +```scala + val newCookie = cookie.withHttpOnly +``` +- `withSameSite` updates whether or not a cookie is sent with cross-origin requests +```scala + val newCookie = cookie.withSameSite(Instant.MAX) +``` + +## Reset a Cookie + +you can reset cookie params using: +- `withoutSecure` resets `isSecure` to `false` in cookie +- `withoutHttpOnly` resets `isHttpOnly` to `false` in cookie +- `withoutExpiry` resets `expires` to `None` +- `withoutDomain` resets `domain` to `None` +- `withoutPath` resets `path` to `None` +- `withoutMaxAge` resets `maxAge` to `None` +- `withoutSameSite` resets `sameSite` to `None` + +## Sign a Cookie + +The cookies can be signed with a signature: + + - Using `sign` + To sign a cookie, you can use `sign` +```scala + val cookie = Cookie("key", "hello").withMaxAge(5 days) + val app = Http.collect[Request] { case Method.GET -> !! / "cookie" => + Response.ok.addCookie(cookie.sign("secret")) + } +``` +- Using `signCookies` middleware + +To sign all the cookies in your `HttpApp`, you can use `signCookies` middleware: +```scala + private val cookie = Cookie("key", "hello").withMaxAge(5 days) + private val app = Http.collect[Request] { + case Method.GET -> !! / "cookie" => Response.ok.addCookie(cookie) + case Method.GET -> !! / "secure-cookie" => Response.ok.addCookie(cookie.withSecure) + } + + // Run it like any simple app + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app @@ signCookies("secret")).exitCode +``` + +## Adding Cookie in Response + +The cookies can be added in `Response` headers: +```scala + val cookie1: Cookie = Cookie("id", "abc") + val res = Response.ok.addCookie(cookie1) +``` +It updates the response header `Set-Cookie` as + +```Set-Cookie: =``` + +## Getting Cookie from Request + +In HTTP requests, cookies are stored in the `cookie` header. +`cookiesDecoded` can be used to get all the cookies in the request. + +```scala + private val app = Http.collect[Request] { + case req @ Method.GET -> !! / "cookie" => + Response.text(req.cookiesDecoded.mkString("")) + } +``` + + + From b538a1d7cf1af62df506074cfefdbe969a9963c1 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 8 Feb 2022 15:01:31 +0530 Subject: [PATCH 80/95] refactor: drop `CanBeSilent` type-constraint from Http (#964) * refactor: drop `CanBeSilent` type-constraint from Http * update usage of `silent` operator --- .../src/main/scala/example/CookieServerSide.scala | 2 +- example/src/main/scala/example/Endpoints.scala | 2 +- example/src/main/scala/example/FileStreaming.scala | 2 +- example/src/main/scala/example/HelloWorld.scala | 2 +- .../main/scala/example/HelloWorldWithCORS.scala | 2 +- .../scala/example/HelloWorldWithMiddlewares.scala | 2 +- .../src/main/scala/example/StreamingResponse.scala | 2 +- .../src/main/scala/zhttp/http/CanBeSilenced.scala | 14 -------------- zio-http/src/main/scala/zhttp/http/Http.scala | 14 -------------- zio-http/src/main/scala/zhttp/http/package.scala | 5 ----- 10 files changed, 7 insertions(+), 40 deletions(-) delete mode 100644 zio-http/src/main/scala/zhttp/http/CanBeSilenced.scala diff --git a/example/src/main/scala/example/CookieServerSide.scala b/example/src/main/scala/example/CookieServerSide.scala index 28a156da4c..75d376cd35 100644 --- a/example/src/main/scala/example/CookieServerSide.scala +++ b/example/src/main/scala/example/CookieServerSide.scala @@ -27,5 +27,5 @@ object CookieServerSide extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + Server.start(8090, app).exitCode } diff --git a/example/src/main/scala/example/Endpoints.scala b/example/src/main/scala/example/Endpoints.scala index 23e1dbf19e..298ffbdcb3 100644 --- a/example/src/main/scala/example/Endpoints.scala +++ b/example/src/main/scala/example/Endpoints.scala @@ -21,5 +21,5 @@ object Endpoints extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8091, (h3 ++ h2 ++ h1).silent).exitCode + Server.start(8091, (h3 ++ h2 ++ h1)).exitCode } diff --git a/example/src/main/scala/example/FileStreaming.scala b/example/src/main/scala/example/FileStreaming.scala index 26cfce2c61..e8adb1bf0b 100644 --- a/example/src/main/scala/example/FileStreaming.scala +++ b/example/src/main/scala/example/FileStreaming.scala @@ -27,5 +27,5 @@ object FileStreaming extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + Server.start(8090, app).exitCode } diff --git a/example/src/main/scala/example/HelloWorld.scala b/example/src/main/scala/example/HelloWorld.scala index fb346bec04..150c52aef9 100644 --- a/example/src/main/scala/example/HelloWorld.scala +++ b/example/src/main/scala/example/HelloWorld.scala @@ -13,5 +13,5 @@ object HelloWorld extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + Server.start(8090, app).exitCode } diff --git a/example/src/main/scala/example/HelloWorldWithCORS.scala b/example/src/main/scala/example/HelloWorldWithCORS.scala index 23d54560e8..887ec1c458 100644 --- a/example/src/main/scala/example/HelloWorldWithCORS.scala +++ b/example/src/main/scala/example/HelloWorldWithCORS.scala @@ -21,5 +21,5 @@ object HelloWorldWithCORS extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + Server.start(8090, app).exitCode } diff --git a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala index b9c83d53de..b5437baf06 100644 --- a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala +++ b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala @@ -39,5 +39,5 @@ object HelloWorldWithMiddlewares extends App { // Run it like any simple app override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, (app @@ middlewares).silent).exitCode + Server.start(8090, (app @@ middlewares)).exitCode } diff --git a/example/src/main/scala/example/StreamingResponse.scala b/example/src/main/scala/example/StreamingResponse.scala index cadc0c8c6f..c0b786aafd 100644 --- a/example/src/main/scala/example/StreamingResponse.scala +++ b/example/src/main/scala/example/StreamingResponse.scala @@ -12,7 +12,7 @@ object StreamingResponse extends App { override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app.silent).exitCode + Server.start(8090, app).exitCode } // Create a message as a Chunk[Byte] diff --git a/zio-http/src/main/scala/zhttp/http/CanBeSilenced.scala b/zio-http/src/main/scala/zhttp/http/CanBeSilenced.scala deleted file mode 100644 index 767f706ae1..0000000000 --- a/zio-http/src/main/scala/zhttp/http/CanBeSilenced.scala +++ /dev/null @@ -1,14 +0,0 @@ -package zhttp.http - -trait CanBeSilenced[-E, +A] { - def silent(e: E): A -} - -object CanBeSilenced { - implicit object SilenceHttpError extends CanBeSilenced[Throwable, Response] { - override def silent(e: Throwable): Response = e match { - case m: HttpError => m.toResponse - case m => Response.fromHttpError(HttpError.InternalServerError("Internal Server Error", Option(m))) - } - } -} diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index cd76c3af27..c5a7cd43b0 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -280,13 +280,6 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => final def race[R1 <: R, E1 >: E, A1 <: A, B1 >: B](other: Http[R1, E1, A1, B1]): Http[R1, E1, A1, B1] = Http.Race(self, other) - /** - * Converts a failing Http into a non-failing one by handling the failure and - * converting it to a result if possible. - */ - final def silent[E1 >: E, B1 >: B](implicit s: CanBeSilenced[E1, B1]): Http[R, Nothing, A, B1] = - self.catchAll(e => Http.succeed(s.silent(e))) - /** * Extracts `Status` from the type `B` is possible. */ @@ -439,13 +432,6 @@ object Http { */ def setUrl(url: URL): HttpApp[R, E] = http.contramap[Request](_.setUrl(url)) - /** - * Converts a failing Http app into a non-failing one by handling the - * failure and converting it to a result if possible. - */ - def silent[R1 <: R, E1 >: E](implicit s: CanBeSilenced[E1, Response]): HttpApp[R1, E1] = - http.catchAll(e => Http.succeed(s.silent(e))) - /** * Updates the response headers using the provided function */ diff --git a/zio-http/src/main/scala/zhttp/http/package.scala b/zio-http/src/main/scala/zhttp/http/package.scala index a3673941c6..53d84e27cb 100644 --- a/zio-http/src/main/scala/zhttp/http/package.scala +++ b/zio-http/src/main/scala/zhttp/http/package.scala @@ -10,7 +10,6 @@ package object http extends PathModule with RequestSyntax with RouteDecoderModul type UHttpApp = HttpApp[Any, Nothing] type RHttpApp[-R] = HttpApp[R, Throwable] type UHttp[-A, +B] = Http[Any, Nothing, A, B] - type SilentResponse[-E] = CanBeSilenced[E, Response] type ResponseZIO[-R, +E] = ZIO[R, E, Response] type Header = (CharSequence, CharSequence) type UMiddleware[+AIn, -BIn, -AOut, +BOut] = Middleware[Any, Nothing, AIn, BIn, AOut, BOut] @@ -20,10 +19,6 @@ package object http extends PathModule with RequestSyntax with RouteDecoderModul */ val HTTP_CHARSET: Charset = CharsetUtil.UTF_8 - object SilentResponse { - def apply[E: SilentResponse]: SilentResponse[E] = implicitly[SilentResponse[E]] - } - object HeaderNames extends headers.HeaderNames object HeaderValues extends headers.HeaderValues } From d1d917c7f52913a738ef8e4d767944d46f24f1a0 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Tue, 8 Feb 2022 15:04:08 +0530 Subject: [PATCH 81/95] Feature: add `Version` (#965) * refactor: rename `asHttpMethod` to `toJava` * refactor: add `Version` domain * style(*): apply scala fmt --- .../src/main/scala/zhttp/http/Method.scala | 3 +- .../src/main/scala/zhttp/http/Version.scala | 30 +++++++++++++++++++ .../http/headers/HeaderConstructors.scala | 2 +- .../src/main/scala/zhttp/service/Client.scala | 2 +- .../zhttp/service/EncodeClientRequest.scala | 4 +-- .../zhttp/http/EncodeClientRequestSpec.scala | 6 ++-- .../test/scala/zhttp/internal/HttpGen.scala | 3 +- .../zhttp/internal/HttpRunnableSpec.scala | 3 +- .../scala/zhttp/service/KeepAliveSpec.scala | 8 ++--- 9 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 zio-http/src/main/scala/zhttp/http/Version.scala diff --git a/zio-http/src/main/scala/zhttp/http/Method.scala b/zio-http/src/main/scala/zhttp/http/Method.scala index 7c784a408e..54a22eeb6b 100644 --- a/zio-http/src/main/scala/zhttp/http/Method.scala +++ b/zio-http/src/main/scala/zhttp/http/Method.scala @@ -3,8 +3,7 @@ package zhttp.http import io.netty.handler.codec.http.HttpMethod sealed trait Method { self => - lazy val asHttpMethod: HttpMethod = Method.asHttpMethod(self) - + lazy val toJava: HttpMethod = Method.asHttpMethod(self) override def toString(): String = Method.asHttpMethod(self).name() } diff --git a/zio-http/src/main/scala/zhttp/http/Version.scala b/zio-http/src/main/scala/zhttp/http/Version.scala new file mode 100644 index 0000000000..890ee6a43e --- /dev/null +++ b/zio-http/src/main/scala/zhttp/http/Version.scala @@ -0,0 +1,30 @@ +package zhttp.http + +import io.netty.handler.codec.http.HttpVersion + +sealed trait Version { self => + def isHttp1_0: Boolean = self == Version.Http_1_0 + + def isHttp1_1: Boolean = self == Version.Http_1_1 + + def toJava: HttpVersion = self match { + case Version.Http_1_0 => HttpVersion.HTTP_1_0 + case Version.Http_1_1 => HttpVersion.HTTP_1_1 + } +} + +object Version { + val `HTTP/1.0`: Version = Http_1_0 + val `HTTP/1.1`: Version = Http_1_1 + + def unsafeFromJava(version: HttpVersion): Version = + version match { + case HttpVersion.HTTP_1_0 => Http_1_0 + case HttpVersion.HTTP_1_1 => Http_1_1 + case _ => throw new IllegalArgumentException(s"Unsupported HTTP version: $version") + } + + case object Http_1_0 extends Version + + case object Http_1_1 extends Version +} diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala index a265d438cf..2b97b54eb1 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala @@ -54,7 +54,7 @@ trait HeaderConstructors { Headers(HeaderNames.accessControlRequestHeaders, value) final def accessControlRequestMethod(method: Method): Headers = - Headers(HeaderNames.accessControlRequestMethod, method.asHttpMethod.name()) + Headers(HeaderNames.accessControlRequestMethod, method.toJava.name()) final def age(value: CharSequence): Headers = Headers(HeaderNames.age, value) diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 8e9e02f422..de601822e9 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -169,7 +169,7 @@ object Client { method: Method = Method.GET, headers: Headers = Headers.empty, private[zhttp] val data: HttpData = HttpData.empty, - private[zhttp] val version: HttpVersion = HttpVersion.HTTP_1_1, + private[zhttp] val version: Version = Version.Http_1_1, private[zhttp] val attribute: Attribute = Attribute.empty, private val channelContext: ChannelHandlerContext = null, ) extends HeaderExtension[ClientRequest] { diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala index eb96dff2ef..c2f2ec8053 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala @@ -10,8 +10,8 @@ trait EncodeClientRequest { */ def encode(req: Client.ClientRequest): Task[FullHttpRequest] = req.getBodyAsByteBuf.map { content => - val method = req.method.asHttpMethod - val jVersion = req.version + val method = req.method.toJava + val jVersion = req.version.toJava // As per the spec, the path should contain only the relative path. // Host and port information should be in the headers. diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index e8c905a496..f534dbbe35 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -33,13 +33,13 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientRequ testM("method") { checkM(anyClientParam) { params => val req = encode(params).map(_.method()) - assertM(req)(equalTo(params.method.asHttpMethod)) + assertM(req)(equalTo(params.method.toJava)) } } + testM("method on HttpData.File") { checkM(HttpGen.clientParamsForFileHttpData()) { params => val req = encode(params).map(_.method()) - assertM(req)(equalTo(params.method.asHttpMethod)) + assertM(req)(equalTo(params.method.toJava)) } } + suite("uri") { @@ -88,7 +88,7 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientRequ testM("http version") { checkM(anyClientParam) { params => val req = encode(params).map(i => i.protocolVersion()) - assertM(req)(equalTo(params.version)) + assertM(req)(equalTo(params.version.toJava)) } } } diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 456abbb2f4..f4c4b985ff 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -1,7 +1,6 @@ package zhttp.internal import io.netty.buffer.Unpooled -import io.netty.handler.codec.http.HttpVersion import zhttp.http.Scheme.{HTTP, HTTPS, WS, WSS} import zhttp.http.URL.Location import zhttp.http._ @@ -34,7 +33,7 @@ object HttpGen { url <- urlGen headers <- Gen.listOf(headerGen).map(Headers(_)) data <- dataGen - version <- Gen.fromIterable(List(HttpVersion.HTTP_1_0, HttpVersion.HTTP_1_1)) + version <- Gen.fromIterable(List(Version.Http_1_0, Version.Http_1_1)) } yield ClientRequest(url, method, headers, data, version) def cookies: Gen[Random with Sized, Cookie] = for { diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 4624ca9729..5a225c0631 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -1,6 +1,5 @@ package zhttp.internal -import io.netty.handler.codec.http.HttpVersion import zhttp.http.URL.Location import zhttp.http._ import zhttp.internal.DynamicServer.HttpEnv @@ -32,7 +31,7 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => method: Method = Method.GET, content: String = "", headers: Headers = Headers.empty, - version: HttpVersion = HttpVersion.HTTP_1_1, + version: Version = Version.Http_1_1, ): ZIO[R, Throwable, A] = app( Client.ClientRequest( diff --git a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala index 572608906d..7dee9c3204 100644 --- a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala @@ -1,7 +1,7 @@ package zhttp.service -import io.netty.handler.codec.http.{HttpHeaderValues, HttpVersion} -import zhttp.http.{HeaderNames, Headers, Http} +import io.netty.handler.codec.http.HttpHeaderValues +import zhttp.http.{HeaderNames, Headers, Http, Version} import zhttp.internal.{DynamicServer, HttpRunnableSpec} import zhttp.service.server._ import zio.test.Assertion.{equalTo, isNone, isSome} @@ -28,13 +28,13 @@ object KeepAliveSpec extends HttpRunnableSpec { } + suite("Http 1.0") { testM("without keep-alive") { - val res = app.deploy.headerValue(HeaderNames.connection).run(version = HttpVersion.HTTP_1_0) + val res = app.deploy.headerValue(HeaderNames.connection).run(version = Version.Http_1_0) assertM(res)(isSome(equalTo("close"))) } + testM("with keep-alive") { val res = app.deploy .headerValue(HeaderNames.connection) - .run(version = HttpVersion.HTTP_1_0, headers = keepAliveHeader) + .run(version = Version.Http_1_0, headers = keepAliveHeader) assertM(res)(isNone) } } From ab96fdba55ba1bd1148a18adf8493fbf1bc884cb Mon Sep 17 00:00:00 2001 From: Dino Babu John <66246799+dinojohn@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:31:13 +0530 Subject: [PATCH 82/95] Fix: Fire response instead of error in HExit.Failure() (#980) * Bug fix: fixes #979 * Made changes to nonZIOSpec in ServerSpec to include tests for HExit.Failure() --- zio-http/src/main/scala/zhttp/service/Handler.scala | 2 +- zio-http/src/test/scala/zhttp/service/ServerSpec.scala | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/Handler.scala b/zio-http/src/main/scala/zhttp/service/Handler.scala index 739e7f8e7b..b95030bfe7 100644 --- a/zio-http/src/main/scala/zhttp/service/Handler.scala +++ b/zio-http/src/main/scala/zhttp/service/Handler.scala @@ -89,7 +89,7 @@ private[zhttp] final case class Handler[R]( } case HExit.Failure(e) => - ctx.fireChannelRead((e, jReq)): Unit + ctx.fireChannelRead((Response.fromHttpError(HttpError.InternalServerError(cause = Some(e))), jReq)): Unit case HExit.Empty => ctx.fireChannelRead((Response.status(Status.NOT_FOUND), jReq)): Unit } diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 7ffe2e453b..fa0f506fbc 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -31,9 +31,9 @@ object ServerSpec extends HttpRunnableSpec { } // Use this route to test anything that doesn't require ZIO related computations. - private val nonZIO = Http.collect[Request] { - case _ -> !! / "HExitSuccess" => Response.ok - case _ -> !! / "HExitFailure" => Response.fromHttpError(HttpError.BadRequest()) + private val nonZIO = Http.collectHttp[Request] { + case _ -> !! / "HExitSuccess" => Http.ok + case _ -> !! / "HExitFailure" => Http.fail(new RuntimeException("FAILURE")) } private val app = serve { nonZIO ++ staticApp ++ DynamicServer.app } @@ -279,10 +279,10 @@ object ServerSpec extends HttpRunnableSpec { assertM(actual)(equalTo(Status.OK)) } } + - testM("400 response") { + testM("500 response") { checkAllM(HttpGen.method) { method => val actual = status(method, !! / "HExitFailure") - assertM(actual)(equalTo(Status.BAD_REQUEST)) + assertM(actual)(equalTo(Status.INTERNAL_SERVER_ERROR)) } } + testM("404 response ") { From 9c9fd5e058d802eea393fb4bd758511f2d5b98d8 Mon Sep 17 00:00:00 2001 From: Dino Babu John <66246799+dinojohn@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:59:32 +0530 Subject: [PATCH 83/95] fix: typo in bug_report.md (#981) --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f3d5c415e0..2b02ce5e32 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,13 +11,13 @@ assignees: '' A clear and concise description of what the bug is. **To Reproduce** -Steps to reproduce the behavior: +Steps to reproduce the behaviour: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error -**Expected behavior** +**Expected behaviour** A clear and concise description of what you expected to happen. **Screenshots** From 2a73a959f26adefb181dbf3580574549ec974742 Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Wed, 9 Feb 2022 03:39:00 +0100 Subject: [PATCH 84/95] Update netty-all to 4.1.74.Final (#982) --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 9a49de38af..1d25fb875a 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -2,7 +2,7 @@ import sbt._ object Dependencies { val JwtCoreVersion = "9.0.3" - val NettyVersion = "4.1.73.Final" + val NettyVersion = "4.1.74.Final" val NettyIncubatorVersion = "0.0.12.Final" val ScalaCompactCollectionVersion = "2.6.0" val ZioVersion = "1.0.13" From 0c0fda2c6c558501fdb0b0b130dcfbfeb978052a Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 9 Feb 2022 08:24:39 +0530 Subject: [PATCH 85/95] refactor: remove sealed modifier from Middleware trait (#984) --- zio-http/src/main/scala/zhttp/http/Middleware.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index c6364f020b..32ab14bc6c 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -20,7 +20,7 @@ import zio.{UIO, ZIO} * The `AOut` and `BOut` type params represent the type params of the output * Http. */ -sealed trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => +trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => /** * Creates a new middleware that passes the output Http of the current From 4b760b4f4404dae7f88a47c1d3c2b6127511e906 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Wed, 9 Feb 2022 13:08:13 +0530 Subject: [PATCH 86/95] refactor: rename method on Client (#985) --- zio-http/src/main/scala/zhttp/service/Client.scala | 4 ++-- .../src/main/scala/zhttp/service/EncodeClientRequest.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index de601822e9..8da486c610 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -175,7 +175,7 @@ object Client { ) extends HeaderExtension[ClientRequest] { self => - def bodyAsString: Task[String] = getBodyAsByteBuf.map(_.toString(headers.charset)) + def bodyAsString: Task[String] = bodyAsByteBuf.map(_.toString(headers.charset)) def remoteAddress: Option[InetAddress] = { if (channelContext != null && channelContext.channel().remoteAddress().isInstanceOf[InetSocketAddress]) @@ -190,7 +190,7 @@ object Client { override def updateHeaders(update: Headers => Headers): ClientRequest = self.copy(headers = update(self.headers)) - private[zhttp] def getBodyAsByteBuf: Task[ByteBuf] = data.toByteBuf + private[zhttp] def bodyAsByteBuf: Task[ByteBuf] = data.toByteBuf } final case class ClientResponse(status: Status, headers: Headers, private[zhttp] val buffer: ByteBuf) diff --git a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala index c2f2ec8053..ea25cbbe9d 100644 --- a/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala +++ b/zio-http/src/main/scala/zhttp/service/EncodeClientRequest.scala @@ -9,7 +9,7 @@ trait EncodeClientRequest { * Converts client params to JFullHttpRequest */ def encode(req: Client.ClientRequest): Task[FullHttpRequest] = - req.getBodyAsByteBuf.map { content => + req.bodyAsByteBuf.map { content => val method = req.method.toJava val jVersion = req.version.toJava From 7660b9cbf81fe7b6c7f069f2a57023deaaff59c0 Mon Sep 17 00:00:00 2001 From: "John A. De Goes" Date: Thu, 13 Jan 2022 11:34:09 +0000 Subject: [PATCH 87/95] ZIO 2 support (#809) * upgrade to zio 2.0.0-RC1 * bump timeout for failing test * other fixes * increase timeout * rejigger broken test * try, try again * get compiling & tests passing Co-authored-by: Kit Langton --- .gitignore | 6 ++ README.md | 6 +- docs/index.md | 8 +- docs/website/docs/advanced-examples/cors.md | 22 +++++ .../docs/advanced-examples/sticky-threads.md | 0 .../docs/advanced-examples/stream-file.md | 0 docs/website/docs/index.md | 0 .../advanced-examples/authentication.md | 6 +- .../advanced-examples/concrete-entity.md | 19 ++-- .../advanced-examples/hello-world-advanced.md | 5 +- .../advanced-examples/stream-response.md | 9 +- .../advanced-examples/web-socket-advanced.md | 6 +- .../zio-http-basic-examples/hello-world.md | 6 +- .../zio-http-basic-examples/https-client.md | 6 +- .../zio-http-basic-examples/simple-client.md | 21 ++-- .../zio-http-basic-examples/web-socket.md | 6 +- .../zio-http-basic-examples/https-server.md | 0 .../main/scala/example/Authentication.scala | 8 +- .../src/main/scala/example/BasicAuth.scala | 8 +- example/src/main/scala/example/CSRF.scala | 8 +- .../main/scala/example/ConcreteEntity.scala | 8 +- .../main/scala/example/CookieServerSide.scala | 9 +- .../src/main/scala/example/Endpoints.scala | 6 +- .../main/scala/example/FileStreaming.scala | 10 +- .../src/main/scala/example/HelloWorld.scala | 7 +- .../scala/example/HelloWorldAdvanced.scala | 13 ++- .../scala/example/HelloWorldWithCORS.scala | 8 +- .../example/HelloWorldWithMiddlewares.scala | 13 +-- .../main/scala/example/HtmlTemplating.scala | 5 +- .../src/main/scala/example/HttpsClient.scala | 8 +- .../main/scala/example/HttpsHelloWorld.scala | 10 +- .../example/PlainTextBenchmarkServer.scala | 7 +- .../src/main/scala/example/SimpleClient.scala | 9 +- .../scala/example/StreamingResponse.scala | 15 ++- .../scala/example/WebSocketAdvanced.scala | 11 +-- .../main/scala/example/WebSocketEcho.scala | 8 +- project/Dependencies.scala | 2 +- .../zhttp.benchmarks/HttpRouteTextPerf.scala | 4 +- .../src/main/scala/zhttp/http/Cookie.scala | 2 +- .../src/main/scala/zhttp/http/HExit.scala | 2 +- zio-http/src/main/scala/zhttp/http/Http.scala | 32 +++--- .../src/main/scala/zhttp/http/HttpData.scala | 7 +- .../src/main/scala/zhttp/http/Response.scala | 2 +- .../http/headers/HeaderConstructors.scala | 2 +- .../zhttp/http/headers/HeaderModifier.scala | 3 +- .../scala/zhttp/service/ChannelFuture.scala | 6 +- .../src/main/scala/zhttp/service/Client.scala | 8 +- .../scala/zhttp/service/EventLoopGroup.scala | 2 +- .../main/scala/zhttp/service/Handler.scala | 2 +- .../scala/zhttp/service/HttpRuntime.scala | 92 ++++++++--------- .../src/main/scala/zhttp/service/Server.scala | 16 +-- .../service/client/ClientInboundHandler.scala | 4 +- .../main/scala/zhttp/service/package.scala | 7 +- .../src/main/scala/zhttp/socket/Socket.scala | 18 ++-- .../main/scala/zhttp/socket/SocketApp.scala | 24 ++--- .../scala/zhttp/socket/SocketProtocol.scala | 2 +- .../scala/zhttp/endpoint/EndpointSpec.scala | 8 +- .../src/test/scala/zhttp/html/DomSpec.scala | 6 +- .../test/scala/zhttp/http/CookieSpec.scala | 8 +- .../zhttp/http/EncodeClientParamsSpec.scala | 0 .../src/test/scala/zhttp/http/HExitSpec.scala | 3 +- .../test/scala/zhttp/http/HeaderSpec.scala | 8 +- .../test/scala/zhttp/http/HttpDataSpec.scala | 2 +- .../src/test/scala/zhttp/http/HttpSpec.scala | 34 +++---- .../test/scala/zhttp/http/StatusSpec.scala | 6 +- .../src/test/scala/zhttp/http/URLSpec.scala | 2 +- .../scala/zhttp/internal/DynamicServer.scala | 13 ++- .../test/scala/zhttp/internal/HttpGen.scala | 15 ++- .../zhttp/internal/HttpRunnableSpec.scala | 6 +- .../test/scala/zhttp/internal/package.scala | 7 -- .../zhttp/middleware/MiddlewareSpec.scala | 0 .../scala/zhttp/service/ClientHttpsSpec.scala | 26 +++-- .../test/scala/zhttp/service/ClientSpec.scala | 14 +-- .../test/scala/zhttp/service/SSLSpec.scala | 13 ++- .../test/scala/zhttp/service/ServerSpec.scala | 99 +++++++++---------- .../zhttp/service/WebSocketServerSpec.scala | 7 +- .../test/scala/zhttp/socket/SocketSpec.scala | 67 +++++++------ 77 files changed, 458 insertions(+), 420 deletions(-) create mode 100644 docs/website/docs/advanced-examples/cors.md create mode 100644 docs/website/docs/advanced-examples/sticky-threads.md create mode 100644 docs/website/docs/advanced-examples/stream-file.md create mode 100644 docs/website/docs/index.md create mode 100644 docs/website/docs/zio-http-basic-examples/https-server.md create mode 100644 zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala delete mode 100644 zio-http/src/test/scala/zhttp/internal/package.scala create mode 100644 zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala diff --git a/.gitignore b/.gitignore index 61d2cdf338..2992dbd969 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ *.ipr *.iws .idea +.bloop/ +.metals/ +null out .cache/ .history/ @@ -28,3 +31,6 @@ node_modules/ .bsp/ .DS_Store web/.DS_Store + +.vscode +project/metals.sbt \ No newline at end of file diff --git a/README.md b/README.md index 633683becd..8957ad2a84 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,13 @@ import zio._ import zhttp.http._ import zhttp.service.Server -object HelloWorld extends App { +object HelloWorld extends ZIOAppDefault { val app = Http.collect[Request] { case Method.GET -> !! / "text" => Response.text("Hello World!") } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } ``` #### Examples diff --git a/docs/index.md b/docs/index.md index e95b197c79..774cffb8a8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -89,7 +89,7 @@ object Spec extends DefaultRunnableSpec { } def spec = suite("http") ( - testM("should be ok") { + test("should be ok") { val req = ??? val expectedRes = resp => resp.status.toJHttpStatus.code() == Status.OK assertM(app(req))(expectedRes) // an apply method is added via `zhttp.test` package @@ -135,11 +135,11 @@ import zhttp.http._ import zhttp.service.Server import zio._ -object HelloWorld extends App { +object HelloWorld extends ZIOAppDefault { val app = Http.ok - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } ``` diff --git a/docs/website/docs/advanced-examples/cors.md b/docs/website/docs/advanced-examples/cors.md new file mode 100644 index 0000000000..2d28565ca2 --- /dev/null +++ b/docs/website/docs/advanced-examples/cors.md @@ -0,0 +1,22 @@ +# CORS Handling + +```scala +import zhttp.http._ +import zhttp.service.Server +import zio._ + +object HelloWorldWithCORS extends ZIOAppDefault { + // Create HTTP route with CORS enabled + val app: HttpApp[Any, Nothing] = CORS( + Http.collect[Request] { + case Method.GET -> !! / "text" => Response.text("Hello World!") + case Method.GET -> !! / "json" => Response.jsonString("""{"greetings": "Hello World!"}""") + }, + config = CORSConfig(anyOrigin = true), + ) + + // Run it like any simple app + val run = + Server.start(8090, app.silent) +} +``` \ No newline at end of file diff --git a/docs/website/docs/advanced-examples/sticky-threads.md b/docs/website/docs/advanced-examples/sticky-threads.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/advanced-examples/stream-file.md b/docs/website/docs/advanced-examples/stream-file.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/index.md b/docs/website/docs/index.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/v1.x/examples/advanced-examples/authentication.md b/docs/website/docs/v1.x/examples/advanced-examples/authentication.md index a77f3252d7..1aa65022a7 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/authentication.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/authentication.md @@ -8,7 +8,7 @@ import zio._ import java.time.Clock -object Authentication extends App { +object Authentication extends ZIOAppDefault { // Secret Authentication key val SECRET_KEY = "secretKey" @@ -56,8 +56,8 @@ object Authentication extends App { val app: UHttpApp = login ++ authenticate(Http.forbidden("Not allowed!"), user) // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md b/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md index 7e1b7f7fd9..320a407b4a 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md @@ -7,11 +7,11 @@ import zio._ /** * Example to build app on concrete entity */ -object ConcreteEntity extends App { - // Request +object ConcreteEntity extends ZIOAppDefault { + //Request case class CreateUser(name: String) - // Response + //Response case class UserCreated(id: Long) val user: Http[Any, Nothing, CreateUser, UserCreated] = @@ -19,14 +19,15 @@ object ConcreteEntity extends App { UserCreated(2) } - val app: HttpApp[Any, Nothing] = - user - .contramap[Request](req => CreateUser(req.path.toString)) // Http[Any, Nothing, Request, UserCreated] - .map(userCreated => Response.text(userCreated.id.toString)) // Http[Any, Nothing, Request, Response] + val app: Http[Any, Nothing, Request, Response[Any, Nothing]] = user + .contramap[Request](req => CreateUser(req.endpoint._2.toString)) + //Http[Any, Nothing, Request, UserCreated] + .map(userCreated => Response.text(userCreated.id.toString)) + //Http[Any, Nothing, Request, Response] // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md index a49feb9487..0af5eca4f7 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md @@ -8,7 +8,7 @@ import zio._ import scala.util.Try -object HelloWorldAdvanced extends App { +object HelloWorldAdvanced extends ZIOAppDefault { // Set a port private val PORT = 0 @@ -27,7 +27,7 @@ object HelloWorldAdvanced extends App { Server.paranoidLeakDetection ++ // Paranoid leak detection (affects performance) Server.app(fooBar ++ app) // Setup the Http app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + override val run = { // Configure thread count using CLI val nThreads: Int = args.headOption.flatMap(x => Try(x.toInt).toOption).getOrElse(0) @@ -41,7 +41,6 @@ object HelloWorldAdvanced extends App { *> ZIO.never, ) .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(nThreads)) - .exitCode } } diff --git a/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md b/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md index fd9a61919f..ed656ff1e9 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md @@ -9,13 +9,12 @@ import zio._ /** * Example to encode content using a ZStream */ -object StreamingResponse extends App { +object StreamingResponse extends ZIOAppDefault { override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) Server.start(8090, app.silent).exitCode } - // Create a message as a Chunk[Byte] val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) // Use `Http.collect` to match on route @@ -32,5 +31,11 @@ object StreamingResponse extends App { data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream ) } + val run = { + + // Starting the server (for more advanced startup + // configuration checkout `HelloWorldAdvanced`) + Server.start(8090, app.silent) + } } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md index 1d9f8131bd..b69a9e334c 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md @@ -7,7 +7,7 @@ import zio._ import zio.duration._ import zio.stream.ZStream -object WebSocketAdvanced extends App { +object WebSocketAdvanced extends ZIOAppDefault { // Message Handlers private val open = Socket.succeed(WebSocketFrame.text("Greetings!")) @@ -53,8 +53,8 @@ object WebSocketAdvanced extends App { case Method.GET -> !! / "subscriptions" => socketApp.toResponse } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md index db4645bea4..867c76f299 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md @@ -5,7 +5,7 @@ import zhttp.http._ import zhttp.service.Server import zio._ -object HelloWorld extends App { +object HelloWorld extends ZIOAppDefault { // Create HTTP route val app: HttpApp[Any, Nothing] = Http.collect[Request] { @@ -14,7 +14,7 @@ object HelloWorld extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app.silent).exitCode + val run = + Server.start(8090, app.silent) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md index 5bf84d6c48..3d818d5cc9 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md @@ -11,7 +11,7 @@ import java.io.InputStream import java.security.KeyStore import javax.net.ssl.TrustManagerFactory -object HttpsClient extends App { +object HttpsClient extends ZIOAppDefault { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "https://sports.api.decathlon.com/groups/water-aerobics" val headers = Headers.host("sports.api.decathlon.com") @@ -35,8 +35,8 @@ object HttpsClient extends App { _ <- console.putStrLn { data } } yield () - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] - = program.exitCode.provideCustomLayer(env) + override val run = + program.provideCustom(env) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md index 4df170c1be..7dadccb092 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md @@ -1,22 +1,27 @@ # Simple HTTP Client ```scala -import zhttp.http.Headers +import zhttp.http.{Header, HttpData} import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio._ -object SimpleClient extends App { +object SimpleClient extends ZIOAppDefault { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "http://sports.api.decathlon.com/groups/water-aerobics" - val headers = Headers.host("sports.api.decathlon.com") + val headers = List(Header.host("sports.api.decathlon.com")) val program = for { - res <- Client.request(url, headers) - data <- res.getBodyAsString - _ <- console.putStrLn { data } + res <- Client.request(url, headers) + _ <- console.putStrLn { + res.content match { + case HttpData.CompleteData(data) => data.map(_.toChar).mkString + case HttpData.StreamData(_) => "" + case HttpData.Empty => "" + } + } } yield () - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - program.exitCode.provideCustomLayer(env) + override val run = + program.provide(env) } ``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md index d5396923cd..1955a7cdfe 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md @@ -8,7 +8,7 @@ import zio._ import zio.duration._ import zio.stream.ZStream -object WebSocketEcho extends App { +object WebSocketEcho extends ZIOAppDefault { private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) @@ -24,8 +24,8 @@ object WebSocketEcho extends App { case Method.GET -> !! / "subscriptions" => socket.toResponse } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + override val run = + Server.start(8090, app) } ``` diff --git a/docs/website/docs/zio-http-basic-examples/https-server.md b/docs/website/docs/zio-http-basic-examples/https-server.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/example/src/main/scala/example/Authentication.scala b/example/src/main/scala/example/Authentication.scala index afd1b3619d..fb2b01d3cb 100644 --- a/example/src/main/scala/example/Authentication.scala +++ b/example/src/main/scala/example/Authentication.scala @@ -3,11 +3,11 @@ package example import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim} import zhttp.http._ import zhttp.service.Server -import zio.{App, ExitCode, URIO} +import zio._ import java.time.Clock -object Authentication extends App { +object Authentication extends ZIOAppDefault { // Secret Authentication key val SECRET_KEY = "secretKey" @@ -55,6 +55,6 @@ object Authentication extends App { val app: UHttpApp = login ++ authenticate(Http.forbidden("Not allowed!"), user) // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + override val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/BasicAuth.scala b/example/src/main/scala/example/BasicAuth.scala index 7d419b474c..583b50fc64 100644 --- a/example/src/main/scala/example/BasicAuth.scala +++ b/example/src/main/scala/example/BasicAuth.scala @@ -3,9 +3,9 @@ package example import zhttp.http.Middleware.basicAuth import zhttp.http._ import zhttp.service.Server -import zio.{App, ExitCode, URIO} +import zio._ -object BasicAuth extends App { +object BasicAuth extends ZIOAppDefault { // Http app that requires a JWT claim val user: UHttpApp = Http.collect[Request] { case Method.GET -> !! / "user" / name / "greet" => @@ -16,6 +16,6 @@ object BasicAuth extends App { val app: UHttpApp = user @@ basicAuth("admin", "admin") // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/CSRF.scala b/example/src/main/scala/example/CSRF.scala index 3edd3a7375..aa02a31ce9 100644 --- a/example/src/main/scala/example/CSRF.scala +++ b/example/src/main/scala/example/CSRF.scala @@ -5,7 +5,7 @@ import zhttp.http._ import zhttp.service.Server import zio._ -object CSRF extends App { +object CSRF extends ZIOAppDefault { val privateApp = Http.collect[Request] { case Method.GET -> !! / "unsafeEndpoint" => Response.text("secure info") } @@ csrfValidate() // Check for matching csrf header and cookie @@ -14,7 +14,7 @@ object CSRF extends App { Response.text("hello") } @@ csrfGenerate() // set x-csrf token cookie - val app = publicApp ++ privateApp - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val app = publicApp ++ privateApp + + def run = Server.start(8090, app) } diff --git a/example/src/main/scala/example/ConcreteEntity.scala b/example/src/main/scala/example/ConcreteEntity.scala index dc0a533843..fa2f04e86c 100644 --- a/example/src/main/scala/example/ConcreteEntity.scala +++ b/example/src/main/scala/example/ConcreteEntity.scala @@ -2,12 +2,12 @@ package example import zhttp.http.{Http, HttpApp, Request, Response} import zhttp.service.Server -import zio.{App, ExitCode, URIO} +import zio._ /** * Example to build app on concrete entity */ -object ConcreteEntity extends App { +object ConcreteEntity extends ZIOAppDefault { // Request case class CreateUser(name: String) @@ -25,6 +25,6 @@ object ConcreteEntity extends App { .map(userCreated => Response.text(userCreated.id.toString)) // Http[Any, Nothing, Request, Response] // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/CookieServerSide.scala b/example/src/main/scala/example/CookieServerSide.scala index 75d376cd35..a9d3848c60 100644 --- a/example/src/main/scala/example/CookieServerSide.scala +++ b/example/src/main/scala/example/CookieServerSide.scala @@ -2,13 +2,12 @@ package example import zhttp.http.{Cookie, Method, Response, _} import zhttp.service.Server -import zio.duration.durationInt -import zio.{App, ExitCode, URIO} +import zio._ /** * Example to make app using cookies */ -object CookieServerSide extends App { +object CookieServerSide extends ZIOAppDefault { // Setting cookies with an expiry of 5 days private val cookie = Cookie("key", "value").withMaxAge(5 days) @@ -26,6 +25,6 @@ object CookieServerSide extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/Endpoints.scala b/example/src/main/scala/example/Endpoints.scala index 298ffbdcb3..511feddcae 100644 --- a/example/src/main/scala/example/Endpoints.scala +++ b/example/src/main/scala/example/Endpoints.scala @@ -4,9 +4,9 @@ import zhttp.endpoint._ import zhttp.http.Method.GET import zhttp.http.Response import zhttp.service.Server -import zio.{App, ExitCode, UIO, URIO} +import zio._ -object Endpoints extends App { +object Endpoints extends ZIOAppDefault { def h1 = GET / "a" / *[Int] / "b" / *[Boolean] to { a => Response.text(a.params.toString) } @@ -20,6 +20,6 @@ object Endpoints extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + val run = Server.start(8091, (h3 ++ h2 ++ h1)).exitCode } diff --git a/example/src/main/scala/example/FileStreaming.scala b/example/src/main/scala/example/FileStreaming.scala index e8adb1bf0b..229fda401f 100644 --- a/example/src/main/scala/example/FileStreaming.scala +++ b/example/src/main/scala/example/FileStreaming.scala @@ -2,13 +2,13 @@ package example import zhttp.http._ import zhttp.service.Server +import zio._ import zio.stream.ZStream -import zio.{App, ExitCode, URIO} import java.io.File import java.nio.file.Paths -object FileStreaming extends App { +object FileStreaming extends ZIOAppDefault { // Create HTTP route val app = Http.collectHttp[Request] { @@ -16,7 +16,7 @@ object FileStreaming extends App { // Read the file as ZStream // Uses the blocking version of ZStream.fromFile - case Method.GET -> !! / "blocking" => Http.fromStream(ZStream.fromFile(Paths.get("README.md"))) + case Method.GET -> !! / "blocking" => Http.fromStream(ZStream.fromPath(Paths.get("README.md"))) // Uses netty's capability to write file content to the Channel // Content-type response headers are automatically identified and added @@ -26,6 +26,6 @@ object FileStreaming extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/HelloWorld.scala b/example/src/main/scala/example/HelloWorld.scala index 150c52aef9..147ac584d3 100644 --- a/example/src/main/scala/example/HelloWorld.scala +++ b/example/src/main/scala/example/HelloWorld.scala @@ -3,7 +3,8 @@ package example import zhttp.http._ import zhttp.service.Server import zio._ -object HelloWorld extends App { + +object HelloWorld extends ZIOAppDefault { // Create HTTP route val app: HttpApp[Any, Nothing] = Http.collect[Request] { @@ -12,6 +13,6 @@ object HelloWorld extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + override val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/HelloWorldAdvanced.scala b/example/src/main/scala/example/HelloWorldAdvanced.scala index 1615b6c4ee..ad60e187b9 100644 --- a/example/src/main/scala/example/HelloWorldAdvanced.scala +++ b/example/src/main/scala/example/HelloWorldAdvanced.scala @@ -7,7 +7,7 @@ import zio._ import scala.util.Try -object HelloWorldAdvanced extends App { +object HelloWorldAdvanced extends ZIOAppDefault { // Set a port private val PORT = 0 @@ -17,8 +17,8 @@ object HelloWorldAdvanced extends App { } private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "random" => random.nextString(10).map(Response.text(_)) - case Method.GET -> !! / "utc" => clock.currentDateTime.map(s => Response.text(s.toString)) + case Method.GET -> !! / "random" => Random.nextString(10).map(Response.text(_)) + case Method.GET -> !! / "utc" => Clock.currentDateTime.map(s => Response.text(s.toString)) } private val server = @@ -26,7 +26,7 @@ object HelloWorldAdvanced extends App { Server.paranoidLeakDetection ++ // Paranoid leak detection (affects performance) Server.app(fooBar ++ app) // Setup the Http app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + val run = ZIOAppArgs.getArgs.flatMap { args => // Configure thread count using CLI val nThreads: Int = args.headOption.flatMap(x => Try(x.toInt).toOption).getOrElse(0) @@ -34,12 +34,11 @@ object HelloWorldAdvanced extends App { server.make .use(start => // Waiting for the server to start - console.putStrLn(s"Server started on port ${start.port}") + Console.printLine(s"Server started on port ${start.port}") // Ensures the server doesn't die after printing *> ZIO.never, ) - .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(nThreads)) - .exitCode + .provideCustom(ServerChannelFactory.auto, EventLoopGroup.auto(nThreads)) } } diff --git a/example/src/main/scala/example/HelloWorldWithCORS.scala b/example/src/main/scala/example/HelloWorldWithCORS.scala index 887ec1c458..8479a0af0b 100644 --- a/example/src/main/scala/example/HelloWorldWithCORS.scala +++ b/example/src/main/scala/example/HelloWorldWithCORS.scala @@ -4,9 +4,9 @@ import zhttp.http.Middleware.cors import zhttp.http._ import zhttp.http.middleware.Cors.CorsConfig import zhttp.service.Server -import zio.{App, ExitCode, URIO} +import zio._ -object HelloWorldWithCORS extends App { +object HelloWorldWithCORS extends ZIOAppDefault { // Create CORS configuration val config: CorsConfig = @@ -20,6 +20,6 @@ object HelloWorldWithCORS extends App { } @@ cors(config) // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala index b5437baf06..4142222a92 100644 --- a/example/src/main/scala/example/HelloWorldWithMiddlewares.scala +++ b/example/src/main/scala/example/HelloWorldWithMiddlewares.scala @@ -3,15 +3,12 @@ package example import zhttp.http._ import zhttp.http.middleware.HttpMiddleware import zhttp.service.Server -import zio.clock.{Clock, currentTime} -import zio.console.Console -import zio.duration._ -import zio.{App, ExitCode, URIO, ZIO} +import zio._ import java.io.IOException import java.util.concurrent.TimeUnit -object HelloWorldWithMiddlewares extends App { +object HelloWorldWithMiddlewares extends ZIOAppDefault { val app: HttpApp[Clock, Nothing] = Http.collectZIO[Request] { // this will return result instantly @@ -22,7 +19,7 @@ object HelloWorldWithMiddlewares extends App { val serverTime: HttpMiddleware[Clock, Nothing] = Middleware.patchZIO(_ => for { - currentMilliseconds <- currentTime(TimeUnit.MILLISECONDS) + currentMilliseconds <- Clock.currentTime(TimeUnit.MILLISECONDS) withHeader = Patch.addHeader("X-Time", currentMilliseconds.toString) } yield withHeader, ) @@ -38,6 +35,6 @@ object HelloWorldWithMiddlewares extends App { serverTime // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, (app @@ middlewares)).exitCode + override val run = + Server.start(8090, (app @@ middlewares)) } diff --git a/example/src/main/scala/example/HtmlTemplating.scala b/example/src/main/scala/example/HtmlTemplating.scala index e8fe783985..b5ad7d8dda 100644 --- a/example/src/main/scala/example/HtmlTemplating.scala +++ b/example/src/main/scala/example/HtmlTemplating.scala @@ -4,7 +4,7 @@ import zhttp.http._ import zhttp.service.Server import zio._ -object HtmlTemplating extends App { +object HtmlTemplating extends ZIOAppDefault { // Importing everything from `zhttp.html` import zhttp.html._ @@ -47,6 +47,5 @@ object HtmlTemplating extends App { } } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + def run = Server.start(8090, app) } diff --git a/example/src/main/scala/example/HttpsClient.scala b/example/src/main/scala/example/HttpsClient.scala index f604987675..15e8c33303 100644 --- a/example/src/main/scala/example/HttpsClient.scala +++ b/example/src/main/scala/example/HttpsClient.scala @@ -4,13 +4,13 @@ import io.netty.handler.ssl.SslContextBuilder import zhttp.http.Headers import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.{ChannelFactory, Client, EventLoopGroup} -import zio.{App, ExitCode, URIO, console} +import zio._ import java.io.InputStream import java.security.KeyStore import javax.net.ssl.TrustManagerFactory -object HttpsClient extends App { +object HttpsClient extends ZIOAppDefault { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "https://sports.api.decathlon.com/groups/water-aerobics" val headers = Headers.host("sports.api.decathlon.com") @@ -31,9 +31,9 @@ object HttpsClient extends App { val program = for { res <- Client.request(url, headers = headers, ssl = sslOption) data <- res.bodyAsString - _ <- console.putStrLn { data } + _ <- Console.printLine(data) } yield () - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = program.exitCode.provideCustomLayer(env) + val run = program.provideCustom(env) } diff --git a/example/src/main/scala/example/HttpsHelloWorld.scala b/example/src/main/scala/example/HttpsHelloWorld.scala index f26145e763..9bb8a87b46 100644 --- a/example/src/main/scala/example/HttpsHelloWorld.scala +++ b/example/src/main/scala/example/HttpsHelloWorld.scala @@ -4,9 +4,9 @@ import zhttp.http._ import zhttp.service.server.ServerChannelFactory import zhttp.service.server.ServerSSLHandler._ import zhttp.service.{EventLoopGroup, Server} -import zio.{App, ExitCode, URIO} +import zio._ -object HttpsHelloWorld extends App { +object HttpsHelloWorld extends ZIOAppDefault { // Create HTTP route val app: HttpApp[Any, Nothing] = Http.collect[Request] { case Method.GET -> !! / "text" => Response.text("Hello World!") @@ -31,9 +31,7 @@ object HttpsHelloWorld extends App { ServerSSLOptions(sslctx, SSLHttpBehaviour.Accept), ) - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + override val run = server.make.useForever - .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(0)) - .exitCode - } + .provide(ServerChannelFactory.auto, EventLoopGroup.auto(0)) } diff --git a/example/src/main/scala/example/PlainTextBenchmarkServer.scala b/example/src/main/scala/example/PlainTextBenchmarkServer.scala index 882ea286ed..5d12cb56ca 100644 --- a/example/src/main/scala/example/PlainTextBenchmarkServer.scala +++ b/example/src/main/scala/example/PlainTextBenchmarkServer.scala @@ -4,12 +4,12 @@ import io.netty.util.AsciiString import zhttp.http._ import zhttp.service.server.ServerChannelFactory import zhttp.service.{EventLoopGroup, Server} -import zio.{App, ExitCode, UIO, URIO} +import zio._ /** * This server is used to run plaintext benchmarks on CI. */ -object Main extends App { +object Main extends ZIOAppDefault { private val message: String = "Hello, World!" @@ -21,11 +21,10 @@ object Main extends App { .withServer(STATIC_SERVER_NAME) .freeze - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { + def run = { frozenResponse .flatMap(server(_).make.useForever) .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(8)) - .exitCode } private def app(response: Response) = Http.response(response) diff --git a/example/src/main/scala/example/SimpleClient.scala b/example/src/main/scala/example/SimpleClient.scala index 6f7b7e697d..45185312b7 100644 --- a/example/src/main/scala/example/SimpleClient.scala +++ b/example/src/main/scala/example/SimpleClient.scala @@ -1,18 +1,19 @@ package example import zhttp.service.{ChannelFactory, Client, EventLoopGroup} -import zio.{App, ExitCode, URIO, console} +import zio._ -object SimpleClient extends App { +object SimpleClient extends ZIOAppDefault { val env = ChannelFactory.auto ++ EventLoopGroup.auto() val url = "http://sports.api.decathlon.com/groups/water-aerobics" val program = for { res <- Client.request(url) data <- res.bodyAsString - _ <- console.putStrLn { data } + _ <- Console.printLine(data) } yield () - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = program.exitCode.provideCustomLayer(env) + override val run = + program.provideCustom(env) } diff --git a/example/src/main/scala/example/StreamingResponse.scala b/example/src/main/scala/example/StreamingResponse.scala index c0b786aafd..3a3f28cb84 100644 --- a/example/src/main/scala/example/StreamingResponse.scala +++ b/example/src/main/scala/example/StreamingResponse.scala @@ -2,23 +2,20 @@ package example import zhttp.http._ import zhttp.service.Server +import zio._ import zio.stream.ZStream -import zio.{App, Chunk, ExitCode, URIO} /** * Example to encode content using a ZStream */ -object StreamingResponse extends App { - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { - - // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app).exitCode - } +object StreamingResponse extends ZIOAppDefault { + // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) + def run = Server.start(8090, app) // Create a message as a Chunk[Byte] - val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) + def message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) // Use `Http.collect` to match on route - val app: HttpApp[Any, Nothing] = Http.collect[Request] { + def app: HttpApp[Any, Nothing] = Http.collect[Request] { // Simple (non-stream) based route case Method.GET -> !! / "health" => Response.ok diff --git a/example/src/main/scala/example/WebSocketAdvanced.scala b/example/src/main/scala/example/WebSocketAdvanced.scala index 7682a65af3..b95a01c3e0 100644 --- a/example/src/main/scala/example/WebSocketAdvanced.scala +++ b/example/src/main/scala/example/WebSocketAdvanced.scala @@ -4,10 +4,9 @@ import zhttp.http._ import zhttp.service.Server import zhttp.socket._ import zio._ -import zio.duration._ import zio.stream.ZStream -object WebSocketAdvanced extends App { +object WebSocketAdvanced extends ZIOAppDefault { // Message Handlers private val open = Socket.succeed(WebSocketFrame.text("Greetings!")) @@ -35,10 +34,10 @@ object WebSocketAdvanced extends App { .onOpen(open) // Called after the connection is closed - .onClose(_ => console.putStrLn("Closed!").ignore) + .onClose(_ => Console.printLine("Closed!").ignore) // Called whenever there is an error on the socket channel - .onError(_ => console.putStrLn("Error!").ignore) + .onError(_ => Console.printLine("Error!").ignore) // Setup websocket decoder config .withDecoder(decoder) @@ -53,6 +52,6 @@ object WebSocketAdvanced extends App { case Method.GET -> !! / "subscriptions" => socketApp.toResponse } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + override val run = + Server.start(8090, app) } diff --git a/example/src/main/scala/example/WebSocketEcho.scala b/example/src/main/scala/example/WebSocketEcho.scala index c1cf4778bf..6c75ae5677 100644 --- a/example/src/main/scala/example/WebSocketEcho.scala +++ b/example/src/main/scala/example/WebSocketEcho.scala @@ -3,11 +3,11 @@ package example import zhttp.http._ import zhttp.service.Server import zhttp.socket.{Socket, WebSocketFrame} -import zio.duration._ +import zio._ import zio.stream.ZStream import zio.{App, ExitCode, Schedule, UIO, URIO} -object WebSocketEcho extends App { +object WebSocketEcho extends ZIOAppDefault { private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) @@ -23,6 +23,6 @@ object WebSocketEcho extends App { case Method.GET -> !! / "subscriptions" => socket.toResponse } - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = - Server.start(8090, app).exitCode + override val run = + Server.start(8090, app) } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 1d25fb875a..a42aef8ef9 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,7 +5,7 @@ object Dependencies { val NettyVersion = "4.1.74.Final" val NettyIncubatorVersion = "0.0.12.Final" val ScalaCompactCollectionVersion = "2.6.0" - val ZioVersion = "1.0.13" + val ZioVersion = "2.0.0-RC1" val SttpVersion = "3.3.18" val `jwt-core` = "com.github.jwt-scala" %% "jwt-core" % JwtCoreVersion diff --git a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala index 042d470df8..c2b26e6fec 100644 --- a/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala +++ b/zio-http-benchmarks/src/main/scala/zhttp.benchmarks/HttpRouteTextPerf.scala @@ -16,8 +16,8 @@ class HttpRouteTextPerf { private val res = Response.text("HELLO WORLD") private val app = Http.succeed(res) private val req: Request = Request(Method.GET, URL(!!)) - private val httpProgram = ZIO.foreach_(0 to 1000) { _ => app.execute(req).toZIO } - private val UIOProgram = ZIO.foreach_(0 to 1000) { _ => UIO(res) } + private val httpProgram = ZIO.foreachDiscard(0 to 1000) { _ => app.execute(req).toZIO } + private val UIOProgram = ZIO.foreachDiscard(0 to 1000) { _ => UIO(res) } @Benchmark def benchmarkHttpProgram(): Unit = { diff --git a/zio-http/src/main/scala/zhttp/http/Cookie.scala b/zio-http/src/main/scala/zhttp/http/Cookie.scala index 4d7dc61b42..8388313bbb 100644 --- a/zio-http/src/main/scala/zhttp/http/Cookie.scala +++ b/zio-http/src/main/scala/zhttp/http/Cookie.scala @@ -1,6 +1,6 @@ package zhttp.http -import zio.duration._ +import zio._ import java.security.MessageDigest import java.time.Instant diff --git a/zio-http/src/main/scala/zhttp/http/HExit.scala b/zio-http/src/main/scala/zhttp/http/HExit.scala index 811066a449..23ad8c69d6 100644 --- a/zio-http/src/main/scala/zhttp/http/HExit.scala +++ b/zio-http/src/main/scala/zhttp/http/HExit.scala @@ -44,7 +44,7 @@ private[zhttp] sealed trait HExit[-R, +E, +A] { self => case HExit.Failure(e) => ee(e) case HExit.Effect(zio) => Effect( - zio.foldM( + zio.foldZIO( { case Some(error) => ee(error).toZIO case None => dd.toZIO diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index c5a7cd43b0..b0c137bcd8 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -6,8 +6,6 @@ import zhttp.html.Html import zhttp.http.headers.HeaderModifier import zhttp.service.{Handler, HttpRuntime, Server} import zio._ -import zio.clock.Clock -import zio.duration.Duration import zio.stream.ZStream import java.nio.charset.Charset @@ -241,13 +239,13 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Provides the environment to Http. */ - final def provide(r: R)(implicit ev: NeedsEnv[R]): Http[Any, E, A, B] = - Http.fromOptionFunction[A](a => self(a).provide(r)) + final def provideEnvironment(r: ZEnvironment[R])(implicit ev: NeedsEnv[R]): Http[Any, E, A, B] = + Http.fromOptionFunction[A](a => self(a).provideEnvironment(r)) /** * Provide part of the environment to HTTP that is not part of ZEnv */ - final def provideCustomLayer[E1 >: E, R1 <: Has[_]]( + final def provideCustomLayer[E1 >: E, R1]( layer: ZLayer[ZEnv, E1, R1], )(implicit ev: ZEnv with R1 <:< R, tagged: Tag[R1]): Http[ZEnv, E1, A, B] = Http.fromOptionFunction[A](a => self(a).provideCustomLayer(layer.mapError(Option(_)))) @@ -255,21 +253,23 @@ sealed trait Http[-R, +E, -A, +B] extends (A => ZIO[R, Option[E], B]) { self => /** * Provides layer to Http. */ - final def provideLayer[E1 >: E, R0, R1]( - layer: ZLayer[R0, E1, R1], - )(implicit ev1: R1 <:< R, ev2: NeedsEnv[R]): Http[R0, E1, A, B] = + final def provideLayer[E1 >: E, R0]( + layer: ZLayer[R0, E1, R], + )(implicit ev2: NeedsEnv[R]): Http[R0, E1, A, B] = Http.fromOptionFunction[A](a => self(a).provideLayer(layer.mapError(Option(_)))) /** * Provides some of the environment to Http. */ - final def provideSome[R1 <: R](r: R1 => R)(implicit ev: NeedsEnv[R]): Http[R1, E, A, B] = - Http.fromOptionFunction[A](a => self(a).provideSome(r)) + final def provideSomeEnvironment[R1](r: ZEnvironment[R1] => ZEnvironment[R])(implicit + ev: NeedsEnv[R], + ): Http[R1, E, A, B] = + Http.fromOptionFunction[A](a => self(a).provideSomeEnvironment(r)) /** * Provides some of the environment to Http leaving the remainder `R0`. */ - final def provideSomeLayer[R0 <: Has[_], R1 <: Has[_], E1 >: E]( + final def provideSomeLayer[R0, R1, E1 >: E]( layer: ZLayer[R0, E1, R1], )(implicit ev: R0 with R1 <:< R, tagged: Tag[R1]): Http[R0, E1, A, B] = Http.fromOptionFunction[A](a => self(a).provideSomeLayer(layer.mapError(Option(_)))) @@ -551,14 +551,20 @@ object Http { * ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, String], charset: Charset = HTTP_CHARSET): HttpApp[R, Nothing] = - Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r), charset)))).flatten + Http + .fromZIO( + ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r), charset))), + ) + .flatten /** * Creates a Http that always succeeds with a 200 status code and the provided * ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, Byte]): HttpApp[R, Nothing] = - Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provide(r))))).flatten + Http + .fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r))))) + .flatten /** * Converts a ZIO to an Http type diff --git a/zio-http/src/main/scala/zhttp/http/HttpData.scala b/zio-http/src/main/scala/zhttp/http/HttpData.scala index 6820426526..becc3ab02d 100644 --- a/zio-http/src/main/scala/zhttp/http/HttpData.scala +++ b/zio-http/src/main/scala/zhttp/http/HttpData.scala @@ -1,9 +1,8 @@ package zhttp.http import io.netty.buffer.{ByteBuf, Unpooled} -import zio.blocking.Blocking.Service.live.effectBlocking +import zio._ import zio.stream.ZStream -import zio.{Chunk, Task, UIO} import java.nio.charset.Charset import java.nio.file.Files @@ -38,9 +37,9 @@ sealed trait HttpData { self => case HttpData.BinaryStream(stream) => stream .asInstanceOf[ZStream[Any, Throwable, ByteBuf]] - .fold(Unpooled.compositeBuffer())((c, b) => c.addComponent(b)) + .runFold(Unpooled.compositeBuffer())((c, b) => c.addComponent(b)) case HttpData.File(file) => - effectBlocking { + ZIO.attemptBlocking { val fileContent = Files.readAllBytes(file.toPath) Unpooled.copiedBuffer(fileContent) } diff --git a/zio-http/src/main/scala/zhttp/http/Response.scala b/zio-http/src/main/scala/zhttp/http/Response.scala index d400ac7275..1a729859b5 100644 --- a/zio-http/src/main/scala/zhttp/http/Response.scala +++ b/zio-http/src/main/scala/zhttp/http/Response.scala @@ -151,7 +151,7 @@ object Response { Status.SWITCHING_PROTOCOLS, Headers.empty, HttpData.empty, - Attribute(socketApp = Option(app.provide(env))), + Attribute(socketApp = Option(app.provideEnvironment(env))), ) } diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala index 2b97b54eb1..9dc1096ef5 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderConstructors.scala @@ -3,8 +3,8 @@ package zhttp.http.headers import io.netty.handler.codec.http.HttpHeaderNames import zhttp.http.Headers.BasicSchemeName import zhttp.http._ -import zio.duration.Duration +import java.time.Duration import java.util.Base64 /** diff --git a/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala b/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala index fecf4336c8..bfcb06de4d 100644 --- a/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala +++ b/zio-http/src/main/scala/zhttp/http/headers/HeaderModifier.scala @@ -1,7 +1,8 @@ package zhttp.http.headers import zhttp.http.{Cookie, Header, Headers, Method} -import zio.duration.Duration + +import java.time.Duration /** * Maintains a list of operators that modify the current Headers. Once modified, diff --git a/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala b/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala index 20d9be940a..cfdefdf6ea 100644 --- a/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala +++ b/zio-http/src/main/scala/zhttp/service/ChannelFuture.scala @@ -16,7 +16,7 @@ final class ChannelFuture[A] private (jFuture: Future[A]) { def execute: Task[Option[A]] = { var handler: GenericFutureListener[Future[A]] = { _ => {} } ZIO - .effectAsync[Any, Throwable, Option[A]](cb => { + .async[Any, Throwable, Option[A]](cb => { handler = _ => { jFuture.cause() match { case null => cb(Task(Option(jFuture.get))) @@ -30,7 +30,7 @@ final class ChannelFuture[A] private (jFuture: Future[A]) { } def toManaged: ZManaged[Any, Throwable, Option[A]] = { - execute.toManaged(_ => cancel(true)) + execute.toManagedWith(_ => cancel(true)) } // Cancels the future @@ -42,5 +42,5 @@ object ChannelFuture { def unit[A](jFuture: => Future[A]): Task[Unit] = make(jFuture).flatMap(_.execute.unit) - def asManaged[A](jFuture: => Future[A]): TaskManaged[Unit] = make(jFuture).toManaged_.flatMap(_.toManaged.unit) + def asManaged[A](jFuture: => Future[A]): TaskManaged[Unit] = make(jFuture).toManaged.flatMap(_.toManaged.unit) } diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 8da486c610..65466a3b1c 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -125,10 +125,10 @@ final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el } object Client { - def make[R]: ZIO[R with EventLoopGroup with ChannelFactory, Nothing, Client[R]] = for { - cf <- ZIO.service[JChannelFactory[Channel]] - el <- ZIO.service[JEventLoopGroup] - zx <- HttpRuntime.default[R] + def make: ZIO[EventLoopGroup with ChannelFactory, Nothing, Client] = for { + cf <- ZIO.service[ChannelFactory] + el <- ZIO.service[EventLoopGroup] + zx <- HttpRuntime.default[Any] } yield service.Client(zx, cf, el) def request( diff --git a/zio-http/src/main/scala/zhttp/service/EventLoopGroup.scala b/zio-http/src/main/scala/zhttp/service/EventLoopGroup.scala index d0a78fcdd0..2bf70892b5 100644 --- a/zio-http/src/main/scala/zhttp/service/EventLoopGroup.scala +++ b/zio-http/src/main/scala/zhttp/service/EventLoopGroup.scala @@ -30,7 +30,7 @@ object EventLoopGroup { make(UIO(new channel.nio.NioEventLoopGroup(nThreads, executor))) def make(eventLoopGroup: UIO[channel.EventLoopGroup]): ZManaged[Any, Nothing, channel.EventLoopGroup] = - eventLoopGroup.toManaged(ev => ChannelFuture.unit(ev.shutdownGracefully).orDie) + eventLoopGroup.toManagedWith(ev => ChannelFuture.unit(ev.shutdownGracefully).orDie) def epoll(nThreads: Int): ZManaged[Any, Nothing, channel.EventLoopGroup] = make(UIO(new channel.epoll.EpollEventLoopGroup(nThreads))) diff --git a/zio-http/src/main/scala/zhttp/service/Handler.scala b/zio-http/src/main/scala/zhttp/service/Handler.scala index b95030bfe7..e29af8c899 100644 --- a/zio-http/src/main/scala/zhttp/service/Handler.scala +++ b/zio-http/src/main/scala/zhttp/service/Handler.scala @@ -56,7 +56,7 @@ private[zhttp] final case class Handler[R]( http.execute(a) match { case HExit.Effect(resM) => unsafeRunZIO { - resM.foldM( + resM.foldZIO( { case Some(cause) => UIO { diff --git a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala index dac6632af4..2a7729cb32 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala @@ -1,9 +1,8 @@ package zhttp.service import io.netty.channel.{ChannelHandlerContext, EventLoopGroup => JEventLoopGroup} -import io.netty.util.concurrent.{EventExecutor, Future, GenericFutureListener} -import zio._ -import zio.internal.Executor +import io.netty.util.concurrent.{EventExecutor, Future} +import zio.{Executor, Exit, Runtime, URIO, ZIO} import scala.collection.mutable import scala.concurrent.{ExecutionContext => JExecutionContext} @@ -15,23 +14,16 @@ import scala.jdk.CollectionConverters._ * channel closes. */ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { - def unsafeRun(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { - - val rtm = strategy.runtime(ctx) - - // Close the connection if the program fails - // When connection closes, interrupt the program + def unsafeRun(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { + val rtm = strategy.getRuntime(ctx) rtm - .unsafeRunAsync(for { + .unsafeRunAsyncWith(for { fiber <- program.fork - close <- UIO { - val close = closeListener(rtm, fiber) - ctx.channel().closeFuture.addListener(close) - close + _ <- ZIO.attempt { + ctx.channel().closeFuture.addListener((_: Future[_ <: Void]) => rtm.unsafeRunAsync(fiber.interrupt): Unit) } _ <- fiber.join - _ <- UIO(ctx.channel().closeFuture().removeListener(close)) } yield ()) { case Exit.Success(_) => () case Exit.Failure(cause) => @@ -39,59 +31,53 @@ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { case None => () case Some(_) => System.err.println(cause.prettyPrint) } - if (ctx.channel().isOpen) ctx.close() + ctx.close() + } + } + + def unsafeRunUninterruptible(ctx: ChannelHandlerContext)(program: ZIO[R, Throwable, Any]): Unit = { + val rtm = strategy.getRuntime(ctx) + rtm + .unsafeRunAsyncWith(program) { + case Exit.Success(_) => () + case Exit.Failure(cause) => + cause.failureOption match { + case None => () + case Some(_) => System.err.println(cause.prettyPrint) + } + ctx.close() } } - private def closeListener(rtm: Runtime[Any], fiber: Fiber.Runtime[_, _]): GenericFutureListener[Future[_ >: Void]] = - (_: Future[_ >: Void]) => rtm.unsafeRunAsync_(fiber.interrupt): Unit } object HttpRuntime { - def dedicated[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = - Strategy.dedicated(group).map(runtime => new HttpRuntime[R](runtime)) - - def default[R]: URIO[R, HttpRuntime[R]] = - Strategy.default().map(runtime => new HttpRuntime[R](runtime)) - - def sticky[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = - Strategy.sticky(group).map(runtime => new HttpRuntime[R](runtime)) - sealed trait Strategy[R] { - def runtime(ctx: ChannelHandlerContext): Runtime[R] + def getRuntime(ctx: ChannelHandlerContext): Runtime[R] } object Strategy { - def dedicated[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Dedicated(runtime, group)) - - def default[R](): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Default(runtime)) - - def sticky[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = - ZIO.runtime[R].map(runtime => Group(runtime, group)) - case class Default[R](runtime: Runtime[R]) extends Strategy[R] { - override def runtime(ctx: ChannelHandlerContext): Runtime[R] = runtime + override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = runtime } case class Dedicated[R](runtime: Runtime[R], group: JEventLoopGroup) extends Strategy[R] { - private val localRuntime: Runtime[R] = runtime.withYieldOnStart(false).withExecutor { - Executor.fromExecutionContext(runtime.platform.executor.yieldOpCount) { + private val localRuntime: Runtime[R] = runtime.withExecutor { + Executor.fromExecutionContext(runtime.runtimeConfig.executor.yieldOpCount) { JExecutionContext.fromExecutor(group) } } - override def runtime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime + override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime } case class Group[R](runtime: Runtime[R], group: JEventLoopGroup) extends Strategy[R] { private val localRuntime: mutable.Map[EventExecutor, Runtime[R]] = { val map = mutable.Map.empty[EventExecutor, Runtime[R]] for (exe <- group.asScala) - map += exe -> runtime.withYieldOnStart(false).withExecutor { - Executor.fromExecutionContext(runtime.platform.executor.yieldOpCount) { + map += exe -> runtime.withExecutor { + Executor.fromExecutionContext(runtime.runtimeConfig.executor.yieldOpCount) { JExecutionContext.fromExecutor(exe) } } @@ -99,8 +85,26 @@ object HttpRuntime { map } - override def runtime(ctx: ChannelHandlerContext): Runtime[R] = + override def getRuntime(ctx: ChannelHandlerContext): Runtime[R] = localRuntime.getOrElse(ctx.executor(), runtime) } + + def sticky[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Group(runtime, group)) + + def default[R](): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Default(runtime)) + + def dedicated[R](group: JEventLoopGroup): ZIO[R, Nothing, Strategy[R]] = + ZIO.runtime[R].map(runtime => Dedicated(runtime, group)) } + + def sticky[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = + Strategy.sticky(group).map(runtime => new HttpRuntime[R](runtime)) + + def dedicated[R](group: JEventLoopGroup): URIO[R, HttpRuntime[R]] = + Strategy.dedicated(group).map(runtime => new HttpRuntime[R](runtime)) + + def default[R]: URIO[R, HttpRuntime[R]] = + Strategy.default().map(runtime => new HttpRuntime[R](runtime)) } diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index f833043979..a2fe45a2b8 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -178,7 +178,7 @@ object Server { /** * Launches the app on the provided port. */ - def start[R <: Has[_]]( + def start[R]( port: Int, http: HttpApp[R, Throwable], ): ZIO[R, Throwable, Nothing] = { @@ -190,7 +190,7 @@ object Server { .provideSomeLayer[R](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) } - def start[R <: Has[_]]( + def start[R]( address: InetAddress, port: Int, http: HttpApp[R, Throwable], @@ -201,7 +201,7 @@ object Server { .useForever .provideSomeLayer[R](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) - def start[R <: Has[_]]( + def start[R]( socketAddress: InetSocketAddress, http: HttpApp[R, Throwable], ): ZIO[R, Throwable, Nothing] = @@ -216,16 +216,16 @@ object Server { ): ZManaged[R with EventLoopGroup with ServerChannelFactory, Throwable, Start] = { val settings = server.settings() for { - channelFactory <- ZManaged.access[ServerChannelFactory](_.get) - eventLoopGroup <- ZManaged.access[EventLoopGroup](_.get) - zExec <- HttpRuntime.sticky[R](eventLoopGroup).toManaged_ + channelFactory <- ZManaged.service[ServerChannelFactory] + eventLoopGroup <- ZManaged.service[EventLoopGroup] + zExec <- HttpRuntime.sticky[R](eventLoopGroup).toManaged reqHandler = settings.app.compile(zExec, settings) respHandler = ServerResponseHandler(zExec, settings, ServerTimeGenerator.make) init = ServerChannelInitializer(zExec, settings, reqHandler, respHandler) serverBootstrap = new ServerBootstrap().channelFactory(channelFactory).group(eventLoopGroup) - chf <- ZManaged.effect(serverBootstrap.childHandler(init).bind(settings.address)) + chf <- ZManaged.attempt(serverBootstrap.childHandler(init).bind(settings.address)) _ <- ChannelFuture.asManaged(chf) - port <- ZManaged.effect(chf.channel().localAddress().asInstanceOf[InetSocketAddress].getPort) + port <- ZManaged.attempt(chf.channel().localAddress().asInstanceOf[InetSocketAddress].getPort) } yield { ResourceLeakDetector.setLevel(settings.leakDetectionLevel.jResourceLeakDetectionLevel) Start(port) diff --git a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala index 52da0915b9..10f218e8b0 100644 --- a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala @@ -4,7 +4,7 @@ import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler} import io.netty.handler.codec.http.{FullHttpRequest, FullHttpResponse} import zhttp.service.Client.ClientResponse import zhttp.service.HttpRuntime -import zio.Promise +import zio._ /** * Handles HTTP response @@ -36,7 +36,7 @@ final class ClientInboundHandler[R]( } override def exceptionCaught(ctx: ChannelHandlerContext, error: Throwable): Unit = { - zExec.unsafeRun(ctx)(promise.fail(error)) + zExec.unsafeRunUninterruptible(ctx)(promise.fail(error)) releaseRequest() } diff --git a/zio-http/src/main/scala/zhttp/service/package.scala b/zio-http/src/main/scala/zhttp/service/package.scala index fe03605b89..45c119aad5 100644 --- a/zio-http/src/main/scala/zhttp/service/package.scala +++ b/zio-http/src/main/scala/zhttp/service/package.scala @@ -1,7 +1,6 @@ package zhttp import io.netty.channel.{Channel, ChannelFactory => JChannelFactory, EventLoopGroup => JEventLoopGroup, ServerChannel} -import zio.Has package object service { private[service] val AUTO_RELEASE_REQUEST = false @@ -21,8 +20,8 @@ package object service { private[service] val CLIENT_INBOUND_HANDLER = "CLIENT_INBOUND_HANDLER" private[service] val WEB_SOCKET_CLIENT_PROTOCOL_HANDLER = "WEB_SOCKET_CLIENT_PROTOCOL_HANDLER" - type ChannelFactory = Has[JChannelFactory[Channel]] - type EventLoopGroup = Has[JEventLoopGroup] - type ServerChannelFactory = Has[JChannelFactory[ServerChannel]] + type ChannelFactory = JChannelFactory[Channel] + type EventLoopGroup = JEventLoopGroup + type ServerChannelFactory = JChannelFactory[ServerChannel] type UServer = Server[Any, Nothing] } diff --git a/zio-http/src/main/scala/zhttp/socket/Socket.scala b/zio-http/src/main/scala/zhttp/socket/Socket.scala index 5215fa6d3f..00e79a6fc6 100644 --- a/zio-http/src/main/scala/zhttp/socket/Socket.scala +++ b/zio-http/src/main/scala/zhttp/socket/Socket.scala @@ -3,7 +3,7 @@ package zhttp.socket import zhttp.http.{Http, Response} import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zio.stream.ZStream -import zio.{Cause, NeedsEnv, ZIO} +import zio.{Cause, NeedsEnv, ZEnvironment, ZIO} sealed trait Socket[-R, +E, -A, +B] { self => import Socket._ @@ -11,18 +11,18 @@ sealed trait Socket[-R, +E, -A, +B] { self => self orElse other def apply(a: A): ZStream[R, E, B] = self match { - case End => ZStream.halt(Cause.empty) + case End => ZStream.failCause(Cause.empty) case FromStreamingFunction(func) => func(a) case FromStream(s) => s case FMap(m, bc) => m(a).map(bc) - case FMapZIO(m, bc) => m(a).mapM(bc) + case FMapZIO(m, bc) => m(a).mapZIO(bc) case FCMap(m, xa) => m(xa(a)) - case FCMapZIO(m, xa) => ZStream.fromEffect(xa(a)).flatMap(a => m(a)) + case FCMapZIO(m, xa) => ZStream.fromZIO(xa(a)).flatMap(a => m(a)) case FOrElse(sa, sb) => sa(a) <> sb(a) case FMerge(sa, sb) => sa(a) merge sb(a) case Succeed(a) => ZStream.succeed(a) - case Provide(s, r) => s(a).asInstanceOf[ZStream[R, E, B]].provide(r.asInstanceOf[R]) - case Empty => ZStream.empty + case Provide(s, r) => s(a).asInstanceOf[ZStream[R, E, B]].provideEnvironment(r.asInstanceOf[ZEnvironment[R]]) + case Empty => ZStream.empty } def connect(url: String)(implicit @@ -49,7 +49,7 @@ sealed trait Socket[-R, +E, -A, +B] { self => * dependency on R. This operation assumes that your socket requires an * environment. */ - def provide(r: R)(implicit env: NeedsEnv[R]): Socket[Any, E, A, B] = Provide(self, r) + def provideEnvironment(r: ZEnvironment[R])(implicit env: NeedsEnv[R]): Socket[Any, E, A, B] = Provide(self, r) /** * Converts the Socket into an Http @@ -83,7 +83,7 @@ object Socket { */ def empty: Socket[Any, Nothing, Any, Nothing] = Socket.Empty - def end: ZStream[Any, Nothing, Nothing] = ZStream.halt(Cause.empty) + def end: ZStream[Any, Nothing, Nothing] = ZStream.failCause(Cause.empty) def fromFunction[A]: PartialFromFunction[A] = new PartialFromFunction[A](()) @@ -123,7 +123,7 @@ object Socket { private final case class FMerge[R, E, A, B](a: Socket[R, E, A, B], b: Socket[R, E, A, B]) extends Socket[R, E, A, B] - private final case class Provide[R, E, A, B](s: Socket[R, E, A, B], r: R) extends Socket[Any, E, A, B] + private final case class Provide[R, E, A, B](s: Socket[R, E, A, B], r: ZEnvironment[R]) extends Socket[Any, E, A, B] private case object End extends Socket[Any, Nothing, Any, Nothing] diff --git a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala index ca365aefe2..bb65b4bbf5 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketApp.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketApp.scala @@ -4,8 +4,8 @@ import zhttp.http.Response import zhttp.service.{ChannelFactory, Client, EventLoopGroup} import zhttp.socket.SocketApp.Handle.{WithEffect, WithSocket} import zhttp.socket.SocketApp.{Connection, Handle} +import zio._ import zio.stream.ZStream -import zio.{NeedsEnv, ZIO} import java.net.SocketAddress @@ -82,13 +82,13 @@ final case class SocketApp[-R]( * Provides the socket app with its required environment, which eliminates its * dependency on `R`. */ - def provide(env: R)(implicit ev: NeedsEnv[R]): SocketApp[Any] = + def provideEnvironment(env: ZEnvironment[R])(implicit ev: NeedsEnv[R]): SocketApp[Any] = self.copy( - timeout = self.timeout.map(_.provide(env)), - open = self.open.map(_.provide(env)), - message = self.message.map(_.provide(env)), - error = self.error.map(f => (t: Throwable) => f(t).provide(env)), - close = self.close.map(f => (c: Connection) => f(c).provide(env)), + timeout = self.timeout.map(_.provideEnvironment(env)), + open = self.open.map(_.provideEnvironment(env)), + message = self.message.map(_.provideEnvironment(env)), + error = self.error.map(f => (t: Throwable) => f(t).provideEnvironment(env)), + close = self.close.map(f => (c: Connection) => f(c).provideEnvironment(env)), ) /** @@ -96,7 +96,7 @@ final case class SocketApp[-R]( */ def toResponse: ZIO[R, Nothing, Response] = ZIO.environment[R].flatMap { env => - Response.fromSocketApp(self.provide(env)) + Response.fromSocketApp(self.provideEnvironment(env)) } /** @@ -134,14 +134,14 @@ object SocketApp { } } - def provide(r: R)(implicit ev: NeedsEnv[R]): Handle[Any] = + def provideEnvironment(r: ZEnvironment[R])(implicit ev: NeedsEnv[R]): Handle[Any] = self match { - case WithEffect(f) => WithEffect(c => f(c).provide(r)) - case WithSocket(s) => WithSocket(s.provide(r)) + case WithEffect(f) => WithEffect(c => f(c).provideEnvironment(r)) + case WithSocket(s) => WithSocket(s.provideEnvironment(r)) } private def sock: Handle[R] = self match { - case WithEffect(f) => WithSocket(Socket.fromFunction(c => ZStream.fromEffect(f(c)) *> ZStream.empty)) + case WithEffect(f) => WithSocket(Socket.fromFunction(c => ZStream.fromZIO(f(c)) *> ZStream.empty)) case s @ WithSocket(_) => s } } diff --git a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala index a5706048fd..52d5d9e4e2 100644 --- a/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala +++ b/zio-http/src/main/scala/zhttp/socket/SocketProtocol.scala @@ -5,7 +5,7 @@ import io.netty.handler.codec.http.websocketx.{ WebSocketCloseStatus, WebSocketServerProtocolConfig, } -import zio.duration.Duration +import zio.Duration /** * Server side websocket configuration diff --git a/zio-http/src/test/scala/zhttp/endpoint/EndpointSpec.scala b/zio-http/src/test/scala/zhttp/endpoint/EndpointSpec.scala index 96fed95900..cc6f32491c 100644 --- a/zio-http/src/test/scala/zhttp/endpoint/EndpointSpec.scala +++ b/zio-http/src/test/scala/zhttp/endpoint/EndpointSpec.scala @@ -65,19 +65,19 @@ object EndpointSpec extends DefaultRunnableSpec { } } + suite("to") { - testM("endpoint doesn't match") { + test("endpoint doesn't match") { val app = Method.GET / "a" to { _ => Response.ok } assertM(app(Request(url = URL(!! / "b"))).flip)(isNone) } + - testM("endpoint with effect doesn't match") { + test("endpoint with effect doesn't match") { val app = Method.GET / "a" to { _ => UIO(Response.ok) } assertM(app(Request(url = URL(!! / "b"))).flip)(isNone) } + - testM("endpoint matches") { + test("endpoint matches") { val app = Method.GET / "a" to { _ => Response.ok } assertM(app(Request(url = URL(!! / "a"))).map(_.status))(equalTo(Status.OK)) } + - testM("endpoint with effect matches") { + test("endpoint with effect matches") { val app = Method.GET / "a" to { _ => UIO(Response.ok) } assertM(app(Request(url = URL(!! / "a"))).map(_.status))(equalTo(Status.OK)) } diff --git a/zio-http/src/test/scala/zhttp/html/DomSpec.scala b/zio-http/src/test/scala/zhttp/html/DomSpec.scala index b6df33d8fe..f4ac9aa85b 100644 --- a/zio-http/src/test/scala/zhttp/html/DomSpec.scala +++ b/zio-http/src/test/scala/zhttp/html/DomSpec.scala @@ -1,6 +1,6 @@ package zhttp.html -import zio.random.Random +import zio.Random import zio.test.{DefaultRunnableSpec, Gen, assertTrue, checkAll} object DomSpec extends DefaultRunnableSpec { @@ -73,13 +73,13 @@ object DomSpec extends DefaultRunnableSpec { val tagGen: Gen[Random, String] = Gen.stringBounded(1, 5)(Gen.alphaChar).filterNot(Element.voidElementNames.contains) - testM("void") { + test("void") { checkAll(voidTagGen) { name => val dom = Dom.element(name) assertTrue(dom.encode == s"<${name}/>") } } + - testM("not void") { + test("not void") { checkAll(tagGen) { name => val dom = Dom.element(name) assertTrue(dom.encode == s"<${name}>") diff --git a/zio-http/src/test/scala/zhttp/http/CookieSpec.scala b/zio-http/src/test/scala/zhttp/http/CookieSpec.scala index e073c90b6c..84b3a87b6c 100644 --- a/zio-http/src/test/scala/zhttp/http/CookieSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/CookieSpec.scala @@ -7,7 +7,7 @@ import zio.test._ object CookieSpec extends DefaultRunnableSpec { def spec = suite("Cookies") { suite("response cookies") { - testM("encode/decode signed/unsigned cookies with secret") { + test("encode/decode signed/unsigned cookies with secret") { checkAll(HttpGen.cookies) { cookie => val cookieString = cookie.encode assert(Cookie.decodeResponseCookie(cookieString, cookie.secret))(isSome(equalTo(cookie))) && @@ -16,10 +16,10 @@ object CookieSpec extends DefaultRunnableSpec { } } + suite("request cookies") { - testM("encode/decode multiple cookies with ZIO Test Gen") { + test("encode/decode multiple cookies with ZIO Test Gen") { checkAll(for { - name <- Gen.anyString - content <- Gen.anyString + name <- Gen.string + content <- Gen.string cookieList <- Gen.listOf(Gen.const(Cookie(name, content))) cookieString <- Gen.const(cookieList.map(x => s"${x.name}=${x.content}").mkString(";")) } yield (cookieList, cookieString)) { case (cookies, message) => diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientParamsSpec.scala new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zio-http/src/test/scala/zhttp/http/HExitSpec.scala b/zio-http/src/test/scala/zhttp/http/HExitSpec.scala index b4aa6502bb..868c97625d 100644 --- a/zio-http/src/test/scala/zhttp/http/HExitSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HExitSpec.scala @@ -1,10 +1,9 @@ package zhttp.http -import zio.UIO -import zio.duration._ import zio.test.Assertion._ import zio.test.TestAspect._ import zio.test._ +import zio.{UIO, durationInt} object HExitSpec extends DefaultRunnableSpec with HExitAssertion { def spec: ZSpec[Environment, Failure] = { diff --git a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala index b164c5512a..2fc7d6cc2a 100644 --- a/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HeaderSpec.scala @@ -201,8 +201,8 @@ object HeaderSpec extends DefaultRunnableSpec { }, ) + suite("getContentLength") { - testM("should get content-length") { - check(Gen.anyLong) { c => + test("should get content-length") { + check(Gen.long) { c => val actual = Headers.contentLength(c).contentLength assert(actual)(isSome(equalTo(c))) } @@ -211,8 +211,8 @@ object HeaderSpec extends DefaultRunnableSpec { val actual = Headers.empty.contentType assert(actual)(isNone) } + - testM("should get content-length") { - check(Gen.anyChar) { c => + test("should get content-length") { + check(Gen.char) { c => val actual = Headers(HttpHeaderNames.CONTENT_LENGTH, c.toString).contentLength assert(actual)(isNone) } diff --git a/zio-http/src/test/scala/zhttp/http/HttpDataSpec.scala b/zio-http/src/test/scala/zhttp/http/HttpDataSpec.scala index 44da146fe6..89f3b382dd 100644 --- a/zio-http/src/test/scala/zhttp/http/HttpDataSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HttpDataSpec.scala @@ -8,7 +8,7 @@ import java.io.File object HttpDataSpec extends DefaultRunnableSpec { // TODO : Add tests for othe HttpData types override def spec = - suite("HttpDataSpec")(suite("Test toByteBuf")(testM("HttpData.fromFile") { + suite("HttpDataSpec")(suite("Test toByteBuf")(test("HttpData.fromFile") { val file = new File(getClass.getResource("/TestFile.txt").getPath) val res = HttpData.fromFile(file).toByteBuf.map(_.toString(HTTP_CHARSET)) assertM(res)(equalTo("abc\nfoo")) diff --git a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala index 7fcaa2fd48..6528d57d35 100644 --- a/zio-http/src/test/scala/zhttp/http/HttpSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/HttpSpec.scala @@ -1,11 +1,9 @@ package zhttp.http import zio._ -import zio.duration.durationInt import zio.test.Assertion._ import zio.test.TestAspect.timeout import zio.test._ -import zio.test.environment.TestClock object HttpSpec extends DefaultRunnableSpec with HExitAssertion { def spec = suite("Http")( @@ -92,12 +90,12 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("asEffect")( - testM("should resolve") { + test("should resolve") { val a = Http.collect[Int] { case 1 => "A" } val actual = a.execute(1).toZIO assertM(actual)(equalTo("A")) } + - testM("should complete") { + test("should complete") { val a = Http.collect[Int] { case 1 => "A" } val actual = a.execute(2).toZIO.either assertM(actual)(isLeft(isNone)) @@ -142,7 +140,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tap")( - testM("taps the successs") { + test("taps the successs") { for { r <- Ref.make(0) app = Http.succeed(1).tap(v => Http.fromZIO(r.set(v))) @@ -152,7 +150,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tapM")( - testM("taps the successs") { + test("taps the successs") { for { r <- Ref.make(0) app = Http.succeed(1).tapZIO(r.set) @@ -162,7 +160,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tapError")( - testM("taps the error") { + test("taps the error") { for { r <- Ref.make(0) app = Http.fail(1).tapError(v => Http.fromZIO(r.set(v))) @@ -172,7 +170,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tapErrorM")( - testM("taps the error") { + test("taps the error") { for { r <- Ref.make(0) app = Http.fail(1).tapErrorZIO(r.set) @@ -182,7 +180,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tapAll")( - testM("taps the success") { + test("taps the success") { for { r <- Ref.make(0) app = (Http.succeed(1): Http[Any, Any, Any, Int]) @@ -191,7 +189,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { res <- r.get } yield assert(res)(equalTo(1)) } + - testM("taps the failure") { + test("taps the failure") { for { r <- Ref.make(0) app = (Http.fail(1): Http[Any, Int, Any, Any]) @@ -200,7 +198,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { res <- r.get } yield assert(res)(equalTo(1)) } + - testM("taps the empty") { + test("taps the empty") { for { r <- Ref.make(0) app = (Http.empty: Http[Any, Any, Any, Any]) @@ -211,7 +209,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("tapAllM")( - testM("taps the success") { + test("taps the success") { for { r <- Ref.make(0) app = (Http.succeed(1): Http[Any, Any, Any, Int]).tapAllZIO(_ => ZIO.unit, r.set, ZIO.unit) @@ -219,7 +217,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { res <- r.get } yield assert(res)(equalTo(1)) } + - testM("taps the failure") { + test("taps the failure") { for { r <- Ref.make(0) app = (Http.fail(1): Http[Any, Int, Any, Any]).tapAllZIO(r.set, _ => ZIO.unit, ZIO.unit) @@ -227,7 +225,7 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { res <- r.get } yield assert(res)(equalTo(1)) } + - testM("taps the empty") { + test("taps the empty") { for { r <- Ref.make(0) app = (Http.empty: Http[Any, Any, Any, Any]) @@ -238,19 +236,19 @@ object HttpSpec extends DefaultRunnableSpec with HExitAssertion { }, ) + suite("race") { - testM("left wins") { + test("left wins") { val http = Http.succeed(1) race Http.succeed(2) assertM(http(()))(equalTo(1)) } + - testM("sync right wins") { + test("sync right wins") { val http = Http.fromZIO(UIO(1)) race Http.succeed(2) assertM(http(()))(equalTo(2)) } + - testM("sync left wins") { + test("sync left wins") { val http = Http.succeed(1) race Http.fromZIO(UIO(2)) assertM(http(()))(equalTo(1)) } + - testM("async fast wins") { + test("async fast wins") { val http = Http.succeed(1).delay(1 second) race Http.succeed(2).delay(2 second) val program = http(()) <& TestClock.adjust(5 second) assertM(program)(equalTo(1)) diff --git a/zio-http/src/test/scala/zhttp/http/StatusSpec.scala b/zio-http/src/test/scala/zhttp/http/StatusSpec.scala index 820e897a3f..ca5d68d688 100644 --- a/zio-http/src/test/scala/zhttp/http/StatusSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/StatusSpec.scala @@ -14,7 +14,7 @@ object StatusSpec extends DefaultRunnableSpec { def toResponseSpec = suite("toResponse")( - testM("status") { + test("status") { checkAll(statusGen) { case status => assert(status.toResponse.status)(equalTo(status)) } @@ -23,8 +23,8 @@ object StatusSpec extends DefaultRunnableSpec { def toAppSpec = { suite("toApp")( - testM("status") { - checkAllM(statusGen) { case status => + test("status") { + checkAll(statusGen) { case status => val res = status.toApp(Request()) assertM(res.map(_.status))(equalTo(status)) } diff --git a/zio-http/src/test/scala/zhttp/http/URLSpec.scala b/zio-http/src/test/scala/zhttp/http/URLSpec.scala index 4dcd71c1c6..67ed8bc79a 100644 --- a/zio-http/src/test/scala/zhttp/http/URLSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/URLSpec.scala @@ -50,7 +50,7 @@ object URLSpec extends DefaultRunnableSpec { assert(URL.fromString(url).map(_.encode))(isRight(equalTo(url))) suite("asString")( - testM("using gen") { + test("using gen") { checkAll(HttpGen.url) { case url => val source = url.encode val decoded = URL.fromString(source).map(_.encode) diff --git a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala index 176140064e..8aeaa7a4a5 100644 --- a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala +++ b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala @@ -3,12 +3,17 @@ package zhttp.internal import zhttp.http._ import zhttp.service.Server.Start import zio._ -import zio.blocking.Blocking -import zio.console.Console import java.util.UUID -object DynamicServer { +sealed trait DynamicServer { + def add(app: HttpApp[DynamicServer.HttpEnv, Throwable]): UIO[DynamicServer.Id] + def get(id: DynamicServer.Id): UIO[Option[HttpApp[DynamicServer.HttpEnv, Throwable]]] + def setStart(n: Start): UIO[Boolean] + def getStart: IO[Nothing, Start] + def getPort: ZIO[Any, Nothing, Int] +} +object DynamicServer { type Id = String type HttpEnv = DynamicServer with Console with Blocking @@ -37,7 +42,7 @@ object DynamicServer { ZIO.accessM[DynamicServer](_.get.add(app)) def get(id: Id): ZIO[DynamicServer, Nothing, Option[HttpApp[HttpEnv, Throwable]]] = - ZIO.accessM[DynamicServer](_.get.get(id)) + ZIO.serviceWithZIO[DynamicServer](_.get(id)) def httpURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.HTTP) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index f4c4b985ff..7d120ce211 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -5,17 +5,16 @@ import zhttp.http.Scheme.{HTTP, HTTPS, WS, WSS} import zhttp.http.URL.Location import zhttp.http._ import zhttp.service.Client.ClientRequest -import zio.random.Random +import zio._ import zio.stream.ZStream import zio.test.{Gen, Sized} -import zio.{Chunk, ZIO} import java.io.File object HttpGen { def clientParamsForFileHttpData(): Gen[Random with Sized, ClientRequest] = { for { - file <- Gen.fromEffect(ZIO.succeed(new File(getClass.getResource("/TestFile.txt").getPath))) + file <- Gen.fromZIO(ZIO.succeed(new File(getClass.getResource("/TestFile.txt").getPath))) method <- HttpGen.method url <- HttpGen.url headers <- Gen.listOf(HttpGen.header).map(Headers(_)) @@ -37,14 +36,14 @@ object HttpGen { } yield ClientRequest(url, method, headers, data, version) def cookies: Gen[Random with Sized, Cookie] = for { - name <- Gen.anyString - content <- Gen.anyString - expires <- Gen.option(Gen.anyInstant) - domain <- Gen.option(Gen.anyString) + name <- Gen.string + content <- Gen.string + expires <- Gen.option(Gen.instant) + domain <- Gen.option(Gen.string) path <- Gen.option(path) secure <- Gen.boolean httpOnly <- Gen.boolean - maxAge <- Gen.option(Gen.anyLong) + maxAge <- Gen.option(Gen.long) sameSite <- Gen.option(Gen.fromIterable(List(Cookie.SameSite.Strict, Cookie.SameSite.Lax))) secret <- Gen.option(Gen.anyString) } yield Cookie(name, content, expires, domain, path, secure, httpOnly, maxAge, sameSite, secret) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala index 5a225c0631..78a8fc258a 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpRunnableSpec.scala @@ -8,8 +8,8 @@ import zhttp.service.Client.{ClientRequest, ClientResponse} import zhttp.service._ import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.socket.SocketApp +import zio._ import zio.test.DefaultRunnableSpec -import zio.{Has, ZIO, ZManaged} /** * Should be used only when e2e tests needs to be written. Typically we would @@ -83,12 +83,12 @@ abstract class HttpRunnableSpec extends DefaultRunnableSpec { self => } yield response } - def serve[R <: Has[_]]( + def serve[R]( app: HttpApp[R, Throwable], ): ZManaged[R with EventLoopGroup with ServerChannelFactory with DynamicServer, Nothing, Unit] = for { start <- Server.make(Server.app(app) ++ Server.port(0) ++ Server.paranoidLeakDetection).orDie - _ <- DynamicServer.setStart(start).toManaged_ + _ <- DynamicServer.setStart(start).toManaged } yield () def status( diff --git a/zio-http/src/test/scala/zhttp/internal/package.scala b/zio-http/src/test/scala/zhttp/internal/package.scala deleted file mode 100644 index 2fee682449..0000000000 --- a/zio-http/src/test/scala/zhttp/internal/package.scala +++ /dev/null @@ -1,7 +0,0 @@ -package zhttp - -import zio.Has - -package object internal { - type DynamicServer = Has[DynamicServer.Service] -} diff --git a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala new file mode 100644 index 0000000000..e69de29bb2 diff --git a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala index 103d12e511..3d3882a97c 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala @@ -4,7 +4,7 @@ import io.netty.handler.codec.DecoderException import io.netty.handler.ssl.SslContextBuilder import zhttp.http.Status import zhttp.service.client.ClientSSLHandler.ClientSSLOptions -import zio.duration.durationInt +import zio.durationInt import zio.test.Assertion.{anything, equalTo, fails, isSubtype} import zio.test.TestAspect.{ignore, timeout} import zio.test.{DefaultRunnableSpec, assertM} @@ -28,16 +28,26 @@ object ClientHttpsSpec extends DefaultRunnableSpec { val sslOption: ClientSSLOptions = ClientSSLOptions.CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) - override def spec = suite("Https Client request") { - testM("respond Ok") { - val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics") - assertM(actual)(anything) + + override def spec = suite("Https Client request") { + test("should throw DecoderException for handshake failure") { + val actual = Client + .request( + "https://untrusted-root.badssl.com/", + sslOption, + ) + .exit + assertM(actual)(fails(isSubtype[DecoderException](anything))) } + - testM("respond Ok with sslOption") { + test("respond Ok") { + val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics") + assertM(actual)(anything) + } + + test("respond Ok with sslOption") { val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics", ssl = sslOption) assertM(actual)(anything) } + - testM("should respond as Bad Request") { + test("should respond as Bad Request") { val actual = Client .request( "https://www.whatissslcertificate.com/google-has-made-the-list-of-untrusted-providers-of-digital-certificates/", @@ -55,5 +65,5 @@ object ClientHttpsSpec extends DefaultRunnableSpec { .run assertM(actual)(fails(isSubtype[DecoderException](anything))) } - }.provideCustomLayer(env) @@ timeout(30 seconds) @@ ignore + }.provideCustomLayerShared(env) @@ timeout(30 seconds) @@ ignore } diff --git a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala index 85ffc70174..f81d4b3d88 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala @@ -3,7 +3,7 @@ package zhttp.service import zhttp.http._ import zhttp.internal.{DynamicServer, HttpRunnableSpec} import zhttp.service.server._ -import zio.duration.durationInt +import zio._ import zio.test.Assertion._ import zio.test.TestAspect.{sequential, timeout} import zio.test._ @@ -16,26 +16,26 @@ object ClientSpec extends HttpRunnableSpec { EventLoopGroup.nio() ++ ChannelFactory.nio ++ ServerChannelFactory.nio ++ DynamicServer.live def clientSpec = suite("ClientSpec") { - testM("respond Ok") { + test("respond Ok") { val app = Http.ok.deploy.status.run() assertM(app)(equalTo(Status.OK)) } + - testM("non empty content") { + test("non empty content") { val app = Http.text("abc") val responseContent = app.deploy.body.run() assertM(responseContent)(isNonEmpty) } + - testM("echo POST request content") { + test("echo POST request content") { val app = Http.collectZIO[Request] { case req => req.bodyAsString.map(Response.text(_)) } val res = app.deploy.bodyAsString.run(method = Method.POST, content = "ZIO user") assertM(res)(equalTo("ZIO user")) } + - testM("empty content") { + test("empty content") { val app = Http.empty val responseContent = app.deploy.body.run() assertM(responseContent)(isEmpty) } + - testM("text content") { + test("text content") { val app = Http.text("zio user does not exist") val responseContent = app.deploy.bodyAsString.run() assertM(responseContent)(containsString("user")) @@ -47,7 +47,7 @@ object ClientSpec extends HttpRunnableSpec { } override def spec = { - suiteM("Client") { + suite("Client") { serve(DynamicServer.app).as(List(clientSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(5 seconds) @@ sequential } diff --git a/zio-http/src/test/scala/zhttp/service/SSLSpec.scala b/zio-http/src/test/scala/zhttp/service/SSLSpec.scala index a7bafdc50a..689803cb22 100644 --- a/zio-http/src/test/scala/zhttp/service/SSLSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/SSLSpec.scala @@ -6,8 +6,7 @@ import zhttp.http._ import zhttp.service.client.ClientSSLHandler.ClientSSLOptions import zhttp.service.server.ServerSSLHandler.{ServerSSLOptions, ctxFromCert} import zhttp.service.server._ -import zio.ZIO -import zio.duration.durationInt +import zio._ import zio.test.Assertion.equalTo import zio.test.TestAspect.{ignore, timeout} import zio.test.{DefaultRunnableSpec, assertM} @@ -28,19 +27,19 @@ object SSLSpec extends DefaultRunnableSpec { ZIO.succeed(Response.ok) } - override def spec = suiteM("SSL")( + override def spec = suite("SSL")( Server .make(Server.app(app) ++ Server.port(8073) ++ Server.ssl(ServerSSLOptions(serverSSL))) .orDie .as( List( - testM("succeed when client has the server certificate") { + test("succeed when client has the server certificate") { val actual = Client .request("https://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL1)) .map(_.status) assertM(actual)(equalTo(Status.OK)) } + - testM("fail with DecoderException when client doesn't have the server certificate") { + test("fail with DecoderException when client doesn't have the server certificate") { val actual = Client .request("https://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL2)) .catchSome { case _: DecoderException => @@ -48,13 +47,13 @@ object SSLSpec extends DefaultRunnableSpec { } assertM(actual)(equalTo("DecoderException")) } + - testM("succeed when client has default SSL") { + test("succeed when client has default SSL") { val actual = Client .request("https://localhost:8073/success", ssl = ClientSSLOptions.DefaultSSL) .map(_.status) assertM(actual)(equalTo(Status.OK)) } + - testM("Https Redirect when client makes http request") { + test("Https Redirect when client makes http request") { val actual = Client .request("http://localhost:8073/success", ssl = ClientSSLOptions.CustomSSL(clientSSL1)) .map(_.status) diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index fa0f506fbc..99d418ee13 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -4,8 +4,7 @@ import zhttp.html._ import zhttp.http._ import zhttp.internal.{DynamicServer, HttpGen, HttpRunnableSpec} import zhttp.service.server._ -import zio.ZIO -import zio.duration.durationInt +import zio._ import zio.stream.ZStream import zio.test.Assertion._ import zio.test.TestAspect._ @@ -16,15 +15,15 @@ import java.nio.file.Paths object ServerSpec extends HttpRunnableSpec { - private val nonEmptyContent = for { + private def nonEmptyContent = for { data <- Gen.listOf(Gen.alphaNumericString) content <- HttpGen.nonEmptyHttpData(Gen.const(data)) } yield (data.mkString(""), content) - private val env = + private def env = EventLoopGroup.nio() ++ ChannelFactory.nio ++ ServerChannelFactory.nio ++ DynamicServer.live - private val staticApp = Http.collectZIO[Request] { + private def staticApp = Http.collectZIO[Request] { case Method.GET -> !! / "success" => ZIO.succeed(Response.ok) case Method.GET -> !! / "failure" => ZIO.fail(new RuntimeException("FAILURE")) case Method.GET -> !! / "get%2Fsuccess" => ZIO.succeed(Response.ok) @@ -36,45 +35,45 @@ object ServerSpec extends HttpRunnableSpec { case _ -> !! / "HExitFailure" => Http.fail(new RuntimeException("FAILURE")) } - private val app = serve { nonZIO ++ staticApp ++ DynamicServer.app } + private def app = serve { nonZIO ++ staticApp ++ DynamicServer.app } def dynamicAppSpec = suite("DynamicAppSpec") { suite("success") { - testM("status is 200") { + test("status is 200") { val status = Http.ok.deploy.status.run() assertM(status)(equalTo(Status.OK)) } + - testM("status is 200") { + test("status is 200") { val res = Http.text("ABC").deploy.status.run() assertM(res)(equalTo(Status.OK)) } + - testM("content is set") { + test("content is set") { val res = Http.text("ABC").deploy.bodyAsString.run() assertM(res)(containsString("ABC")) } } + suite("not found") { val app = Http.empty - testM("status is 404") { + test("status is 404") { val res = app.deploy.status.run() assertM(res)(equalTo(Status.NOT_FOUND)) } + - testM("header is set") { + test("header is set") { val res = app.deploy.headerValue(HeaderNames.contentLength).run() assertM(res)(isSome(equalTo("0"))) } } + suite("error") { val app = Http.fail(new Error("SERVER_ERROR")) - testM("status is 500") { + test("status is 500") { val res = app.deploy.status.run() assertM(res)(equalTo(Status.INTERNAL_SERVER_ERROR)) } + - testM("content is set") { + test("content is set") { val res = app.deploy.bodyAsString.run() assertM(res)(containsString("SERVER_ERROR")) } + - testM("header is set") { + test("header is set") { val res = app.deploy.headerValue(HeaderNames.contentLength).run() assertM(res)(isSome(anything)) } @@ -84,32 +83,32 @@ object ServerSpec extends HttpRunnableSpec { req.bodyAsString.map(text => Response.text(text)) } - testM("status is 200") { + test("status is 200") { val res = app.deploy.status.run() assertM(res)(equalTo(Status.OK)) } + - testM("body is ok") { + test("body is ok") { val res = app.deploy.bodyAsString.run(content = "ABC") assertM(res)(equalTo("ABC")) } + - testM("empty string") { + test("empty string") { val res = app.deploy.bodyAsString.run(content = "") assertM(res)(equalTo("")) } + - testM("one char") { + test("one char") { val res = app.deploy.bodyAsString.run(content = "1") assertM(res)(equalTo("1")) } } + suite("headers") { val app = Http.ok.addHeader("Foo", "Bar") - testM("headers are set") { + test("headers are set") { val res = app.deploy.headerValue("Foo").run() assertM(res)(isSome(equalTo("Bar"))) } } + suite("response") { val app = Http.response(Response(status = Status.OK, data = HttpData.fromString("abc"))) - testM("body is set") { + test("body is set") { val res = app.deploy.bodyAsString.run() assertM(res)(equalTo("abc")) } @@ -120,13 +119,13 @@ object ServerSpec extends HttpRunnableSpec { val app: HttpApp[Any, Nothing] = Http.collect[Request] { case req => Response.text(req.contentLength.getOrElse(-1).toString) } - testM("has content-length") { - checkAllM(Gen.alphaNumericString) { string => + test("has content-length") { + checkAll(Gen.alphaNumericString) { string => val res = app.deploy.bodyAsString.run(content = string) assertM(res)(equalTo(string.length.toString)) } } + - testM("POST Request.getBody") { + test("POST Request.getBody") { val app = Http.collectZIO[Request] { case req => req.body.as(Response.ok) } val res = app.deploy.status.run(path = !!, method = Method.POST, content = "some text") assertM(res)(equalTo(Status.OK)) @@ -134,18 +133,18 @@ object ServerSpec extends HttpRunnableSpec { } def responseSpec = suite("ResponseSpec") { - testM("data") { - checkAllM(nonEmptyContent) { case (string, data) => + test("data") { + checkAll(nonEmptyContent) { case (string, data) => val res = Http.fromData(data).deploy.bodyAsString.run() assertM(res)(equalTo(string)) } } + - testM("data from file") { + test("data from file") { val file = new File(getClass.getResource("/TestFile.txt").getPath) val res = Http.fromFile(file).deploy.bodyAsString.run() assertM(res)(equalTo("abc\nfoo")) } + - testM("content-type header on file response") { + test("content-type header on file response") { val file = new File(getClass.getResource("/TestFile.txt").getPath) val res = Http @@ -156,19 +155,19 @@ object ServerSpec extends HttpRunnableSpec { .map(_.getOrElse("Content type header not found.")) assertM(res)(equalTo("text/plain")) } + - testM("status") { - checkAllM(HttpGen.status) { case status => + test("status") { + checkAll(HttpGen.status) { case status => val res = Http.status(status).deploy.status.run() assertM(res)(equalTo(status)) } } + - testM("header") { - checkAllM(HttpGen.header) { case header @ (name, value) => + test("header") { + checkAll(HttpGen.header) { case header @ (name, value) => val res = Http.ok.addHeader(header).deploy.headerValue(name).run() assertM(res)(isSome(equalTo(value))) } } + - testM("text streaming") { + test("text streaming") { val res = Http.fromStream(ZStream("a", "b", "c")).deploy.bodyAsString.run() assertM(res)(equalTo("abc")) } + @@ -182,17 +181,17 @@ object ServerSpec extends HttpRunnableSpec { .run(content = "abc") assertM(res)(equalTo("abc")) } + - testM("file-streaming") { + test("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath - val res = Http.fromStream(ZStream.fromFile(Paths.get(path))).deploy.bodyAsString.run() + val res = Http.fromStream(ZStream.fromPath(Paths.get(path))).deploy.bodyAsString.run() assertM(res)(equalTo("abc\nfoo")) - } + + } @@ TestAspect.unix + suite("html") { - testM("body") { + test("body") { val res = Http.html(html(body(div(id := "foo", "bar")))).deploy.bodyAsString.run() assertM(res)(equalTo("""
bar
""")) } + - testM("content-type") { + test("content-type") { val app = Http.html(html(body(div(id := "foo", "bar")))) val res = app.deploy.headerValue(HeaderNames.contentType).run() assertM(res)(isSome(equalTo(HeaderValues.textHtml.toString))) @@ -200,18 +199,18 @@ object ServerSpec extends HttpRunnableSpec { } + suite("content-length") { suite("string") { - testM("unicode text") { + test("unicode text") { val res = Http.text("äöü").deploy.contentLength.run() assertM(res)(isSome(equalTo(6L))) } + - testM("already set") { + test("already set") { val res = Http.text("1234567890").withContentLength(4L).deploy.contentLength.run() assertM(res)(isSome(equalTo(4L))) } } } + suite("memoize") { - testM("concurrent") { + test("concurrent") { val size = 100 val expected = (0 to size) map (_ => Status.OK) for { @@ -219,7 +218,7 @@ object ServerSpec extends HttpRunnableSpec { actual <- ZIO.foreachPar(0 to size)(_ => Http.response(response).deploy.status.run()) } yield assert(actual)(equalTo(expected)) } + - testM("update after cache") { + test("update after cache") { val server = "ZIO-Http" for { res <- Response.text("abc").freeze @@ -230,15 +229,15 @@ object ServerSpec extends HttpRunnableSpec { } def serverStartSpec = suite("ServerStartSpec") { - testM("desired port") { + test("desired port") { val port = 8088 (Server.port(port) ++ Server.app(Http.empty)).make.use { start => - assertM(ZIO.effect(start.port))(equalTo(port)) + assertM(ZIO.attempt(start.port))(equalTo(port)) } } + - testM("available port") { + test("available port") { (Server.port(0) ++ Server.app(Http.empty)).make.use { start => - assertM(ZIO.effect(start.port))(not(equalTo(0))) + assertM(ZIO.attempt(start.port))(not(equalTo(0))) } } } @@ -249,23 +248,23 @@ object ServerSpec extends HttpRunnableSpec { }.provideCustomLayerShared(env) @@ timeout(30 seconds) def staticAppSpec = suite("StaticAppSpec") { - testM("200 response") { + test("200 response") { val actual = status(path = !! / "success") assertM(actual)(equalTo(Status.OK)) } + - testM("500 response") { + test("500 response") { val actual = status(path = !! / "failure") assertM(actual)(equalTo(Status.INTERNAL_SERVER_ERROR)) } + - testM("404 response") { + test("404 response") { val actual = status(path = !! / "random") assertM(actual)(equalTo(Status.NOT_FOUND)) } + - testM("200 response with encoded path") { + test("200 response with encoded path") { val actual = status(path = !! / "get%2Fsuccess") assertM(actual)(equalTo(Status.OK)) } + - testM("Multiple 200 response") { + test("Multiple 200 response") { for { data <- status(path = !! / "success").repeatN(1024) } yield assertTrue(data == Status.OK) diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index e950abf505..505e7bae87 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -3,12 +3,9 @@ package zhttp.service import zhttp.http.Status import zhttp.internal.{DynamicServer, HttpRunnableSpec} import zhttp.service.server._ -import zhttp.socket.{Socket, WebSocketFrame} import zio.ZIO -import zio.duration._ -import zio.test.Assertion.equalTo +import zio._ import zio.test.TestAspect.timeout -import zio.test._ object WebSocketServerSpec extends HttpRunnableSpec { @@ -20,7 +17,7 @@ object WebSocketServerSpec extends HttpRunnableSpec { app.as(List(websocketSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(10 seconds) - def websocketSpec = suite("WebSocket Server") { + def websocketSpec = suite("WebSocket Server")() /* { suite("connections") { testM("Multiple websocket upgrades") { val app = Socket.succeed(WebSocketFrame.text("BAR")).toHttp.deployWS diff --git a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala index b0889fadf2..f34054245a 100644 --- a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala +++ b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala @@ -15,47 +15,50 @@ object SocketSpec extends DefaultRunnableSpec { } @@ timeout(5 seconds) def operationsSpec = suite("OperationsSpec") { - testM("fromStream provide") { + test("fromStream provide") { val text = "Cat ipsum dolor sit amet" - val environment = ZStream.environment[String] + val environment = ZStream.service[String] val socket = Socket .fromStream(environment) - .provide(text) + .provideEnvironment(ZEnvironment(text)) .execute("") - assertM(socket.runCollect)(equalTo(Chunk(text))) - } + - testM("fromFunction provide") { - val environmentFunction = (_: Any) => ZStream.environment[WebSocketFrame] - val socket = Socket - .fromFunction(environmentFunction) - .provide(WebSocketFrame.text("Foo")) - .execute(WebSocketFrame.text("Bar")) - - assertM(socket.runCollect)(equalTo(Chunk(WebSocketFrame.text("Foo")))) - } + - testM("collect provide") { - val environment = ZStream.environment[WebSocketFrame] - val socket = Socket - .collect[WebSocketFrame] { case WebSocketFrame.Pong => - environment - } - .provide(WebSocketFrame.ping) - .execute(WebSocketFrame.pong) + assertM(socket.runCollect) { + equalTo(Chunk(text)) + } + } + test("fromFunction provide") { + val environmentFunction = (_: Any) => ZStream.service[WebSocketFrame] + val socket = Socket + .fromFunction(environmentFunction) + .provideEnvironment(ZEnvironment(WebSocketFrame.text("Foo"))) + .execute(WebSocketFrame.text("Bar")) - assertM(socket.runCollect)(equalTo(Chunk(WebSocketFrame.ping))) - } + - testM("ordered provide") { - val socket = Socket.collect[Int] { case _ => - ZStream.environment[Int] + assertM(socket.runCollect) { + equalTo(Chunk(WebSocketFrame.text("Foo"))) + } + } + test("collect provide") { + val environment = ZStream.service[WebSocketFrame] + val socket = Socket + .collect[WebSocketFrame] { case WebSocketFrame.Pong => + environment } + .provideEnvironment(ZEnvironment(WebSocketFrame.ping)) + .execute(WebSocketFrame.pong) + + assertM(socket.runCollect) { + equalTo(Chunk(WebSocketFrame.ping)) + } + } + test("ordered provide") { + val socket = Socket.collect[Int] { case _ => + ZStream.service[Int] + } - val socketA: Socket[Int, Nothing, Int, Int] = socket.provide(12) - val socketB: Socket[Int, Nothing, Int, Int] = socketA.provide(1) - val socketC: Socket[Any, Nothing, Int, Int] = socketB.provide(42) + val socketA: Socket[Int, Nothing, Int, Int] = socket.provideEnvironment(ZEnvironment(12)) + val socketB: Socket[Int, Nothing, Int, Int] = socketA.provideEnvironment(ZEnvironment(1)) + val socketC: Socket[Any, Nothing, Int, Int] = socketB.provideEnvironment(ZEnvironment(42)) - assertM(socketC.execute(1000).runCollect)(equalTo(Chunk(12))) - } + + assertM(socketC.execute(1000).runCollect)(equalTo(Chunk(12))) + } + testM("echo") { assertM(Socket.echo(1).runCollect)(equalTo(Chunk(1))) } + From bbcffb6020346b70f97f07d93b96c2cf0f64d935 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Sat, 15 Jan 2022 17:22:48 +0530 Subject: [PATCH 88/95] Backmerge main 14 jan 2021 (#831) * Doc: Add outline (#815) * doc: add categories * refactor: doc structure refactored * fix: package-lock.json removed * refactor: create outline sub-directories * refactor: rename test to testing * Update netty-all to 4.1.73.Final (#811) * Feature: API to modify headers (#824) * feat(Headers):added new api to update headers * renamed api * Feature: Signed Cookie (#751) * feat(cookie): added secret in cookie * feat(cookie): added signcookie middleware * feat(cookie): scalafmt * fix(cookie): sign cookie while encoding * scalafmt * fix(Cookie): added unsign method for cookie * fix(cookie): minor changes * fix(signCookieMiddleware: simplified signCookies * fix(cookie): removed try catch from signContent * cookie: throw error in verify * cookie: throw error in verify * verify method changes * fixed test cases * fix: removed decodeResponseSignedCookie * fix: middlewareSpec * added modifyheaders in middleware * removed unwanted changes * scalafmt * refactoring * refactoring * build fix * build fix * fix: decodeResponseCookie * added modify * Update sbt-scalafix to 0.9.34 (#805) * Fix: Echo streaming (#828) * Failing test * Fix echo streaming * Pr Comments * ZIO 2 support (#809) * upgrade to zio 2.0.0-RC1 * bump timeout for failing test * other fixes * increase timeout * rejigger broken test * try, try again * get compiling & tests passing Co-authored-by: Kit Langton * ZIO2 changes * scalafmt * renamed Co-authored-by: Shubham Girdhar Co-authored-by: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Co-authored-by: John A. De Goes Co-authored-by: Kit Langton --- docs/website/docs/client/_category_.json | 4 ++ docs/website/docs/client/index.md | 1 + docs/website/docs/dsl/_category_.json | 4 ++ docs/website/docs/dsl/cookies/_category_.json | 4 ++ docs/website/docs/dsl/cookies/index.md | 1 + docs/website/docs/dsl/headers/_category_.json | 4 ++ docs/website/docs/dsl/headers/index.md | 1 + .../docs/dsl/http-data/_category_.json | 4 ++ docs/website/docs/dsl/http-data/index.md | 1 + .../docs/dsl/http-endpoint/_category_.json | 4 ++ docs/website/docs/dsl/http-endpoint/index.md | 1 + docs/website/docs/dsl/http/_category_.json | 4 ++ docs/website/docs/dsl/http/index.md | 1 + .../docs/dsl/middleware/_category_.json | 4 ++ docs/website/docs/dsl/middleware/index.md | 1 + docs/website/docs/dsl/request/_category_.json | 4 ++ docs/website/docs/dsl/request/index.md | 1 + .../website/docs/dsl/response/_category_.json | 4 ++ docs/website/docs/dsl/response/index.md | 1 + docs/website/docs/dsl/server/_category_.json | 4 ++ docs/website/docs/dsl/server/config.md | 3 + docs/website/docs/dsl/socket/_category_.json | 4 ++ docs/website/docs/dsl/socket/index.md | 1 + docs/website/docs/examples/_category_.json | 4 ++ .../advanced-examples/_category_.json} | 0 .../advanced-examples/authentication.md} | 0 .../advanced-examples/concrete-entity.md} | 0 .../{ => examples}/advanced-examples/cors.md | 0 .../advanced-examples/hello-world-advanced.md | 0 .../advanced-examples/sticky-threads.md | 0 .../examples/advanced-examples/stream-file.md | 0 .../advanced-examples/stream-response.md | 0 .../advanced-examples/web-socket-advanced.md | 0 .../zio-http-basic-examples/_category_.json | 0 .../zio-http-basic-examples/hello-world.md | 0 .../zio-http-basic-examples/https-client.md | 0 .../zio-http-basic-examples/https-server.md | 0 .../zio-http-basic-examples/simple-client.md | 0 .../zio-http-basic-examples/web-socket.md | 0 .../website/docs/integrations/_category_.json | 4 ++ docs/website/docs/integrations/index.md | 1 + docs/website/docs/testing/_category_.json | 4 ++ docs/website/docs/testing/index.md | 1 + .../advanced-examples/_category_.json | 4 -- .../advanced-examples/authentication.md | 63 ------------------- .../advanced-examples/concrete-entity.md | 33 ---------- .../advanced-examples/hello-world-advanced.md | 47 -------------- .../advanced-examples/stream-response.md | 41 ------------ .../advanced-examples/web-socket-advanced.md | 60 ------------------ .../zio-http-basic-examples/_category_.json | 4 -- .../zio-http-basic-examples/hello-world.md | 20 ------ .../zio-http-basic-examples/https-client.md | 42 ------------- .../zio-http-basic-examples/simple-client.md | 27 -------- .../zio-http-basic-examples/web-socket.md | 31 --------- .../src/main/scala/example/SignCookies.scala | 9 ++- .../src/main/scala/zhttp/http/Headers.scala | 2 + .../main/scala/zhttp/http/Middleware.scala | 16 +++++ .../handlers/ServerResponseHandler.scala | 9 +++ .../zhttp/middleware/MiddlewareSpec.scala | 1 + .../test/scala/zhttp/service/ServerSpec.scala | 8 +++ .../zhttp/service/WebSocketServerSpec.scala | 31 --------- 61 files changed, 115 insertions(+), 408 deletions(-) create mode 100644 docs/website/docs/client/_category_.json create mode 100644 docs/website/docs/client/index.md create mode 100644 docs/website/docs/dsl/_category_.json create mode 100644 docs/website/docs/dsl/cookies/_category_.json create mode 100644 docs/website/docs/dsl/cookies/index.md create mode 100644 docs/website/docs/dsl/headers/_category_.json create mode 100644 docs/website/docs/dsl/headers/index.md create mode 100644 docs/website/docs/dsl/http-data/_category_.json create mode 100644 docs/website/docs/dsl/http-data/index.md create mode 100644 docs/website/docs/dsl/http-endpoint/_category_.json create mode 100644 docs/website/docs/dsl/http-endpoint/index.md create mode 100644 docs/website/docs/dsl/http/_category_.json create mode 100644 docs/website/docs/dsl/http/index.md create mode 100644 docs/website/docs/dsl/middleware/_category_.json create mode 100644 docs/website/docs/dsl/middleware/index.md create mode 100644 docs/website/docs/dsl/request/_category_.json create mode 100644 docs/website/docs/dsl/request/index.md create mode 100644 docs/website/docs/dsl/response/_category_.json create mode 100644 docs/website/docs/dsl/response/index.md create mode 100644 docs/website/docs/dsl/server/_category_.json create mode 100644 docs/website/docs/dsl/server/config.md create mode 100644 docs/website/docs/dsl/socket/_category_.json create mode 100644 docs/website/docs/dsl/socket/index.md create mode 100644 docs/website/docs/examples/_category_.json rename docs/website/docs/{advanced-examples/sticky-threads.md => examples/advanced-examples/_category_.json} (100%) rename docs/website/docs/{advanced-examples/stream-file.md => examples/advanced-examples/authentication.md} (100%) rename docs/website/docs/{zio-http-basic-examples/https-server.md => examples/advanced-examples/concrete-entity.md} (100%) rename docs/website/docs/{ => examples}/advanced-examples/cors.md (100%) create mode 100644 docs/website/docs/examples/advanced-examples/hello-world-advanced.md create mode 100644 docs/website/docs/examples/advanced-examples/sticky-threads.md create mode 100644 docs/website/docs/examples/advanced-examples/stream-file.md create mode 100644 docs/website/docs/examples/advanced-examples/stream-response.md create mode 100644 docs/website/docs/examples/advanced-examples/web-socket-advanced.md create mode 100644 docs/website/docs/examples/zio-http-basic-examples/_category_.json create mode 100644 docs/website/docs/examples/zio-http-basic-examples/hello-world.md create mode 100644 docs/website/docs/examples/zio-http-basic-examples/https-client.md create mode 100644 docs/website/docs/examples/zio-http-basic-examples/https-server.md create mode 100644 docs/website/docs/examples/zio-http-basic-examples/simple-client.md create mode 100644 docs/website/docs/examples/zio-http-basic-examples/web-socket.md create mode 100644 docs/website/docs/integrations/_category_.json create mode 100644 docs/website/docs/integrations/index.md create mode 100644 docs/website/docs/testing/_category_.json create mode 100644 docs/website/docs/testing/index.md diff --git a/docs/website/docs/client/_category_.json b/docs/website/docs/client/_category_.json new file mode 100644 index 0000000000..2375b2e5de --- /dev/null +++ b/docs/website/docs/client/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Client", + "position": 4 +} diff --git a/docs/website/docs/client/index.md b/docs/website/docs/client/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/client/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/_category_.json b/docs/website/docs/dsl/_category_.json new file mode 100644 index 0000000000..26a54df6b1 --- /dev/null +++ b/docs/website/docs/dsl/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "DSL", + "position": 3 +} diff --git a/docs/website/docs/dsl/cookies/_category_.json b/docs/website/docs/dsl/cookies/_category_.json new file mode 100644 index 0000000000..9b211dec85 --- /dev/null +++ b/docs/website/docs/dsl/cookies/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Cookies", + "position": 6 +} diff --git a/docs/website/docs/dsl/cookies/index.md b/docs/website/docs/dsl/cookies/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/cookies/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/headers/_category_.json b/docs/website/docs/dsl/headers/_category_.json new file mode 100644 index 0000000000..e262285346 --- /dev/null +++ b/docs/website/docs/dsl/headers/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Headers", + "position": 5 +} diff --git a/docs/website/docs/dsl/headers/index.md b/docs/website/docs/dsl/headers/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/headers/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http-data/_category_.json b/docs/website/docs/dsl/http-data/_category_.json new file mode 100644 index 0000000000..b75e6fa5f0 --- /dev/null +++ b/docs/website/docs/dsl/http-data/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "HttpData", + "position": 4 +} diff --git a/docs/website/docs/dsl/http-data/index.md b/docs/website/docs/dsl/http-data/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http-data/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http-endpoint/_category_.json b/docs/website/docs/dsl/http-endpoint/_category_.json new file mode 100644 index 0000000000..32aac10e88 --- /dev/null +++ b/docs/website/docs/dsl/http-endpoint/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Endpoint", + "position": 7 +} diff --git a/docs/website/docs/dsl/http-endpoint/index.md b/docs/website/docs/dsl/http-endpoint/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http-endpoint/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/http/_category_.json b/docs/website/docs/dsl/http/_category_.json new file mode 100644 index 0000000000..36e5fb9e60 --- /dev/null +++ b/docs/website/docs/dsl/http/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Http", + "position": 1 +} diff --git a/docs/website/docs/dsl/http/index.md b/docs/website/docs/dsl/http/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/http/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/middleware/_category_.json b/docs/website/docs/dsl/middleware/_category_.json new file mode 100644 index 0000000000..56c8cbc188 --- /dev/null +++ b/docs/website/docs/dsl/middleware/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Middleware", + "position": 9 +} diff --git a/docs/website/docs/dsl/middleware/index.md b/docs/website/docs/dsl/middleware/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/middleware/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/request/_category_.json b/docs/website/docs/dsl/request/_category_.json new file mode 100644 index 0000000000..c942703c4e --- /dev/null +++ b/docs/website/docs/dsl/request/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Request", + "position": 2 +} diff --git a/docs/website/docs/dsl/request/index.md b/docs/website/docs/dsl/request/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/request/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/response/_category_.json b/docs/website/docs/dsl/response/_category_.json new file mode 100644 index 0000000000..cf41ce17cb --- /dev/null +++ b/docs/website/docs/dsl/response/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Response", + "position": 3 +} diff --git a/docs/website/docs/dsl/response/index.md b/docs/website/docs/dsl/response/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/response/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/server/_category_.json b/docs/website/docs/dsl/server/_category_.json new file mode 100644 index 0000000000..2e000bb553 --- /dev/null +++ b/docs/website/docs/dsl/server/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Server", + "position": 8 +} diff --git a/docs/website/docs/dsl/server/config.md b/docs/website/docs/dsl/server/config.md new file mode 100644 index 0000000000..50b2454a71 --- /dev/null +++ b/docs/website/docs/dsl/server/config.md @@ -0,0 +1,3 @@ +# Config + +Work in progress \ No newline at end of file diff --git a/docs/website/docs/dsl/socket/_category_.json b/docs/website/docs/dsl/socket/_category_.json new file mode 100644 index 0000000000..095acccf27 --- /dev/null +++ b/docs/website/docs/dsl/socket/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Socket", + "position": 10 +} diff --git a/docs/website/docs/dsl/socket/index.md b/docs/website/docs/dsl/socket/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/dsl/socket/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/examples/_category_.json b/docs/website/docs/examples/_category_.json new file mode 100644 index 0000000000..2dc4c4fe79 --- /dev/null +++ b/docs/website/docs/examples/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Examples", + "position": 7 +} diff --git a/docs/website/docs/advanced-examples/sticky-threads.md b/docs/website/docs/examples/advanced-examples/_category_.json similarity index 100% rename from docs/website/docs/advanced-examples/sticky-threads.md rename to docs/website/docs/examples/advanced-examples/_category_.json diff --git a/docs/website/docs/advanced-examples/stream-file.md b/docs/website/docs/examples/advanced-examples/authentication.md similarity index 100% rename from docs/website/docs/advanced-examples/stream-file.md rename to docs/website/docs/examples/advanced-examples/authentication.md diff --git a/docs/website/docs/zio-http-basic-examples/https-server.md b/docs/website/docs/examples/advanced-examples/concrete-entity.md similarity index 100% rename from docs/website/docs/zio-http-basic-examples/https-server.md rename to docs/website/docs/examples/advanced-examples/concrete-entity.md diff --git a/docs/website/docs/advanced-examples/cors.md b/docs/website/docs/examples/advanced-examples/cors.md similarity index 100% rename from docs/website/docs/advanced-examples/cors.md rename to docs/website/docs/examples/advanced-examples/cors.md diff --git a/docs/website/docs/examples/advanced-examples/hello-world-advanced.md b/docs/website/docs/examples/advanced-examples/hello-world-advanced.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/advanced-examples/sticky-threads.md b/docs/website/docs/examples/advanced-examples/sticky-threads.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/advanced-examples/stream-file.md b/docs/website/docs/examples/advanced-examples/stream-file.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/advanced-examples/stream-response.md b/docs/website/docs/examples/advanced-examples/stream-response.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/examples/advanced-examples/web-socket-advanced.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/_category_.json b/docs/website/docs/examples/zio-http-basic-examples/_category_.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/hello-world.md b/docs/website/docs/examples/zio-http-basic-examples/hello-world.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-client.md b/docs/website/docs/examples/zio-http-basic-examples/https-client.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/https-server.md b/docs/website/docs/examples/zio-http-basic-examples/https-server.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/simple-client.md b/docs/website/docs/examples/zio-http-basic-examples/simple-client.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/examples/zio-http-basic-examples/web-socket.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/website/docs/integrations/_category_.json b/docs/website/docs/integrations/_category_.json new file mode 100644 index 0000000000..3e6c5308c1 --- /dev/null +++ b/docs/website/docs/integrations/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Integrations", + "position": 6 +} diff --git a/docs/website/docs/integrations/index.md b/docs/website/docs/integrations/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/integrations/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/testing/_category_.json b/docs/website/docs/testing/_category_.json new file mode 100644 index 0000000000..ed8fcad563 --- /dev/null +++ b/docs/website/docs/testing/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Testing", + "position": 5 +} diff --git a/docs/website/docs/testing/index.md b/docs/website/docs/testing/index.md new file mode 100644 index 0000000000..acfff8c574 --- /dev/null +++ b/docs/website/docs/testing/index.md @@ -0,0 +1 @@ +# Work in progress \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/_category_.json b/docs/website/docs/v1.x/examples/advanced-examples/_category_.json index 0621e5caa1..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/_category_.json +++ b/docs/website/docs/v1.x/examples/advanced-examples/_category_.json @@ -1,4 +0,0 @@ -{ - "label": "Advanced Examples", - "position": 2 -} diff --git a/docs/website/docs/v1.x/examples/advanced-examples/authentication.md b/docs/website/docs/v1.x/examples/advanced-examples/authentication.md index 1aa65022a7..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/authentication.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/authentication.md @@ -1,63 +0,0 @@ -# Authentication - -```scala -import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim} -import zhttp.http._ -import zhttp.service.Server -import zio._ - -import java.time.Clock - -object Authentication extends ZIOAppDefault { - // Secret Authentication key - val SECRET_KEY = "secretKey" - - implicit val clock: Clock = Clock.systemUTC - - // Helper to encode the JWT token - def jwtEncode(username: String): String = { - val json = s"""{"user": "${username}"}""" - val claim = JwtClaim { json }.issuedNow.expiresIn(60) - Jwt.encode(claim, SECRET_KEY, JwtAlgorithm.HS512) - } - - // Helper to decode the JWT token - def jwtDecode(token: String): Option[JwtClaim] = { - Jwt.decode(token, SECRET_KEY, Seq(JwtAlgorithm.HS512)).toOption - } - - // Authentication middleware - // Takes in a Failing HttpApp and a Succeed HttpApp which are called based on Authentication success or failure - // For each request tries to read the `X-ACCESS-TOKEN` header - // Validates JWT Claim - def authenticate[R, E](fail: HttpApp[R, E], success: JwtClaim => HttpApp[R, E]): HttpApp[R, E] = - Http - .fromFunction[Request] { - _.getHeader("X-ACCESS-TOKEN") - .flatMap(header => jwtDecode(header._2.toString)) - .fold[HttpApp[R, E]](fail)(success) - } - .flatten - - // Http app that requires a JWT claim - def user(claim: JwtClaim): UHttpApp = Http.collect[Request] { - case Method.GET -> !! / "user" / name / "greet" => Response.text(s"Welcome to the ZIO party! ${name}") - case Method.GET -> !! / "user" / "expiration" => Response.text(s"Expires in: ${claim.expiration.getOrElse(-1L)}") - } - - // App that let's the user login - // Login is successful only if the password is the reverse of the username - def login: UHttpApp = Http.collect[Request] { case Method.GET -> !! / "login" / username / password => - if (password.reverse == username) Response.text(jwtEncode(username)) - else Response.fromHttpError(HttpError.Unauthorized("Invalid username of password\n")) - } - - // Composing all the HttpApps together - val app: UHttpApp = login ++ authenticate(Http.forbidden("Not allowed!"), user) - - // Run it like any simple app - val run = - Server.start(8090, app) -} - -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md b/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md index 320a407b4a..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/concrete-entity.md @@ -1,33 +0,0 @@ -# Concrete Enity -```scala -import zhttp.http._ -import zhttp.service.Server -import zio._ - -/** - * Example to build app on concrete entity - */ -object ConcreteEntity extends ZIOAppDefault { - //Request - case class CreateUser(name: String) - - //Response - case class UserCreated(id: Long) - - val user: Http[Any, Nothing, CreateUser, UserCreated] = - Http.collect[CreateUser] { case CreateUser(_) => - UserCreated(2) - } - - val app: Http[Any, Nothing, Request, Response[Any, Nothing]] = user - .contramap[Request](req => CreateUser(req.endpoint._2.toString)) - //Http[Any, Nothing, Request, UserCreated] - .map(userCreated => Response.text(userCreated.id.toString)) - //Http[Any, Nothing, Request, Response] - - // Run it like any simple app - val run = - Server.start(8090, app) -} - -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md index 0af5eca4f7..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/hello-world-advanced.md @@ -1,47 +0,0 @@ -# Advanced Server - -```scala -import zhttp.http._ -import zhttp.service._ -import zhttp.service.server.ServerChannelFactory -import zio._ - -import scala.util.Try - -object HelloWorldAdvanced extends ZIOAppDefault { - // Set a port - private val PORT = 0 - - private val fooBar: HttpApp[Any, Nothing] = Http.collect[Request] { - case Method.GET -> !! / "foo" => Response.text("bar") - case Method.GET -> !! / "bar" => Response.text("foo") - } - - private val app = Http.collectZIO[Request] { - case Method.GET -> !! / "random" => random.nextString(10).map(Response.text(_)) - case Method.GET -> !! / "utc" => clock.currentDateTime.map(s => Response.text(s.toString)) - } - - private val server = - Server.port(PORT) ++ // Setup port - Server.paranoidLeakDetection ++ // Paranoid leak detection (affects performance) - Server.app(fooBar ++ app) // Setup the Http app - - override val run = { - // Configure thread count using CLI - val nThreads: Int = args.headOption.flatMap(x => Try(x.toInt).toOption).getOrElse(0) - - // Create a new server - server.make - .use(start => - // Waiting for the server to start - console.putStrLn(s"Server started on port ${start.port}") - - // Ensures the server doesn't die after printing - *> ZIO.never, - ) - .provideCustomLayer(ServerChannelFactory.auto ++ EventLoopGroup.auto(nThreads)) - } -} - -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md b/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md index ed656ff1e9..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/stream-response.md @@ -1,41 +0,0 @@ -# Streaming Response - -```scala -import zhttp.http._ -import zhttp.service.Server -import zio.stream.ZStream -import zio._ - -/** - * Example to encode content using a ZStream - */ -object StreamingResponse extends ZIOAppDefault { - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = { - - // Starting the server (for more advanced startup configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app.silent).exitCode - } - // Create a message as a Chunk[Byte] - val message = Chunk.fromArray("Hello world !\r\n".getBytes(HTTP_CHARSET)) - // Use `Http.collect` to match on route - val app: HttpApp[Any, Nothing] = Http.collect[Request] { - - // Simple (non-stream) based route - case Method.GET -> !! / "health" => Response.ok - - // ZStream powered response - case Method.GET -> !! / "stream" => - Response( - status = Status.OK, - headers = Headers.contentLength(message.length.toLong), - data = HttpData.fromStream(ZStream.fromChunk(message)), // Encoding content using a ZStream - ) - } - val run = { - - // Starting the server (for more advanced startup - // configuration checkout `HelloWorldAdvanced`) - Server.start(8090, app.silent) - } -} -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md index b69a9e334c..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md +++ b/docs/website/docs/v1.x/examples/advanced-examples/web-socket-advanced.md @@ -1,60 +0,0 @@ -# Web Socket Server -```scala -import zhttp.http._ -import zhttp.service.Server -import zhttp.socket._ -import zio._ -import zio.duration._ -import zio.stream.ZStream - -object WebSocketAdvanced extends ZIOAppDefault { - // Message Handlers - private val open = Socket.succeed(WebSocketFrame.text("Greetings!")) - - private val echo = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text(text) => - ZStream.repeat(WebSocketFrame.text(s"Received: $text")).schedule(Schedule.spaced(1 second)).take(3) - } - - private val fooBar = Socket.collect[WebSocketFrame] { - case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) - case WebSocketFrame.Text("BAR") => ZStream.succeed(WebSocketFrame.text("FOO")) - } - - // Setup protocol settings - private val protocol = SocketProtocol.subProtocol("json") - - // Setup decoder settings - private val decoder = SocketDecoder.allowExtensions - - // Combine all channel handlers together - private val socketApp = { - - SocketApp(echo merge fooBar) // Called after each message being received on the channel - - // Called after the request is successfully upgraded to websocket - .onOpen(open) - - // Called after the connection is closed - .onClose(_ => console.putStrLn("Closed!").ignore) - - // Called whenever there is an error on the socket channel - .onError(_ => console.putStrLn("Error!").ignore) - - // Setup websocket decoder config - .withDecoder(decoder) - - // Setup websocket protocol config - .withProtocol(protocol) - } - - private val app = - Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings ${name}!")) - case Method.GET -> !! / "subscriptions" => socketApp.toResponse - } - - val run = - Server.start(8090, app) -} - -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json b/docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json index 8afc5e6543..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/_category_.json @@ -1,4 +0,0 @@ -{ - "label": "Basic Examples", - "position": 1 -} diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md index 867c76f299..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/hello-world.md @@ -1,20 +0,0 @@ -# Simple Server - -```scala -import zhttp.http._ -import zhttp.service.Server -import zio._ - -object HelloWorld extends ZIOAppDefault { - - // Create HTTP route - val app: HttpApp[Any, Nothing] = Http.collect[Request] { - case Method.GET -> !! / "text" => Response.text("Hello World!") - case Method.GET -> !! / "json" => Response.json("""{"greetings": "Hello World!"}""") - } - - // Run it like any simple app - val run = - Server.start(8090, app.silent) -} -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md index 3d818d5cc9..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/https-client.md @@ -1,42 +0,0 @@ -# HTTPS Cient - -```scala -import io.netty.handler.ssl.SslContextBuilder -import zhttp.http.Headers -import zhttp.service.client.ClientSSLHandler.ClientSSLOptions -import zhttp.service.{ChannelFactory, Client, EventLoopGroup} -import zio._ - -import java.io.InputStream -import java.security.KeyStore -import javax.net.ssl.TrustManagerFactory - -object HttpsClient extends ZIOAppDefault { - val env = ChannelFactory.auto ++ EventLoopGroup.auto() - val url = "https://sports.api.decathlon.com/groups/water-aerobics" - val headers = Headers.host("sports.api.decathlon.com") - - // Configuring Truststore for https(optional) - val trustStore: KeyStore = KeyStore.getInstance("JKS") - val trustStorePath: InputStream = getClass.getClassLoader.getResourceAsStream("truststore.jks") - val trustStorePassword: String = "changeit" - val trustManagerFactory: TrustManagerFactory = - TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm) - - trustStore.load(trustStorePath, trustStorePassword.toCharArray) - trustManagerFactory.init(trustStore) - - val sslOption: ClientSSLOptions = - ClientSSLOptions.CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) - - val program = for { - res <- Client.request(url, headers, sslOption) - data <- res.getBodyAsString - _ <- console.putStrLn { data } - } yield () - - override val run = - program.provideCustom(env) - -} -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md index 7dadccb092..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/simple-client.md @@ -1,27 +0,0 @@ -# Simple HTTP Client -```scala -import zhttp.http.{Header, HttpData} -import zhttp.service.{ChannelFactory, Client, EventLoopGroup} -import zio._ - -object SimpleClient extends ZIOAppDefault { - val env = ChannelFactory.auto ++ EventLoopGroup.auto() - val url = "http://sports.api.decathlon.com/groups/water-aerobics" - val headers = List(Header.host("sports.api.decathlon.com")) - - val program = for { - res <- Client.request(url, headers) - _ <- console.putStrLn { - res.content match { - case HttpData.CompleteData(data) => data.map(_.toChar).mkString - case HttpData.StreamData(_) => "" - case HttpData.Empty => "" - } - } - } yield () - - override val run = - program.provide(env) - -} -``` \ No newline at end of file diff --git a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md index 1955a7cdfe..e69de29bb2 100644 --- a/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md +++ b/docs/website/docs/v1.x/examples/zio-http-basic-examples/web-socket.md @@ -1,31 +0,0 @@ -# Simple Websocket Server - -```scala -import zhttp.http._ -import zhttp.service._ -import zhttp.socket._ -import zio._ -import zio.duration._ -import zio.stream.ZStream - -object WebSocketEcho extends ZIOAppDefault { - private val socket = - Socket.collect[WebSocketFrame] { - case WebSocketFrame.Text("FOO") => ZStream.succeed(WebSocketFrame.text("BAR")) - case WebSocketFrame.Text("BAR") => ZStream.succeed(WebSocketFrame.text("FOO")) - case WebSocketFrame.Ping => ZStream.succeed(WebSocketFrame.pong) - case WebSocketFrame.Pong => ZStream.succeed(WebSocketFrame.ping) - case fr @ WebSocketFrame.Text(_) => ZStream.repeat(fr).schedule(Schedule.spaced(1 second)).take(10) - } - - private val app = - Http.collectZIO[Request] { - case Method.GET -> !! / "greet" / name => UIO(Response.text(s"Greetings {$name}!")) - case Method.GET -> !! / "subscriptions" => socket.toResponse - } - - override val run = - Server.start(8090, app) -} - -``` diff --git a/example/src/main/scala/example/SignCookies.scala b/example/src/main/scala/example/SignCookies.scala index 5df689905a..4de03d5978 100644 --- a/example/src/main/scala/example/SignCookies.scala +++ b/example/src/main/scala/example/SignCookies.scala @@ -1,14 +1,13 @@ package example -import zhttp.http.{Cookie, Method, Response, _} +import zhttp.http._ import zhttp.service.Server -import zio.duration.durationInt -import zio.{App, ExitCode, URIO} +import zio._ /** * Example to make app using signed-cookies */ -object SignCookies extends App { +object SignCookies extends ZIOAppDefault { // Setting cookies with an expiry of 5 days private val cookie = Cookie("key", "hello").withMaxAge(5 days) @@ -18,6 +17,6 @@ object SignCookies extends App { } // Run it like any simple app - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + val run = Server.start(8090, app).exitCode } diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index 92c9ac5eb5..33dd701a87 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -30,6 +30,8 @@ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList + def modify(f: Header => Header): Headers = Headers(toChunk.map(f(_))) + override def updateHeaders(update: Headers => Headers): Headers = update(self) def when(cond: Boolean): Headers = if (cond) self else Headers.empty diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index 32ab14bc6c..3f2760f799 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -1,5 +1,6 @@ package zhttp.http +import io.netty.util.AsciiString.contentEqualsIgnoreCase import zhttp.http.middleware.Web import zio.clock.Clock import zio.duration.Duration @@ -121,6 +122,12 @@ trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => final def map[BOut0](f: BOut => BOut0): Middleware[R, E, AIn, BIn, AOut, BOut0] = self.flatMap(b => Middleware.succeed(f(b))) + /** + * Modifies the provided list of headers to the updated list of headers + */ + def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[Any, Nothing] = + patch((_, _) => Patch.updateHeaders(_.modify(f))) + /** * Transforms the output type of the current middleware using effect function. */ @@ -192,6 +199,15 @@ object Middleware extends Web { */ def collect[A]: PartialCollect[A] = new PartialCollect[A](()) + /** + * Creates a middleware for signing cookies + */ + def signCookies(secret: String): Middleware[Any, Nothing] = + modifyHeaders { + case h if contentEqualsIgnoreCase(h._1, HeaderNames.setCookie) => + (HeaderNames.setCookie, Cookie.decodeResponseCookie(h._2.toString).get.sign(secret).encode) + } + /** * Creates a middleware using specified effect function */ diff --git a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala index 4352eeb9a9..ad06a6bf90 100644 --- a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala @@ -52,6 +52,15 @@ private[zhttp] case class ServerResponseHandler[R]( } } + /** + * Releases the FullHttpRequest safely. + */ + private def releaseRequest(jReq: FullHttpRequest): Unit = { + if (jReq.refCnt() > 0) { + jReq.release(jReq.refCnt()): Unit + } + } + /** * Checks if an encoded version of the response exists, uses it if it does. * Otherwise, it will return a fresh response. It will also set the server diff --git a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala index e69de29bb2..8b13789179 100644 --- a/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala +++ b/zio-http/src/test/scala/zhttp/middleware/MiddlewareSpec.scala @@ -0,0 +1 @@ + diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 99d418ee13..48f603688e 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -181,6 +181,14 @@ object ServerSpec extends HttpRunnableSpec { .run(content = "abc") assertM(res)(equalTo("abc")) } + + test("echo streaming") { + val res = Http + .collectHttp[Request] { case req => + Http.fromStream(ZStream.fromZIO(req.getBody).flattenChunks) + } + .requestBodyAsString(content = "abc") + assertM(res)(equalTo("abc")) + } + test("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath val res = Http.fromStream(ZStream.fromPath(Paths.get(path))).deploy.bodyAsString.run() diff --git a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala index 505e7bae87..8b13789179 100644 --- a/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/WebSocketServerSpec.scala @@ -1,32 +1 @@ -package zhttp.service -import zhttp.http.Status -import zhttp.internal.{DynamicServer, HttpRunnableSpec} -import zhttp.service.server._ -import zio.ZIO -import zio._ -import zio.test.TestAspect.timeout - -object WebSocketServerSpec extends HttpRunnableSpec { - - private val env = - EventLoopGroup.nio() ++ ServerChannelFactory.nio ++ DynamicServer.live ++ ChannelFactory.nio - private val app = serve { DynamicServer.app } - - override def spec = suiteM("Server") { - app.as(List(websocketSpec)).useNow - }.provideCustomLayerShared(env) @@ timeout(10 seconds) - - def websocketSpec = suite("WebSocket Server")() /* { - suite("connections") { - testM("Multiple websocket upgrades") { - val app = Socket.succeed(WebSocketFrame.text("BAR")).toHttp.deployWS - val codes = ZIO - .foreach(1 to 1024)(_ => app(Socket.empty.toSocketApp).map(_.status)) - .map(_.count(_ == Status.SWITCHING_PROTOCOLS)) - - assertM(codes)(equalTo(1024)) - } - } - } -} From ade0980a819099e2921937740bf5f4c525335ab5 Mon Sep 17 00:00:00 2001 From: Amit Kumar Singh Date: Mon, 17 Jan 2022 09:20:02 +0530 Subject: [PATCH 89/95] Enable snapshot versioning for ZIO-2/series (#844) --- .github/workflows/ci.yml | 2 +- build.sbt | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce5c60b58c..659227895b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: publish: name: Publish Artifacts needs: [build] - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')) + if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/zio-series/2.x' || startsWith(github.ref, 'refs/tags/v')) strategy: matrix: os: [ubuntu-latest] diff --git a/build.sbt b/build.sbt index c669bc3a40..cbcd5e8e22 100644 --- a/build.sbt +++ b/build.sbt @@ -4,14 +4,14 @@ import Dependencies._ val releaseDrafterVersion = "5" // CI Configuration -ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.graalvm("21.1.0", "11"), JavaSpec.temurin("8")) -ThisBuild / githubWorkflowPREventTypes := Seq( +ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.graalvm("21.1.0", "11"), JavaSpec.temurin("8")) +ThisBuild / githubWorkflowPREventTypes := Seq( PREventType.Opened, PREventType.Synchronize, PREventType.Reopened, PREventType.Edited, ) -ThisBuild / githubWorkflowAddedJobs := +ThisBuild / githubWorkflowAddedJobs := Seq( WorkflowJob( id = "update_release_draft", @@ -40,8 +40,12 @@ ThisBuild / githubWorkflowAddedJobs := ) ++ ScoverageWorkFlow(50, 60) ++ BenchmarkWorkFlow() ThisBuild / githubWorkflowTargetTags ++= Seq("v*") -ThisBuild / githubWorkflowPublishTargetBranches += RefPredicate.StartsWith(Ref.Tag("v")) -ThisBuild / githubWorkflowPublish := +ThisBuild / githubWorkflowPublishTargetBranches := Seq( + RefPredicate.Equals(Ref.Branch("main")), + RefPredicate.Equals(Ref.Branch("zio-series/2.x")), + RefPredicate.StartsWith(Ref.Tag("v")), +) +ThisBuild / githubWorkflowPublish := Seq( WorkflowStep.Sbt( List("ci-release"), @@ -56,7 +60,7 @@ ThisBuild / githubWorkflowPublish := ) //scala fix isn't available for scala 3 so ensure we only run the fmt check //using the latest scala 2.13 -ThisBuild / githubWorkflowBuildPreamble := +ThisBuild / githubWorkflowBuildPreamble := WorkflowJob( "fmtCheck", "Format", @@ -66,7 +70,7 @@ ThisBuild / githubWorkflowBuildPreamble := scalas = List(Scala213), ).steps -ThisBuild / githubWorkflowBuildPostamble := +ThisBuild / githubWorkflowBuildPostamble := WorkflowJob( "checkDocGeneration", "Check doc generation", From 1ba6ac0e56ce2ccbb100c32d22e5b474df830467 Mon Sep 17 00:00:00 2001 From: "John A. De Goes" Date: Wed, 19 Jan 2022 17:45:03 +0000 Subject: [PATCH 90/95] ZIO 2: Latest changes from main (#858) * Doc: Add outline (#815) * doc: add categories * refactor: doc structure refactored * fix: package-lock.json removed * refactor: create outline sub-directories * refactor: rename test to testing * Docs: Update Basic Examples (#814) * doc(Getting started): updated examples * docs: updated basic examples * docs: update advanced examples (#816) * maintenance: semanticdb revision usage (#832) * maintenance: workflow scala version (#833) * Fix: HasHeader bug (#835) * #834 - fix and test for the bug. * applied suggested change * refactor: fix naming for Http operators (#839) * Update sbt-bloop to 1.4.12 (#810) * Update sbt-bloop to 1.4.12 * Update sbt-bloop to 1.4.12 * Update scala-library to 2.13.8 (#801) * Update scala-library to 2.13.8 * Regenerate workflow with sbt-github-actions * Add configuration builder methods to zhttp.service.Server (#768) * Add configuration builder methods to zhttp.service.Server * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Update zio-http/src/main/scala/zhttp/service/Server.scala Co-authored-by: Tushar Mathur * Change some server with* builder methods (enable parameter) * Server withAcceptContinue(enabled) Co-authored-by: Tushar Mathur * maintenance: html template for internal server error string (#851) Closes #842 * Performance: Improve benchmarking code (#731) * wip: try server codec without validation * wip: remove flush consolidator * wip: use wrapped buffer * wip: add flush consolidator * perf: make response encoding checks faster * use encoder and decoder (#733) * wip: remove Request creation * use encoder and decoder Co-authored-by: Tushar Mathur * disable object aggregator * disable object aggregator * revert disable object aggregator * doc: update scala doc * perf: freeze the HttpResponse Co-authored-by: Amit Kumar Singh Co-authored-by: amitsingh * Refactor: Support middlewares on Http (#773) * refactor: remove type-params from Response * chore: self review * refactor: rename Middleware to HttpMiddleware * refactor: add `@@@` to Http as an alternative to `@@`. * feature: add new Middleware API * feature: add `flatten` and `ifThenElse` * feature: add `ifThenElseZIO` * refactor: fix type params for `identity` * feature: add `when` * feature: add `make` constructor * refactor: make middleware methods final * refactor: git remains * refactor: implement HttpMiddleware as Middleware * scala3 fix * Refactor CORS middleware (#788) * Refactor/merge middleware and http middleware (#790) * Refactor move cors and timeout * move some httpMiddlewares to Middleware * move some AuthMiddleware to Middleware * move remaining AuthMiddleware to Middleware * move Middlewares to middleware package * scaladoc * codec example * move Middleware to http package * named alias for `@@` * rename Auth to AuthMiddlewares * rename CORSMiddleware to CorsMiddlewares * rename CSRF to CsrfMiddlewares * make primitives private * rename MiddlewareExtensions to HttpMiddlewares * rename operators in HttpMiddlewares * scalaDoc * arg rename * doc update and general refactor * simplify cors middleware * rename CorsConfig * renames * Make middlewares package private MiddlewareRequest * Introduce MiddlewareRequest (#798) * Introduce MiddlewareRequest * PR review comments * Refactor move runAfter to Middleware * refactor: add `UMiddleware` * feature: add `contramapZIO` * refactor: move cors config to Cors file * refactor: rename files * refactor: remove AuthSpec from WebSpec * refactor: fix naming for Http operators * refactor: add partial type suport for contraMapZIO * Refactor: Codec (#841) * Add Run Before (#840) * Add Run Before * Add Run Before and After * use renamed operator * refactor: add partial type suport for contraMap * Implement missing operators in Middleware (#807) * Implement missing operators in Middleware * fix as operator * headers Middleware changes * sign cookie * extend with HeaderExtensions * rename suite * PR comments * refactor: use `Request` instead of `MiddlewareRequest` * refactor: rename methods * refactor: resolve fix me issue Co-authored-by: amitsingh Co-authored-by: Amit Kumar Singh * ZIO 2 support (#809) * upgrade to zio 2.0.0-RC1 * bump timeout for failing test * other fixes * increase timeout * rejigger broken test * try, try again * get compiling & tests passing Co-authored-by: Kit Langton * Delete commented websocket tests (#826) * Backmerge main 14 jan 2021 (#831) * Doc: Add outline (#815) * doc: add categories * refactor: doc structure refactored * fix: package-lock.json removed * refactor: create outline sub-directories * refactor: rename test to testing * Update netty-all to 4.1.73.Final (#811) * Feature: API to modify headers (#824) * feat(Headers):added new api to update headers * renamed api * Feature: Signed Cookie (#751) * feat(cookie): added secret in cookie * feat(cookie): added signcookie middleware * feat(cookie): scalafmt * fix(cookie): sign cookie while encoding * scalafmt * fix(Cookie): added unsign method for cookie * fix(cookie): minor changes * fix(signCookieMiddleware: simplified signCookies * fix(cookie): removed try catch from signContent * cookie: throw error in verify * cookie: throw error in verify * verify method changes * fixed test cases * fix: removed decodeResponseSignedCookie * fix: middlewareSpec * added modifyheaders in middleware * removed unwanted changes * scalafmt * refactoring * refactoring * build fix * build fix * fix: decodeResponseCookie * added modify * Update sbt-scalafix to 0.9.34 (#805) * Fix: Echo streaming (#828) * Failing test * Fix echo streaming * Pr Comments * ZIO 2 support (#809) * upgrade to zio 2.0.0-RC1 * bump timeout for failing test * other fixes * increase timeout * rejigger broken test * try, try again * get compiling & tests passing Co-authored-by: Kit Langton * ZIO2 changes * scalafmt * renamed Co-authored-by: Shubham Girdhar Co-authored-by: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Co-authored-by: John A. De Goes Co-authored-by: Kit Langton * Merge Co-authored-by: Shubham Girdhar Co-authored-by: Shruti Verma <62893271+ShrutiVerma97@users.noreply.github.com> Co-authored-by: Gabriel Ciuloaica <95849448+gciuloaica@users.noreply.github.com> Co-authored-by: Tushar Mathur Co-authored-by: Amit Kumar Singh Co-authored-by: Javier Goday Co-authored-by: Tushar Mathur Co-authored-by: amitsingh Co-authored-by: Kit Langton --- .../docs/examples/advanced-examples/cors.md | 22 --- docs/website/docs/getting-started.md | 133 ++++++++++++++++++ .../src/main/scala/example/SignCookies.scala | 3 +- zio-http/src/main/scala/zhttp/http/Http.scala | 13 +- .../src/main/scala/zhttp/service/Server.scala | 2 +- .../zhttp/http/middleware/CorsSpec.scala | 4 +- .../zhttp/http/middleware/CsrfSpec.scala | 8 +- 7 files changed, 148 insertions(+), 37 deletions(-) delete mode 100644 docs/website/docs/examples/advanced-examples/cors.md create mode 100644 docs/website/docs/getting-started.md diff --git a/docs/website/docs/examples/advanced-examples/cors.md b/docs/website/docs/examples/advanced-examples/cors.md deleted file mode 100644 index 2d28565ca2..0000000000 --- a/docs/website/docs/examples/advanced-examples/cors.md +++ /dev/null @@ -1,22 +0,0 @@ -# CORS Handling - -```scala -import zhttp.http._ -import zhttp.service.Server -import zio._ - -object HelloWorldWithCORS extends ZIOAppDefault { - // Create HTTP route with CORS enabled - val app: HttpApp[Any, Nothing] = CORS( - Http.collect[Request] { - case Method.GET -> !! / "text" => Response.text("Hello World!") - case Method.GET -> !! / "json" => Response.jsonString("""{"greetings": "Hello World!"}""") - }, - config = CORSConfig(anyOrigin = true), - ) - - // Run it like any simple app - val run = - Server.start(8090, app.silent) -} -``` \ No newline at end of file diff --git a/docs/website/docs/getting-started.md b/docs/website/docs/getting-started.md new file mode 100644 index 0000000000..e3a09048b8 --- /dev/null +++ b/docs/website/docs/getting-started.md @@ -0,0 +1,133 @@ +--- +sidebar_position: 2 +--- + +# Getting Started + +## Http + +### Creating a "_Hello World_" app + +```scala +import zhttp.http._ + +val app = Http.text("Hello World!") +``` + +An application can be made using any of the available operators on `zhttp.Http`. In the above program for any Http request, the response is always `"Hello World!"`. + +### Routing + +```scala +import zhttp.http._ + +val app = Http.collect[Request] { + case Method.GET -> !! / "fruits" / "a" => Response.text("Apple") + case Method.GET -> !! / "fruits" / "b" => Response.text("Banana") +} +``` + +Pattern matching on route is supported by the framework + +### Composition + +```scala +import zhttp.http._ + +val a = Http.collect[Request] { case Method.GET -> !! / "a" => Response.ok } +val b = Http.collect[Request] { case Method.GET -> !! / "b" => Response.ok } + +val app = a <> b +``` + +Apps can be composed using the `<>` operator. The way it works is, if none of the routes match in `a` , or a `NotFound` error is thrown from `a`, and then the control is passed on to the `b` app. + +### ZIO Integration + +```scala +val app = Http.collectZIO[Request] { + case Method.GET -> !! / "hello" => Response.text("Hello World").wrapZIO +} +``` + +`Http.collectZIO` allow routes to return a ZIO effect value. + +### Accessing the Request + +```scala +import zhttp.http._ + +val app = Http.collectZIO[Request] { + case req @ Method.GET -> !! / "fruits" / "a" => + Response.text("URL:" + req.url.path.asString + " Headers: " + req.getHeaders).wrapZIO + case req @ Method.POST -> !! / "fruits" / "a" => + req.getBodyAsString.map(Response.text(_)) + } +``` + +### Testing + +zhttp provides a `zhttp-test` package for use in unit tests. You can utilize it as follows: + +```scala +import zio.test._ +import zhttp.test._ +import zhttp.http._ + +object Spec extends DefaultRunnableSpec { + + def spec = suite("http")( + testM("should be ok") { + val app = Http.ok + val req = Request() + assertM(app(req))(equalTo(Response.ok)) // an apply method is added via `zhttp.test` package + } + ) +} +``` + +## Socket + +### Creating a socket app + +```scala +import zhttp.socket._ + +private val socket = Socket.collect[WebSocketFrame] { case WebSocketFrame.Text("FOO") => + ZStream.succeed(WebSocketFrame.text("BAR")) + } + + private val app = Http.collectZIO[Request] { + case Method.GET -> !! / "greet" / name => Response.text(s"Greetings {$name}!").wrapZIO + case Method.GET -> !! / "ws" => socket.toResponse + } +``` + +## Server + +### Starting an Http App + +```scala +import zhttp.http._ +import zhttp.service.Server +import zio._ + +object HelloWorld extends App { + val app = Http.ok + + override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = + Server.start(8090, app).exitCode +} +``` + +A simple Http app that responds with empty content and a `200` status code is deployed on port `8090` using `Server.start`. + +## Examples + +- [Simple Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorld.scala) +- [Advanced Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/HelloWorldAdvanced.scala) +- [WebSocket Server](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SocketEchoServer.scala) +- [Streaming Response](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/StreamingResponse.scala) +- [Simple Client](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/SimpleClient.scala) +- [File Streaming](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/FileStreaming.scala) +- [Authentication](https://github.com/dream11/zio-http/blob/main/example/src/main/scala/Authentication.scala) diff --git a/example/src/main/scala/example/SignCookies.scala b/example/src/main/scala/example/SignCookies.scala index 4de03d5978..49b20719cd 100644 --- a/example/src/main/scala/example/SignCookies.scala +++ b/example/src/main/scala/example/SignCookies.scala @@ -17,6 +17,5 @@ object SignCookies extends ZIOAppDefault { } // Run it like any simple app - val run = - Server.start(8090, app).exitCode + val run = Server.start(8090, app) } diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index b0c137bcd8..04ff15398f 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -552,9 +552,7 @@ object Http { */ def fromStream[R](stream: ZStream[R, Throwable, String], charset: Charset = HTTP_CHARSET): HttpApp[R, Nothing] = Http - .fromZIO( - ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r), charset))), - ) + .fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r), charset)))) .flatten /** @@ -562,9 +560,12 @@ object Http { * ZStream as the body */ def fromStream[R](stream: ZStream[R, Throwable, Byte]): HttpApp[R, Nothing] = - Http - .fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r))))) - .flatten + Http.fromZIO(ZIO.environment[R].map(r => Http.fromData(HttpData.fromStream(stream.provideEnvironment(r))))).flatten + + /** + * Converts a ZIO to an Http type + */ + def fromZIO[R, E, B](effect: ZIO[R, E, B]): Http[R, E, Any, B] = Http.fromFunctionZIO(_ => effect) /** * Converts a ZIO to an Http type diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index a2fe45a2b8..955bf3cccd 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -44,7 +44,7 @@ sealed trait Server[-R, +E] { self => * Launches the app with current settings: default EventLoopGroup (nThreads = * 0) and ServerChannelFactory.auto. */ - def startDefault[R1 <: Has[_] with R](implicit ev: E <:< Throwable): ZIO[R1, Throwable, Nothing] = + def startDefault[R1 <: R](implicit ev: E <:< Throwable): ZIO[R1, Throwable, Nothing] = start.provideSomeLayer[R1](EventLoopGroup.auto(0) ++ ServerChannelFactory.auto) /** diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala index b168596233..18a35ecba6 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/CorsSpec.scala @@ -10,7 +10,7 @@ import zio.test._ object CorsSpec extends DefaultRunnableSpec with HttpAppTestExtensions { override def spec = suite("CorsMiddlewares") { val app = Http.ok @@ cors() - testM("OPTIONS request") { + test("OPTIONS request") { val request = Request( method = Method.OPTIONS, url = URL(!! / "success"), @@ -31,7 +31,7 @@ object CorsSpec extends DefaultRunnableSpec with HttpAppTestExtensions { } yield assert(res.headersAsList)(hasSubset(expected)) && assertTrue(res.status == Status.NO_CONTENT) } + - testM("GET request") { + test("GET request") { val request = Request( method = Method.GET, diff --git a/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala index 4cf706171d..07007459d3 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/CsrfSpec.scala @@ -13,20 +13,20 @@ object CsrfSpec extends DefaultRunnableSpec with HttpAppTestExtensions { val setCookie = Headers.cookie(Cookie("x-token", "secret")) val invalidXToken = Headers("x-token", "secret1") val validXToken = Headers("x-token", "secret") - testM("x-token not present") { + test("x-token not present") { assertM(app(Request(headers = setCookie)))(equalTo(Status.FORBIDDEN)) } + - testM("x-token mismatch") { + test("x-token mismatch") { assertM(app(Request(headers = setCookie ++ invalidXToken)))( equalTo(Status.FORBIDDEN), ) } + - testM("x-token match") { + test("x-token match") { assertM(app(Request(headers = setCookie ++ validXToken)))( equalTo(Status.OK), ) } + - testM("app execution skipped") { + test("app execution skipped") { for { r <- Ref.make(false) app = Http.ok.tapZIO(_ => r.set(true)) @@ csrfValidate("x-token") From f1e182aeed0d70de072106b43ac44391a413c184 Mon Sep 17 00:00:00 2001 From: Adam Fraser Date: Tue, 1 Feb 2022 22:06:10 -0800 Subject: [PATCH 91/95] upgrade zio version (#942) --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index a42aef8ef9..af3cac1dd4 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -5,7 +5,7 @@ object Dependencies { val NettyVersion = "4.1.74.Final" val NettyIncubatorVersion = "0.0.12.Final" val ScalaCompactCollectionVersion = "2.6.0" - val ZioVersion = "2.0.0-RC1" + val ZioVersion = "2.0.0-RC2" val SttpVersion = "3.3.18" val `jwt-core` = "com.github.jwt-scala" %% "jwt-core" % JwtCoreVersion From 9f4acc52b40d01572bdb7962982c349e42de7445 Mon Sep 17 00:00:00 2001 From: amitsingh Date: Wed, 9 Feb 2022 16:14:47 +0530 Subject: [PATCH 92/95] zio2 support --- docs/website/docs/getting-started.md | 2 +- docs/website/docs/v1.x/dsl/http/index.md | 2 +- docs/website/docs/v1.x/getting-started.md | 2 +- .../main/scala/example/WebSocketEcho.scala | 1 - .../scala/example/WebSocketSimpleClient.scala | 7 +- .../src/main/scala/zhttp/http/Headers.scala | 2 - zio-http/src/main/scala/zhttp/http/Http.scala | 5 -- .../main/scala/zhttp/http/Middleware.scala | 20 +---- .../scala/zhttp/http/middleware/Web.scala | 13 ++- .../src/main/scala/zhttp/service/Client.scala | 10 +-- .../zhttp/service/WebSocketAppHandler.scala | 2 +- .../handlers/ServerResponseHandler.scala | 9 --- .../zhttp/http/EncodeClientRequestSpec.scala | 38 ++++----- .../zhttp/http/GetBodyAsStringSpec.scala | 6 +- .../scala/zhttp/http/MiddlewareSpec.scala | 72 ++++++++--------- .../test/scala/zhttp/http/ResponseSpec.scala | 2 +- .../test/scala/zhttp/http/SchemeSpec.scala | 6 +- .../zhttp/http/middleware/AuthSpec.scala | 6 +- .../scala/zhttp/http/middleware/WebSpec.scala | 80 +++++++++---------- .../scala/zhttp/internal/DynamicServer.scala | 35 ++++---- .../test/scala/zhttp/internal/HttpGen.scala | 2 +- .../scala/zhttp/service/ClientHttpsSpec.scala | 19 ++--- .../test/scala/zhttp/service/ClientSpec.scala | 2 +- .../scala/zhttp/service/KeepAliveSpec.scala | 10 +-- .../test/scala/zhttp/service/ServerSpec.scala | 26 +++--- .../test/scala/zhttp/socket/SocketSpec.scala | 7 +- 26 files changed, 159 insertions(+), 227 deletions(-) diff --git a/docs/website/docs/getting-started.md b/docs/website/docs/getting-started.md index e3a09048b8..0524799b71 100644 --- a/docs/website/docs/getting-started.md +++ b/docs/website/docs/getting-started.md @@ -77,7 +77,7 @@ import zhttp.http._ object Spec extends DefaultRunnableSpec { def spec = suite("http")( - testM("should be ok") { + test("should be ok") { val app = Http.ok val req = Request() assertM(app(req))(equalTo(Response.ok)) // an apply method is added via `zhttp.test` package diff --git a/docs/website/docs/v1.x/dsl/http/index.md b/docs/website/docs/v1.x/dsl/http/index.md index 2a0cc6ce65..653bfdc041 100644 --- a/docs/website/docs/v1.x/dsl/http/index.md +++ b/docs/website/docs/v1.x/dsl/http/index.md @@ -226,7 +226,7 @@ The below snippet tests an app that takes `Int` as input and responds by adding object Spec extends DefaultRunnableSpec { def spec = suite("http")( - testM("1 + 1 = 2") { + test("1 + 1 = 2") { val app: Http[Any, Nothing, Int, Int] = Http.fromFunction[Int](_ + 1) assertM(app(1))(equalTo(2)) } diff --git a/docs/website/docs/v1.x/getting-started.md b/docs/website/docs/v1.x/getting-started.md index 47b1b1c188..74968332a9 100644 --- a/docs/website/docs/v1.x/getting-started.md +++ b/docs/website/docs/v1.x/getting-started.md @@ -108,7 +108,7 @@ import zhttp.http._ object Spec extends DefaultRunnableSpec { def spec = suite("http")( - testM("should be ok") { + test("should be ok") { val app = Http.ok val req = Request() assertM(app(req))(equalTo(Response.ok)) diff --git a/example/src/main/scala/example/WebSocketEcho.scala b/example/src/main/scala/example/WebSocketEcho.scala index 6c75ae5677..f698c69d0b 100644 --- a/example/src/main/scala/example/WebSocketEcho.scala +++ b/example/src/main/scala/example/WebSocketEcho.scala @@ -5,7 +5,6 @@ import zhttp.service.Server import zhttp.socket.{Socket, WebSocketFrame} import zio._ import zio.stream.ZStream -import zio.{App, ExitCode, Schedule, UIO, URIO} object WebSocketEcho extends ZIOAppDefault { private val socket = diff --git a/example/src/main/scala/example/WebSocketSimpleClient.scala b/example/src/main/scala/example/WebSocketSimpleClient.scala index 2a669c83c5..3ca1ed11c2 100644 --- a/example/src/main/scala/example/WebSocketSimpleClient.scala +++ b/example/src/main/scala/example/WebSocketSimpleClient.scala @@ -5,7 +5,7 @@ import zhttp.socket.{Socket, WebSocketFrame} import zio._ import zio.stream.ZStream -object WebSocketSimpleClient extends zio.App { +object WebSocketSimpleClient extends ZIOAppDefault { // Setup client envs val env = EventLoopGroup.auto() ++ ChannelFactory.auto @@ -20,7 +20,6 @@ object WebSocketSimpleClient extends zio.App { .toSocketApp .connect(url) - override def run(args: List[String]): URIO[ZEnv, ExitCode] = { - app.exitCode.provideCustomLayer(env) - } + val run = app.exitCode.provideCustomLayer(env) + } diff --git a/zio-http/src/main/scala/zhttp/http/Headers.scala b/zio-http/src/main/scala/zhttp/http/Headers.scala index 33dd701a87..92c9ac5eb5 100644 --- a/zio-http/src/main/scala/zhttp/http/Headers.scala +++ b/zio-http/src/main/scala/zhttp/http/Headers.scala @@ -30,8 +30,6 @@ final case class Headers(toChunk: Chunk[Header]) extends HeaderExtension[Headers def toList: List[(String, String)] = toChunk.map { case (name, value) => (name.toString, value.toString) }.toList - def modify(f: Header => Header): Headers = Headers(toChunk.map(f(_))) - override def updateHeaders(update: Headers => Headers): Headers = update(self) def when(cond: Boolean): Headers = if (cond) self else Headers.empty diff --git a/zio-http/src/main/scala/zhttp/http/Http.scala b/zio-http/src/main/scala/zhttp/http/Http.scala index 04ff15398f..462c7a79b5 100644 --- a/zio-http/src/main/scala/zhttp/http/Http.scala +++ b/zio-http/src/main/scala/zhttp/http/Http.scala @@ -567,11 +567,6 @@ object Http { */ def fromZIO[R, E, B](effect: ZIO[R, E, B]): Http[R, E, Any, B] = Http.fromFunctionZIO(_ => effect) - /** - * Converts a ZIO to an Http type - */ - def fromZIO[R, E, B](effect: ZIO[R, E, B]): Http[R, E, Any, B] = Http.fromFunctionZIO(_ => effect) - /** * Creates an HTTP app which always responds with the provided Html page. */ diff --git a/zio-http/src/main/scala/zhttp/http/Middleware.scala b/zio-http/src/main/scala/zhttp/http/Middleware.scala index 3f2760f799..74702043f9 100644 --- a/zio-http/src/main/scala/zhttp/http/Middleware.scala +++ b/zio-http/src/main/scala/zhttp/http/Middleware.scala @@ -1,10 +1,7 @@ package zhttp.http -import io.netty.util.AsciiString.contentEqualsIgnoreCase import zhttp.http.middleware.Web -import zio.clock.Clock -import zio.duration.Duration -import zio.{UIO, ZIO} +import zio._ /** * Middlewares are essentially transformations that one can apply on any Http to @@ -122,12 +119,6 @@ trait Middleware[-R, +E, +AIn, -BIn, -AOut, +BOut] { self => final def map[BOut0](f: BOut => BOut0): Middleware[R, E, AIn, BIn, AOut, BOut0] = self.flatMap(b => Middleware.succeed(f(b))) - /** - * Modifies the provided list of headers to the updated list of headers - */ - def modifyHeaders(f: PartialFunction[Header, Header]): Middleware[Any, Nothing] = - patch((_, _) => Patch.updateHeaders(_.modify(f))) - /** * Transforms the output type of the current middleware using effect function. */ @@ -199,15 +190,6 @@ object Middleware extends Web { */ def collect[A]: PartialCollect[A] = new PartialCollect[A](()) - /** - * Creates a middleware for signing cookies - */ - def signCookies(secret: String): Middleware[Any, Nothing] = - modifyHeaders { - case h if contentEqualsIgnoreCase(h._1, HeaderNames.setCookie) => - (HeaderNames.setCookie, Cookie.decodeResponseCookie(h._2.toString).get.sign(secret).encode) - } - /** * Creates a middleware using specified effect function */ diff --git a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala index e828bb4c26..ebe30d42e8 100644 --- a/zio-http/src/main/scala/zhttp/http/middleware/Web.scala +++ b/zio-http/src/main/scala/zhttp/http/middleware/Web.scala @@ -3,10 +3,7 @@ package zhttp.http.middleware import zhttp.http._ import zhttp.http.headers.HeaderModifier import zhttp.http.middleware.Web.{PartialInterceptPatch, PartialInterceptZIOPatch} -import zio.clock.Clock -import zio.console.Console -import zio.duration.Duration -import zio.{UIO, ZIO, clock, console} +import zio._ import java.io.IOException @@ -35,12 +32,12 @@ private[zhttp] trait Web extends Cors with Csrf with Auth with HeaderModifier[Ht * Add log status, method, url and time taken from req to res */ final def debug: HttpMiddleware[Console with Clock, IOException] = - interceptZIOPatch(req => zio.clock.nanoTime.map(start => (req.method, req.url, start))) { + interceptZIOPatch(req => Clock.nanoTime.map(start => (req.method, req.url, start))) { case (response, (method, url, start)) => for { - end <- clock.nanoTime - _ <- console - .putStrLn(s"${response.status.asJava.code()} ${method} ${url.encode} ${(end - start) / 1000000}ms") + end <- Clock.nanoTime + _ <- Console + .printLine(s"${response.status.asJava.code()} ${method} ${url.encode} ${(end - start) / 1000000}ms") .mapError(Option(_)) } yield Patch.empty } diff --git a/zio-http/src/main/scala/zhttp/service/Client.scala b/zio-http/src/main/scala/zhttp/service/Client.scala index 65466a3b1c..08aa55b6a2 100644 --- a/zio-http/src/main/scala/zhttp/service/Client.scala +++ b/zio-http/src/main/scala/zhttp/service/Client.scala @@ -48,7 +48,7 @@ final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el url, Method.GET, headers, - attribute = Client.Attribute(socketApp = Some(socketApp.provide(env)), ssl = Some(sslOptions)), + attribute = Client.Attribute(socketApp = Some(socketApp.provideEnvironment(env)), ssl = Some(sslOptions)), ), ) } yield res @@ -125,10 +125,10 @@ final case class Client[R](rtm: HttpRuntime[R], cf: JChannelFactory[Channel], el } object Client { - def make: ZIO[EventLoopGroup with ChannelFactory, Nothing, Client] = for { - cf <- ZIO.service[ChannelFactory] - el <- ZIO.service[EventLoopGroup] - zx <- HttpRuntime.default[Any] + def make[R]: ZIO[R with EventLoopGroup with ChannelFactory, Nothing, Client[R]] = for { + cf <- ZIO.service[JChannelFactory[Channel]] + el <- ZIO.service[JEventLoopGroup] + zx <- HttpRuntime.default[R] } yield service.Client(zx, cf, el) def request( diff --git a/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala index 09880f957d..d49b1d71e3 100644 --- a/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/WebSocketAppHandler.scala @@ -72,7 +72,7 @@ final class WebSocketAppHandler[R]( private def writeAndFlush(ctx: ChannelHandlerContext, stream: ZStream[R, Throwable, WebSocketFrame]): Unit = zExec.unsafeRun(ctx)( stream - .mapM(frame => ChannelFuture.unit(ctx.writeAndFlush(frame.toWebSocketFrame))) + .mapZIO(frame => ChannelFuture.unit(ctx.writeAndFlush(frame.toWebSocketFrame))) .runDrain, ) } diff --git a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala index ad06a6bf90..4352eeb9a9 100644 --- a/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/server/content/handlers/ServerResponseHandler.scala @@ -52,15 +52,6 @@ private[zhttp] case class ServerResponseHandler[R]( } } - /** - * Releases the FullHttpRequest safely. - */ - private def releaseRequest(jReq: FullHttpRequest): Unit = { - if (jReq.refCnt() > 0) { - jReq.release(jReq.refCnt()): Unit - } - } - /** * Checks if an encoded version of the response exists, uses it if it does. * Otherwise, it will return a fresh response. It will also set the server diff --git a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala index f534dbbe35..10aacf6c8d 100644 --- a/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/EncodeClientRequestSpec.scala @@ -3,7 +3,7 @@ package zhttp.http import io.netty.handler.codec.http.HttpHeaderNames import zhttp.internal.HttpGen import zhttp.service.{Client, EncodeClientRequest} -import zio.random.Random +import zio._ import zio.test.Assertion._ import zio.test._ @@ -30,63 +30,63 @@ object EncodeClientRequestSpec extends DefaultRunnableSpec with EncodeClientRequ ) def spec = suite("EncodeClientParams") { - testM("method") { - checkM(anyClientParam) { params => + test("method") { + check(anyClientParam) { params => val req = encode(params).map(_.method()) assertM(req)(equalTo(params.method.toJava)) } } + - testM("method on HttpData.File") { - checkM(HttpGen.clientParamsForFileHttpData()) { params => + test("method on HttpData.File") { + check(HttpGen.clientParamsForFileHttpData()) { params => val req = encode(params).map(_.method()) assertM(req)(equalTo(params.method.toJava)) } } + suite("uri") { - testM("uri") { - checkM(anyClientParam) { params => + test("uri") { + check(anyClientParam) { params => val req = encode(params).map(_.uri()) assertM(req)(equalTo(params.url.relative.encode)) } } + - testM("uri on HttpData.File") { - checkM(HttpGen.clientParamsForFileHttpData()) { params => + test("uri on HttpData.File") { + check(HttpGen.clientParamsForFileHttpData()) { params => val req = encode(params).map(_.uri()) assertM(req)(equalTo(params.url.relative.encode)) } } } + - testM("content-length") { - checkM(clientParamWithFiniteData(5)) { params => + test("content-length") { + check(clientParamWithFiniteData(5)) { params => val req = encode(params).map( _.headers().getInt(HttpHeaderNames.CONTENT_LENGTH).toLong, ) assertM(req)(equalTo(5L)) } } + - testM("host header") { - checkM(anyClientParam) { params => + test("host header") { + check(anyClientParam) { params => val req = encode(params).map(i => Option(i.headers().get(HttpHeaderNames.HOST))) assertM(req)(equalTo(params.url.host)) } } + - testM("host header when absolute url") { - checkM(clientParamWithAbsoluteUrl) { params => + test("host header when absolute url") { + check(clientParamWithAbsoluteUrl) { params => val req = encode(params) .map(i => Option(i.headers().get(HttpHeaderNames.HOST))) assertM(req)(equalTo(params.url.host)) } } + - testM("only one host header exists") { - checkM(clientParamWithAbsoluteUrl) { params => + test("only one host header exists") { + check(clientParamWithAbsoluteUrl) { params => val req = encode(params) .map(_.headers().getAll(HttpHeaderNames.HOST).size) assertM(req)(equalTo(1)) } } + - testM("http version") { - checkM(anyClientParam) { params => + test("http version") { + check(anyClientParam) { params => val req = encode(params).map(i => i.protocolVersion()) assertM(req)(equalTo(params.version.toJava)) } diff --git a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala index 1747aeaa33..a0b49ff06e 100644 --- a/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/GetBodyAsStringSpec.scala @@ -15,9 +15,9 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { Gen.fromIterable(List(UTF_8, UTF_16, UTF_16BE, UTF_16LE, US_ASCII, ISO_8859_1)) suite("binary chunk") { - testM("should map bytes according to charset given") { + test("should map bytes according to charset given") { - checkM(charsetGen) { charset => + check(charsetGen) { charset => val request = Client .ClientRequest( URL(!!), @@ -30,7 +30,7 @@ object GetBodyAsStringSpec extends DefaultRunnableSpec { assertM(encoded)(equalTo(expected)) } } + - testM("should map bytes to default utf-8 if no charset given") { + test("should map bytes to default utf-8 if no charset given") { val request = Client.ClientRequest(URL(!!), data = HttpData.BinaryChunk(Chunk.fromArray("abc".getBytes()))) val encoded = request.bodyAsString val expected = new String(Chunk.fromArray("abc".getBytes()).toArray, HTTP_CHARSET) diff --git a/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala b/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala index fb6a500bd0..fd10b2ac30 100644 --- a/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/MiddlewareSpec.scala @@ -1,30 +1,28 @@ package zhttp.http -import zio.duration._ import zio.test.Assertion._ -import zio.test.environment.{TestClock, TestConsole} -import zio.test.{DefaultRunnableSpec, assert, assertM} -import zio.{Ref, UIO, console} +import zio.test.{DefaultRunnableSpec, TestClock, TestConsole, assert, assertM} +import zio._ object MiddlewareSpec extends DefaultRunnableSpec with HExitAssertion { def spec = suite("Middleware") { val increment = Middleware.codec[Int, Int](decoder = a => Right(a + 1), encoder = b => Right(b + 1)) - testM("empty") { + test("empty") { val http = Http.empty val app = Middleware.identity(http) assertM(app(()).either)(isLeft(isNone)) } + - testM("constant") { + test("constant") { val mid = Middleware.fromHttp(Http.succeed("OK")) val app = Http.succeed(1) @@ mid assertM(app(()))(equalTo("OK")) } + - testM("as") { + test("as") { val mid = Middleware.fromHttp(Http.succeed("Not OK")).as("OK") val app = Http.succeed(1) @@ mid assertM(app(()))(equalTo("OK")) } + - testM("interceptZIO") { + test("interceptZIO") { for { ref <- Ref.make(0) mid = Middleware.interceptZIO[Int, Int](i => UIO(i * 10))((i, j) => ref.set(i + j)) @@ -33,44 +31,44 @@ object MiddlewareSpec extends DefaultRunnableSpec with HExitAssertion { i <- ref.get } yield assert(i)(equalTo(11)) } + - testM("orElse") { + test("orElse") { val mid = Middleware.fail("left") <> Middleware.fail("right") val app = Http.empty @@ mid assertM(app(()).flip)(isSome(equalTo("right"))) } + - testM("combine") { + test("combine") { val mid1 = increment val mid2 = increment val mid = mid1 andThen mid2 val app = Http.identity[Int] @@ mid assertM(app(0))(equalTo(4)) } + - testM("flatMap") { + test("flatMap") { val mid = increment.flatMap(i => Middleware.succeed(i + 1)) val app = Http.identity[Int] @@ mid assertM(app(0))(equalTo(3)) } + - testM("mapZIO") { + test("mapZIO") { val mid = increment.mapZIO(i => UIO(i + 1)) val app = Http.identity[Int] @@ mid assertM(app(0))(equalTo(3)) } + - testM("runBefore") { - val mid = Middleware.identity.runBefore(console.putStrLn("A")) - val app = Http.fromZIO(console.putStrLn("B")) @@ mid + test("runBefore") { + val mid = Middleware.identity.runBefore(Console.printLine("A")) + val app = Http.fromZIO(Console.printLine("B")) @@ mid assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n"))) } + - testM("runAfter") { - val mid = Middleware.identity.runAfter(console.putStrLn("B")) - val app = Http.fromZIO(console.putStrLn("A")) @@ mid + test("runAfter") { + val mid = Middleware.identity.runAfter(Console.printLine("B")) + val app = Http.fromZIO(Console.printLine("A")) @@ mid assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n"))) } + - testM("runBefore and runAfter") { - val mid = Middleware.identity.runBefore(console.putStrLn("A")).runAfter(console.putStrLn("C")) - val app = Http.fromZIO(console.putStrLn("B")) @@ mid + test("runBefore and runAfter") { + val mid = Middleware.identity.runBefore(Console.printLine("A")).runAfter(Console.printLine("C")) + val app = Http.fromZIO(Console.printLine("B")) @@ mid assertM(app(()) *> TestConsole.output)(equalTo(Vector("A\n", "B\n", "C\n"))) } + - testM("race") { + test("race") { val mid = Middleware.succeed('A').delay(2 second) race Middleware.succeed("B").delay(1 second) val app = Http.succeed(1) @@ mid assertM(app(()) <& TestClock.adjust(3 second))(equalTo("B")) @@ -80,11 +78,11 @@ object MiddlewareSpec extends DefaultRunnableSpec with HExitAssertion { isTrue = i => Middleware.succeed(i + 1), isFalse = i => Middleware.succeed(i - 1), ) - testM("isTrue") { + test("isTrue") { val app = Http.identity[Int] @@ mid assertM(app(10))(equalTo(11)) } + - testM("isFalse") { + test("isFalse") { val app = Http.identity[Int] @@ mid assertM(app(1))(equalTo(0)) } @@ -94,63 +92,63 @@ object MiddlewareSpec extends DefaultRunnableSpec with HExitAssertion { isTrue = i => Middleware.succeed(i + 1), isFalse = i => Middleware.succeed(i - 1), ) - testM("isTrue") { + test("isTrue") { val app = Http.identity[Int] @@ mid assertM(app(10))(equalTo(11)) } + - testM("isFalse") { + test("isFalse") { val app = Http.identity[Int] @@ mid assertM(app(1))(equalTo(0)) } } + suite("contramap") { val mid = Middleware.intercept[String, String](a => a + "Bar")((b, s) => b + s) - testM("contramap") { + test("contramap") { val app = Http.identity[String] @@ mid.contramap[Int] { i => s"${i}Foo" } assertM(app(0))(equalTo("0Foo0FooBar")) } + - testM("contramapZIO") { + test("contramapZIO") { val app = Http.identity[String] @@ mid.contramapZIO[Int] { i => UIO(s"${i}Foo") } assertM(app(0))(equalTo("0Foo0FooBar")) } } + suite("when") { val mid = Middleware.succeed(0) - testM("condition is true") { + test("condition is true") { val app = Http.identity[Int] @@ mid.when[Int](_ => true) assertM(app(10))(equalTo(0)) } + - testM("condition is false") { + test("condition is false") { val app = Http.identity[Int] @@ mid.when[Int](_ => false) assertM(app(1))(equalTo(1)) } } + suite("whenZIO") { val mid = Middleware.succeed(0) - testM("condition is true") { + test("condition is true") { val app = Http.identity[Int] @@ mid.whenZIO[Any, Nothing, Int](_ => UIO(true)) assertM(app(10))(equalTo(0)) } + - testM("condition is false") { + test("condition is false") { val app = Http.identity[Int] @@ mid.whenZIO[Any, Nothing, Int](_ => UIO(false)) assertM(app(1))(equalTo(1)) } } + suite("codec") { - testM("codec success") { + test("codec success") { val mid = Middleware.codec[String, Int](a => Right(a.toInt), b => Right(b.toString)) val app = Http.identity[Int] @@ mid assertM(app("1"))(equalTo("1")) } + - testM("decoder failure") { + test("decoder failure") { val mid = Middleware.codec[String, Int](a => Left(a), b => Right(b.toString)) val app = Http.identity[Int] @@ mid - assertM(app("a").run)(fails(anything)) + assertM(app("a").exit)(fails(anything)) } + - testM("encoder failure") { + test("encoder failure") { val mid = Middleware.codec[String, Int](a => Right(a.toInt), b => Left(b.toString)) val app = Http.identity[Int] @@ mid - assertM(app("1").run)(fails(anything)) + assertM(app("1").exit)(fails(anything)) } } } diff --git a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala index 47fc405dcf..fd488c0750 100644 --- a/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/ResponseSpec.scala @@ -32,7 +32,7 @@ object ResponseSpec extends DefaultRunnableSpec { }, ) + suite("toHttp")( - testM("should convert response to Http") { + test("should convert response to Http") { val http = Http(Response.ok) assertM(http(()))(equalTo(Response.ok)) }, diff --git a/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala b/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala index d757074d06..0c38d7ce4b 100644 --- a/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/SchemeSpec.scala @@ -7,17 +7,17 @@ import zio.test._ object SchemeSpec extends DefaultRunnableSpec { override def spec = suite("SchemeSpec") { - testM("string") { + test("string") { checkAll(HttpGen.scheme) { scheme => assertTrue(Scheme.decode(scheme.encode).get == scheme) } } + - testM("java http scheme") { + test("java http scheme") { checkAll(jHttpScheme) { jHttpScheme => assertTrue(Scheme.fromJScheme(jHttpScheme).flatMap(_.toJHttpScheme).get == jHttpScheme) } } + - testM("java websocket scheme") { + test("java websocket scheme") { checkAll(jWebSocketScheme) { jWebSocketScheme => assertTrue( Scheme.fromJScheme(jWebSocketScheme).flatMap(_.toJWebSocketScheme).get == jWebSocketScheme, diff --git a/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala index 965efc1dc9..827ed8df49 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/AuthSpec.scala @@ -12,15 +12,15 @@ object AuthSpec extends DefaultRunnableSpec with HttpAppTestExtensions { def spec = suite("AuthSpec") { suite("basicAuth") { - testM("HttpApp is accepted if the basic authentication succeeds") { + test("HttpApp is accepted if the basic authentication succeeds") { val app = (Http.ok @@ basicAuthM).status assertM(app(Request().addHeaders(basicHS)))(equalTo(Status.OK)) } + - testM("Uses forbidden app if the basic authentication fails") { + test("Uses forbidden app if the basic authentication fails") { val app = (Http.ok @@ basicAuthM).status assertM(app(Request().addHeaders(basicHF)))(equalTo(Status.FORBIDDEN)) } + - testM("Responses should have WWW-Authentication header if Basic Auth failed") { + test("Responses should have WWW-Authentication header if Basic Auth failed") { val app = Http.ok @@ basicAuthM header "WWW-AUTHENTICATE" assertM(app(Request().addHeaders(basicHF)))(isSome) } diff --git a/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala index c462668ff3..5c35409fec 100644 --- a/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala +++ b/zio-http/src/test/scala/zhttp/http/middleware/WebSpec.scala @@ -4,12 +4,10 @@ import zhttp.http.Middleware._ import zhttp.http._ import zhttp.internal.HttpAppTestExtensions import zio._ -import zio.duration._ import zio.test.Assertion._ import zio.test._ -import zio.test.environment.{TestClock, TestConsole} -object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { +object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { self => private val app = Http.collectZIO[Request] { case Method.GET -> !! / "health" => UIO(Response.ok).delay(1 second) } @@ -18,134 +16,134 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { def spec = suite("HttpMiddleware") { suite("headers suite") { - testM("addHeaders") { + test("addHeaders") { val middleware = addHeaders(Headers("KeyA", "ValueA") ++ Headers("KeyB", "ValueB")) val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) } + - testM("addHeader") { + test("addHeader") { val middleware = addHeader("KeyA", "ValueA") val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA")) } + - testM("updateHeaders") { + test("updateHeaders") { val middleware = updateHeaders(_ => Headers("KeyA", "ValueA")) val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA")) } + - testM("removeHeader") { + test("removeHeader") { val middleware = removeHeader("KeyA") val headers = (Http.succeed(Response.ok.setHeaders(Headers("KeyA", "ValueA"))) @@ middleware) header "KeyA" assertM(headers(Request()))(isNone) } } + suite("debug") { - testM("log status method url and time") { - val program = run(app @@ debug) *> TestConsole.output + test("log status method url and time") { + val program = runApp(app @@ debug) *> TestConsole.output assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) } + - testM("log 404 status method url and time") { - val program = run(Http.empty ++ Http.notFound @@ debug) *> TestConsole.output + test("log 404 status method url and time") { + val program = runApp(Http.empty ++ Http.notFound @@ debug) *> TestConsole.output assertM(program)(equalTo(Vector("404 GET /health 0ms\n"))) } } + suite("when") { - testM("condition is true") { - val program = run(app @@ debug.when(_ => true)) *> TestConsole.output + test("condition is true") { + val program = runApp(self.app @@ debug.when(_ => true)) *> TestConsole.output assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) } + - testM("condition is false") { - val log = run(app @@ debug.when(_ => false)) *> TestConsole.output + test("condition is false") { + val log = runApp(self.app @@ debug.when(_ => false)) *> TestConsole.output assertM(log)(equalTo(Vector())) } } + suite("whenZIO") { - testM("condition is true") { - val program = run(app @@ debug.whenZIO(_ => UIO(true))) *> TestConsole.output + test("condition is true") { + val program = runApp(self.app @@ debug.whenZIO(_ => UIO(true))) *> TestConsole.output assertM(program)(equalTo(Vector("200 GET /health 1000ms\n"))) } + - testM("condition is false") { - val log = run(app @@ debug.whenZIO(_ => UIO(false))) *> TestConsole.output + test("condition is false") { + val log = runApp(self.app @@ debug.whenZIO(_ => UIO(false))) *> TestConsole.output assertM(log)(equalTo(Vector())) } } + suite("race") { - testM("achieved") { - val program = run(app @@ timeout(5 seconds)).map(_.status) + test("achieved") { + val program = runApp(self.app @@ timeout(5 seconds)).map(_.status) assertM(program)(equalTo(Status.OK)) } + - testM("un-achieved") { - val program = run(app @@ timeout(500 millis)).map(_.status) + test("un-achieved") { + val program = runApp(self.app @@ timeout(500 millis)).map(_.status) assertM(program)(equalTo(Status.REQUEST_TIMEOUT)) } } + suite("combine") { - testM("before and after") { - val middleware = runBefore(console.putStrLn("A")) - val program = run(app @@ middleware) *> TestConsole.output + test("before and after") { + val middleware = runBefore(Console.printLine("A")) + val program = runApp(self.app @@ middleware) *> TestConsole.output assertM(program)(equalTo(Vector("A\n"))) } + - testM("add headers twice") { + test("add headers twice") { val middleware = addHeader("KeyA", "ValueA") ++ addHeader("KeyB", "ValueB") val headers = (Http.ok @@ middleware).headerValues assertM(headers(Request()))(contains("ValueA") && contains("ValueB")) } + - testM("add and remove header") { + test("add and remove header") { val middleware = addHeader("KeyA", "ValueA") ++ removeHeader("KeyA") val program = (Http.ok @@ middleware) header "KeyA" assertM(program(Request()))(isNone) } } + suite("ifRequestThenElseZIO") { - testM("if the condition is true take first") { + test("if the condition is true take first") { val app = (Http.ok @@ ifRequestThenElseZIO(condM(true))(midA, midB)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + - testM("if the condition is false take 2nd") { + test("if the condition is false take 2nd") { val app = (Http.ok @@ ifRequestThenElseZIO(condM(false))(midA, midB)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("B"))) } } + suite("ifRequestThenElse") { - testM("if the condition is true take first") { + test("if the condition is true take first") { val app = Http.ok @@ ifRequestThenElse(cond(true))(midA, midB) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + - testM("if the condition is false take 2nd") { + test("if the condition is false take 2nd") { val app = Http.ok @@ ifRequestThenElse(cond(false))(midA, midB) header "X-Custom" assertM(app(Request()))(isSome(equalTo("B"))) } } + suite("whenRequestZIO") { - testM("if the condition is true apply middleware") { + test("if the condition is true apply middleware") { val app = (Http.ok @@ whenRequestZIO(condM(true))(midA)) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + - testM("if the condition is false don't apply any middleware") { + test("if the condition is false don't apply any middleware") { val app = (Http.ok @@ whenRequestZIO(condM(false))(midA)) header "X-Custom" assertM(app(Request()))(isNone) } } + suite("whenRequest") { - testM("if the condition is true apple middleware") { + test("if the condition is true apple middleware") { val app = Http.ok @@ Middleware.whenRequest(cond(true))(midA) header "X-Custom" assertM(app(Request()))(isSome(equalTo("A"))) } + - testM("if the condition is false don't apply the middleware") { + test("if the condition is false don't apply the middleware") { val app = Http.ok @@ Middleware.whenRequest(cond(false))(midA) header "X-Custom" assertM(app(Request()))(isNone) } } + suite("cookie") { - testM("addCookie") { + test("addCookie") { val cookie = Cookie("test", "testValue") val app = (Http.ok @@ addCookie(cookie)).header("set-cookie") assertM(app(Request()))( equalTo(Some(cookie.encode)), ) } + - testM("addCookieM") { + test("addCookieM") { val cookie = Cookie("test", "testValue") val app = (Http.ok @@ addCookieZIO(UIO(cookie))).header("set-cookie") @@ -155,12 +153,12 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { } } + suite("signCookies") { - testM("should sign cookies") { + test("should sign cookies") { val cookie = Cookie("key", "value").withHttpOnly val app = Http.ok.withSetCookie(cookie) @@ signCookies("secret") header "set-cookie" assertM(app(Request()))(isSome(equalTo(cookie.sign("secret").encode))) } + - testM("sign cookies no cookie header") { + test("sign cookies no cookie header") { val app = (Http.ok.addHeader("keyA", "ValueA") @@ signCookies("secret")).headerValues assertM(app(Request()))(contains("ValueA")) } @@ -171,7 +169,7 @@ object WebSpec extends DefaultRunnableSpec with HttpAppTestExtensions { private def condM(flg: Boolean) = (_: Any) => UIO(flg) - private def run[R, E](app: HttpApp[R, E]): ZIO[TestClock with R, Option[E], Response] = { + private def runApp[R, E](app: HttpApp[R, E]): ZIO[TestClock with R, Option[E], Response] = { for { fib <- app { Request(url = URL(!! / "health")) }.fork _ <- TestClock.adjust(10 seconds) diff --git a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala index 8aeaa7a4a5..7b53762ab2 100644 --- a/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala +++ b/zio-http/src/test/scala/zhttp/internal/DynamicServer.scala @@ -1,22 +1,26 @@ package zhttp.internal import zhttp.http._ +import zhttp.internal.DynamicServer.{HttpEnv, Id} import zhttp.service.Server.Start import zio._ import java.util.UUID sealed trait DynamicServer { - def add(app: HttpApp[DynamicServer.HttpEnv, Throwable]): UIO[DynamicServer.Id] - def get(id: DynamicServer.Id): UIO[Option[HttpApp[DynamicServer.HttpEnv, Throwable]]] + def add(app: HttpApp[HttpEnv, Throwable]): UIO[Id] + def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] + + def port: ZIO[Any, Nothing, Int] + + def start: IO[Nothing, Start] + def setStart(n: Start): UIO[Boolean] - def getStart: IO[Nothing, Start] - def getPort: ZIO[Any, Nothing, Int] } object DynamicServer { type Id = String - type HttpEnv = DynamicServer with Console with Blocking + type HttpEnv = DynamicServer with Console type HttpAppTest = HttpApp[HttpEnv, Throwable] val APP_ID = "X-APP_ID" @@ -39,7 +43,7 @@ object DynamicServer { port.map(port => s"${scheme.encode}://localhost:$port") def deploy(app: HttpApp[HttpEnv, Throwable]): ZIO[DynamicServer, Nothing, String] = - ZIO.accessM[DynamicServer](_.get.add(app)) + ZIO.serviceWithZIO[DynamicServer](_.add(app)) def get(id: Id): ZIO[DynamicServer, Nothing, Option[HttpApp[HttpEnv, Throwable]]] = ZIO.serviceWithZIO[DynamicServer](_.get(id)) @@ -53,26 +57,15 @@ object DynamicServer { } yield new Live(ref, pr) }.toLayer - def port: ZIO[DynamicServer, Nothing, Int] = ZIO.accessM[DynamicServer](_.get.port) + def port: ZIO[DynamicServer, Nothing, Int] = ZIO.serviceWithZIO[DynamicServer](_.port) - def setStart(s: Start): ZIO[DynamicServer, Nothing, Boolean] = ZIO.accessM[DynamicServer](_.get.setStart(s)) + def setStart(s: Start): ZIO[DynamicServer, Nothing, Boolean] = ZIO.serviceWithZIO[DynamicServer](_.setStart(s)) - def start: ZIO[DynamicServer, Nothing, Start] = ZIO.accessM[DynamicServer](_.get.start) + def start: ZIO[DynamicServer, Nothing, Start] = ZIO.serviceWithZIO[DynamicServer](_.start) def wsURL: ZIO[DynamicServer, Nothing, String] = baseURL(Scheme.WS) - sealed trait Service { - def add(app: HttpApp[HttpEnv, Throwable]): UIO[Id] - def get(id: Id): UIO[Option[HttpApp[HttpEnv, Throwable]]] - - def port: ZIO[Any, Nothing, Int] - - def start: IO[Nothing, Start] - - def setStart(n: Start): UIO[Boolean] - } - - final class Live(ref: Ref[Map[Id, HttpApp[HttpEnv, Throwable]]], pr: Promise[Nothing, Start]) extends Service { + final class Live(ref: Ref[Map[Id, HttpApp[HttpEnv, Throwable]]], pr: Promise[Nothing, Start]) extends DynamicServer { def add(app: HttpApp[HttpEnv, Throwable]): UIO[Id] = for { id <- UIO(UUID.randomUUID().toString) _ <- ref.update(map => map + (id -> app)) diff --git a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala index 7d120ce211..005b6da1e3 100644 --- a/zio-http/src/test/scala/zhttp/internal/HttpGen.scala +++ b/zio-http/src/test/scala/zhttp/internal/HttpGen.scala @@ -45,7 +45,7 @@ object HttpGen { httpOnly <- Gen.boolean maxAge <- Gen.option(Gen.long) sameSite <- Gen.option(Gen.fromIterable(List(Cookie.SameSite.Strict, Cookie.SameSite.Lax))) - secret <- Gen.option(Gen.anyString) + secret <- Gen.option(Gen.string) } yield Cookie(name, content, expires, domain, path, secure, httpOnly, maxAge, sameSite, secret) def genAbsoluteLocation: Gen[Random with Sized, Location.Absolute] = for { diff --git a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala index 3d3882a97c..c175893f7b 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientHttpsSpec.scala @@ -30,19 +30,10 @@ object ClientHttpsSpec extends DefaultRunnableSpec { ClientSSLOptions.CustomSSL(SslContextBuilder.forClient().trustManager(trustManagerFactory).build()) override def spec = suite("Https Client request") { - test("should throw DecoderException for handshake failure") { - val actual = Client - .request( - "https://untrusted-root.badssl.com/", - sslOption, - ) - .exit - assertM(actual)(fails(isSubtype[DecoderException](anything))) + test("respond Ok") { + val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics") + assertM(actual)(anything) } + - test("respond Ok") { - val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics") - assertM(actual)(anything) - } + test("respond Ok with sslOption") { val actual = Client.request("https://sports.api.decathlon.com/groups/water-aerobics", ssl = sslOption) assertM(actual)(anything) @@ -56,13 +47,13 @@ object ClientHttpsSpec extends DefaultRunnableSpec { .map(_.status) assertM(actual)(equalTo(Status.BAD_REQUEST)) } + - testM("should throw DecoderException for handshake failure") { + test("should throw DecoderException for handshake failure") { val actual = Client .request( "https://untrusted-root.badssl.com/", ssl = sslOption, ) - .run + .exit assertM(actual)(fails(isSubtype[DecoderException](anything))) } }.provideCustomLayerShared(env) @@ timeout(30 seconds) @@ ignore diff --git a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala index f81d4b3d88..52cd47dee3 100644 --- a/zio-http/src/test/scala/zhttp/service/ClientSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ClientSpec.scala @@ -40,7 +40,7 @@ object ClientSpec extends HttpRunnableSpec { val responseContent = app.deploy.bodyAsString.run() assertM(responseContent)(containsString("user")) } + - testM("handle connection failure") { + test("handle connection failure") { val res = Client.request("http://localhost:1").either assertM(res)(isLeft(isSubtype[ConnectException](anything))) } diff --git a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala index 7dee9c3204..2750750008 100644 --- a/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/KeepAliveSpec.scala @@ -17,21 +17,21 @@ object KeepAliveSpec extends HttpRunnableSpec { def keepAliveSpec = suite("KeepAlive") { suite("Http 1.1") { - testM("without connection close") { + test("without connection close") { val res = app.deploy.headerValue(HeaderNames.connection).run() assertM(res)(isNone) } + - testM("with connection close") { + test("with connection close") { val res = app.deploy.headerValue(HeaderNames.connection).run(headers = connectionCloseHeader) assertM(res)(isSome(equalTo("close"))) } } + suite("Http 1.0") { - testM("without keep-alive") { + test("without keep-alive") { val res = app.deploy.headerValue(HeaderNames.connection).run(version = Version.Http_1_0) assertM(res)(isSome(equalTo("close"))) } + - testM("with keep-alive") { + test("with keep-alive") { val res = app.deploy .headerValue(HeaderNames.connection) .run(version = Version.Http_1_0, headers = keepAliveHeader) @@ -41,7 +41,7 @@ object KeepAliveSpec extends HttpRunnableSpec { } override def spec = { - suiteM("ServerConfigSpec") { + suite("ServerConfigSpec") { appKeepAliveEnabled.as(List(keepAliveSpec)).useNow }.provideCustomLayerShared(env) } diff --git a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala index 48f603688e..3bf1ab874f 100644 --- a/zio-http/src/test/scala/zhttp/service/ServerSpec.scala +++ b/zio-http/src/test/scala/zhttp/service/ServerSpec.scala @@ -171,24 +171,16 @@ object ServerSpec extends HttpRunnableSpec { val res = Http.fromStream(ZStream("a", "b", "c")).deploy.bodyAsString.run() assertM(res)(equalTo("abc")) } + - testM("echo streaming") { + test("echo streaming") { val res = Http .collectHttp[Request] { case req => - Http.fromStream(ZStream.fromEffect(req.body).flattenChunks) + Http.fromStream(ZStream.fromZIO(req.body).flattenChunks) } .deploy .bodyAsString .run(content = "abc") assertM(res)(equalTo("abc")) } + - test("echo streaming") { - val res = Http - .collectHttp[Request] { case req => - Http.fromStream(ZStream.fromZIO(req.getBody).flattenChunks) - } - .requestBodyAsString(content = "abc") - assertM(res)(equalTo("abc")) - } + test("file-streaming") { val path = getClass.getResource("/TestFile.txt").getPath val res = Http.fromStream(ZStream.fromPath(Paths.get(path))).deploy.bodyAsString.run() @@ -251,7 +243,7 @@ object ServerSpec extends HttpRunnableSpec { } override def spec = - suiteM("Server") { + suite("Server") { app.as(List(serverStartSpec, staticAppSpec, dynamicAppSpec, responseSpec, requestSpec, nonZIOSpec)).useNow }.provideCustomLayerShared(env) @@ timeout(30 seconds) @@ -280,20 +272,20 @@ object ServerSpec extends HttpRunnableSpec { } def nonZIOSpec = suite("NonZIOSpec") { - testM("200 response") { - checkAllM(HttpGen.method) { method => + test("200 response") { + checkAll(HttpGen.method) { method => val actual = status(method, !! / "HExitSuccess") assertM(actual)(equalTo(Status.OK)) } } + - testM("500 response") { - checkAllM(HttpGen.method) { method => + test("500 response") { + checkAll(HttpGen.method) { method => val actual = status(method, !! / "HExitFailure") assertM(actual)(equalTo(Status.INTERNAL_SERVER_ERROR)) } } + - testM("404 response ") { - checkAllM(HttpGen.method) { method => + test("404 response ") { + checkAll(HttpGen.method) { method => val actual = status(method, !! / "A") assertM(actual)(equalTo(Status.NOT_FOUND)) } diff --git a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala index f34054245a..e65256ecbd 100644 --- a/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala +++ b/zio-http/src/test/scala/zhttp/socket/SocketSpec.scala @@ -2,7 +2,6 @@ package zhttp.socket import zhttp.http.Status import zio._ -import zio.duration.durationInt import zio.stream.ZStream import zio.test.Assertion._ import zio.test.TestAspect.timeout @@ -59,13 +58,13 @@ object SocketSpec extends DefaultRunnableSpec { assertM(socketC.execute(1000).runCollect)(equalTo(Chunk(12))) } + - testM("echo") { + test("echo") { assertM(Socket.echo(1).runCollect)(equalTo(Chunk(1))) } + - testM("empty") { + test("empty") { assertM(Socket.empty(()).runCollect)(isEmpty) } + - testM("toHttp") { + test("toHttp") { val http = Socket.succeed(WebSocketFrame.ping).toHttp assertM(http(()).map(_.status))(equalTo(Status.SWITCHING_PROTOCOLS)) } From 92a8c3b17c694d9f5994065ab0eef486b04f82da Mon Sep 17 00:00:00 2001 From: amitsingh Date: Wed, 9 Feb 2022 20:24:00 +0530 Subject: [PATCH 93/95] use default runtime strategy --- zio-http/src/main/scala/zhttp/service/Server.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 955bf3cccd..6bfb8b18eb 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -218,7 +218,7 @@ object Server { for { channelFactory <- ZManaged.service[ServerChannelFactory] eventLoopGroup <- ZManaged.service[EventLoopGroup] - zExec <- HttpRuntime.sticky[R](eventLoopGroup).toManaged + zExec <- HttpRuntime.default[R].toManaged reqHandler = settings.app.compile(zExec, settings) respHandler = ServerResponseHandler(zExec, settings, ServerTimeGenerator.make) init = ServerChannelInitializer(zExec, settings, reqHandler, respHandler) From 0a7d1060c7f2511c5fe0ccc4cd76fb13e58b9077 Mon Sep 17 00:00:00 2001 From: amitsingh Date: Wed, 9 Feb 2022 20:44:42 +0530 Subject: [PATCH 94/95] use unsafeRunUninterruptible in client --- .../main/scala/zhttp/service/client/ClientInboundHandler.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala index 10f218e8b0..7bd9fb56d8 100644 --- a/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala +++ b/zio-http/src/main/scala/zhttp/service/client/ClientInboundHandler.scala @@ -28,7 +28,7 @@ final class ClientInboundHandler[R]( override def channelRead0(ctx: ChannelHandlerContext, msg: FullHttpResponse): Unit = { msg.touch("handlers.ClientInboundHandler-channelRead0") - zExec.unsafeRun(ctx)(promise.succeed(ClientResponse.unsafeFromJResponse(msg))) + zExec.unsafeRunUninterruptible(ctx)(promise.succeed(ClientResponse.unsafeFromJResponse(msg))) if (isWebSocket) { ctx.fireChannelRead(msg.retain()) ctx.pipeline().remove(ctx.name()): Unit From f732acf4adf3a0057e7192e6df9a2ae105cda9a0 Mon Sep 17 00:00:00 2001 From: amitsingh Date: Wed, 9 Feb 2022 20:52:19 +0530 Subject: [PATCH 95/95] use sticky on Server --- zio-http/src/main/scala/zhttp/service/HttpRuntime.scala | 2 +- zio-http/src/main/scala/zhttp/service/Server.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala index 8a121beb4c..6b4f6f5470 100644 --- a/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala +++ b/zio-http/src/main/scala/zhttp/service/HttpRuntime.scala @@ -52,7 +52,7 @@ final class HttpRuntime[+R](strategy: HttpRuntime.Strategy[R]) { case None => () case Some(_) => java.lang.System.err.println(cause.prettyPrint) } - ctx.close() + if (ctx.channel().isOpen) ctx.close() } } diff --git a/zio-http/src/main/scala/zhttp/service/Server.scala b/zio-http/src/main/scala/zhttp/service/Server.scala index 6bfb8b18eb..955bf3cccd 100644 --- a/zio-http/src/main/scala/zhttp/service/Server.scala +++ b/zio-http/src/main/scala/zhttp/service/Server.scala @@ -218,7 +218,7 @@ object Server { for { channelFactory <- ZManaged.service[ServerChannelFactory] eventLoopGroup <- ZManaged.service[EventLoopGroup] - zExec <- HttpRuntime.default[R].toManaged + zExec <- HttpRuntime.sticky[R](eventLoopGroup).toManaged reqHandler = settings.app.compile(zExec, settings) respHandler = ServerResponseHandler(zExec, settings, ServerTimeGenerator.make) init = ServerChannelInitializer(zExec, settings, reqHandler, respHandler)