summaryrefslogtreecommitdiffhomepage
path: root/cmd/tsconnect
diff options
context:
space:
mode:
authorNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
committerNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
commit0267fe83b200f1702a2fa0a395442c02a053fadb (patch)
tree63654c55225eeb834de59a5a0bc8d19033c6145b /cmd/tsconnect
parent87546a5edf6b6503a87eeb2d666baba57398a066 (diff)
downloadtailscale-1.78.0.tar.xz
tailscale-1.78.0.zip
VERSION.txt: this is v1.78.0v1.78.0
Signed-off-by: Nick Khyl <nickk@tailscale.com>
Diffstat (limited to 'cmd/tsconnect')
-rw-r--r--cmd/tsconnect/.gitignore6
-rw-r--r--cmd/tsconnect/README.md98
-rw-r--r--cmd/tsconnect/README.pkg.md6
-rw-r--r--cmd/tsconnect/build-pkg.go198
-rw-r--r--cmd/tsconnect/dev-pkg.go36
-rw-r--r--cmd/tsconnect/dev.go36
-rw-r--r--cmd/tsconnect/dist/placeholder4
-rw-r--r--cmd/tsconnect/index.html40
-rw-r--r--cmd/tsconnect/package.json50
-rw-r--r--cmd/tsconnect/package.json.tmpl32
-rw-r--r--cmd/tsconnect/serve.go288
-rw-r--r--cmd/tsconnect/src/app/app.tsx294
-rw-r--r--cmd/tsconnect/src/app/go-panic-display.tsx40
-rw-r--r--cmd/tsconnect/src/app/header.tsx74
-rw-r--r--cmd/tsconnect/src/app/index.css148
-rw-r--r--cmd/tsconnect/src/app/index.ts72
-rw-r--r--cmd/tsconnect/src/app/ssh.tsx314
-rw-r--r--cmd/tsconnect/src/app/url-display.tsx62
-rw-r--r--cmd/tsconnect/src/lib/js-state-store.ts26
-rw-r--r--cmd/tsconnect/src/pkg/pkg.css16
-rw-r--r--cmd/tsconnect/src/pkg/pkg.ts80
-rw-r--r--cmd/tsconnect/src/types/esbuild.d.ts28
-rw-r--r--cmd/tsconnect/src/types/wasm_js.d.ts206
-rw-r--r--cmd/tsconnect/tailwind.config.js16
-rw-r--r--cmd/tsconnect/tsconfig.json30
-rw-r--r--cmd/tsconnect/tsconnect.go142
-rw-r--r--cmd/tsconnect/yarn.lock1426
27 files changed, 1884 insertions, 1884 deletions
diff --git a/cmd/tsconnect/.gitignore b/cmd/tsconnect/.gitignore
index 13615d121..b791f8e64 100644
--- a/cmd/tsconnect/.gitignore
+++ b/cmd/tsconnect/.gitignore
@@ -1,3 +1,3 @@
-node_modules/
-/dist
-/pkg
+node_modules/
+/dist
+/pkg
diff --git a/cmd/tsconnect/README.md b/cmd/tsconnect/README.md
index 536cd7bbf..f518f932e 100644
--- a/cmd/tsconnect/README.md
+++ b/cmd/tsconnect/README.md
@@ -1,49 +1,49 @@
-# tsconnect
-
-The tsconnect command builds and serves the static site that is generated for
-the Tailscale Connect JS/WASM client.
-
-## Development
-
-To start the development server:
-
-```
-./tool/go run ./cmd/tsconnect dev
-```
-
-The site is served at http://localhost:9090/. JavaScript, CSS and Go `wasm` package changes can be picked up with a browser reload. Server-side Go changes require the server to be stopped and restarted. In development mode the state the Tailscale client state is stored in `sessionStorage` and will thus survive page reloads (but not the tab being closed).
-
-## Deployment
-
-To build the static assets necessary for serving, run:
-
-```
-./tool/go run ./cmd/tsconnect build
-```
-
-To serve them, run:
-
-```
-./tool/go run ./cmd/tsconnect serve
-```
-
-By default the build output is placed in the `dist/` directory and embedded in the binary, but this can be controlled by the `-distdir` flag. The `-addr` flag controls the interface and port that the serve listens on.
-
-# Library / NPM Package
-
-The client is also available as [an NPM package](https://www.npmjs.com/package/@tailscale/connect). To build it, run:
-
-```
-./tool/go run ./cmd/tsconnect build-pkg
-```
-
-That places the output in the `pkg/` directory, which may then be uploaded to a package registry (or installed from the file path directly).
-
-To do two-sided development (on both the NPM package and code that uses it), run:
-
-```
-./tool/go run ./cmd/tsconnect dev-pkg
-
-```
-
-This serves the module at http://localhost:9090/pkg/pkg.js and the generated wasm file at http://localhost:9090/pkg/main.wasm. The two files can be used as drop-in replacements for normal imports of the NPM module.
+# tsconnect
+
+The tsconnect command builds and serves the static site that is generated for
+the Tailscale Connect JS/WASM client.
+
+## Development
+
+To start the development server:
+
+```
+./tool/go run ./cmd/tsconnect dev
+```
+
+The site is served at http://localhost:9090/. JavaScript, CSS and Go `wasm` package changes can be picked up with a browser reload. Server-side Go changes require the server to be stopped and restarted. In development mode the state the Tailscale client state is stored in `sessionStorage` and will thus survive page reloads (but not the tab being closed).
+
+## Deployment
+
+To build the static assets necessary for serving, run:
+
+```
+./tool/go run ./cmd/tsconnect build
+```
+
+To serve them, run:
+
+```
+./tool/go run ./cmd/tsconnect serve
+```
+
+By default the build output is placed in the `dist/` directory and embedded in the binary, but this can be controlled by the `-distdir` flag. The `-addr` flag controls the interface and port that the serve listens on.
+
+# Library / NPM Package
+
+The client is also available as [an NPM package](https://www.npmjs.com/package/@tailscale/connect). To build it, run:
+
+```
+./tool/go run ./cmd/tsconnect build-pkg
+```
+
+That places the output in the `pkg/` directory, which may then be uploaded to a package registry (or installed from the file path directly).
+
+To do two-sided development (on both the NPM package and code that uses it), run:
+
+```
+./tool/go run ./cmd/tsconnect dev-pkg
+
+```
+
+This serves the module at http://localhost:9090/pkg/pkg.js and the generated wasm file at http://localhost:9090/pkg/main.wasm. The two files can be used as drop-in replacements for normal imports of the NPM module.
diff --git a/cmd/tsconnect/README.pkg.md b/cmd/tsconnect/README.pkg.md
index df8d66789..df5799578 100644
--- a/cmd/tsconnect/README.pkg.md
+++ b/cmd/tsconnect/README.pkg.md
@@ -1,3 +1,3 @@
-# @tailscale/connect
-
-NPM package that contains a WebAssembly-based Tailscale client, see [the `cmd/tsconnect` directory in the tailscale repo](https://github.com/tailscale/tailscale/tree/main/cmd/tsconnect#library--npm-package) for more details.
+# @tailscale/connect
+
+NPM package that contains a WebAssembly-based Tailscale client, see [the `cmd/tsconnect` directory in the tailscale repo](https://github.com/tailscale/tailscale/tree/main/cmd/tsconnect#library--npm-package) for more details.
diff --git a/cmd/tsconnect/build-pkg.go b/cmd/tsconnect/build-pkg.go
index 047504858..2b6cc9b1f 100644
--- a/cmd/tsconnect/build-pkg.go
+++ b/cmd/tsconnect/build-pkg.go
@@ -1,99 +1,99 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !plan9
-
-package main
-
-import (
- "encoding/json"
- "fmt"
- "log"
- "os"
- "path"
-
- "github.com/tailscale/hujson"
- "tailscale.com/util/precompress"
- "tailscale.com/version"
-)
-
-func runBuildPkg() {
- buildOptions, err := commonPkgSetup(prodMode)
- if err != nil {
- log.Fatalf("Cannot setup: %v", err)
- }
-
- log.Printf("Linting...\n")
- if err := runYarn("lint"); err != nil {
- log.Fatalf("Linting failed: %v", err)
- }
-
- if err := cleanDir(*pkgDir); err != nil {
- log.Fatalf("Cannot clean %s: %v", *pkgDir, err)
- }
-
- buildOptions.Write = true
- buildOptions.MinifyWhitespace = true
- buildOptions.MinifyIdentifiers = true
- buildOptions.MinifySyntax = true
-
- runEsbuild(*buildOptions)
-
- if err := precompressWasm(); err != nil {
- log.Fatalf("Could not pre-recompress wasm: %v", err)
- }
-
- log.Printf("Generating types...\n")
- if err := runYarn("pkg-types"); err != nil {
- log.Fatalf("Type generation failed: %v", err)
- }
-
- if err := updateVersion(); err != nil {
- log.Fatalf("Cannot update version: %v", err)
- }
-
- if err := copyReadme(); err != nil {
- log.Fatalf("Cannot copy readme: %v", err)
- }
-
- log.Printf("Built package version %s", version.Long())
-}
-
-func precompressWasm() error {
- log.Printf("Pre-compressing main.wasm...\n")
- return precompress.Precompress(path.Join(*pkgDir, "main.wasm"), precompress.Options{
- FastCompression: *fastCompression,
- })
-}
-
-func updateVersion() error {
- packageJSONBytes, err := os.ReadFile("package.json.tmpl")
- if err != nil {
- return fmt.Errorf("Could not read package.json: %w", err)
- }
-
- var packageJSON map[string]any
- packageJSONBytes, err = hujson.Standardize(packageJSONBytes)
- if err != nil {
- return fmt.Errorf("Could not standardize template package.json: %w", err)
- }
- if err := json.Unmarshal(packageJSONBytes, &packageJSON); err != nil {
- return fmt.Errorf("Could not unmarshal package.json: %w", err)
- }
- packageJSON["version"] = version.Long()
-
- packageJSONBytes, err = json.MarshalIndent(packageJSON, "", " ")
- if err != nil {
- return fmt.Errorf("Could not marshal package.json: %w", err)
- }
-
- return os.WriteFile(path.Join(*pkgDir, "package.json"), packageJSONBytes, 0644)
-}
-
-func copyReadme() error {
- readmeBytes, err := os.ReadFile("README.pkg.md")
- if err != nil {
- return fmt.Errorf("Could not read README.pkg.md: %w", err)
- }
- return os.WriteFile(path.Join(*pkgDir, "README.md"), readmeBytes, 0644)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !plan9
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "path"
+
+ "github.com/tailscale/hujson"
+ "tailscale.com/util/precompress"
+ "tailscale.com/version"
+)
+
+func runBuildPkg() {
+ buildOptions, err := commonPkgSetup(prodMode)
+ if err != nil {
+ log.Fatalf("Cannot setup: %v", err)
+ }
+
+ log.Printf("Linting...\n")
+ if err := runYarn("lint"); err != nil {
+ log.Fatalf("Linting failed: %v", err)
+ }
+
+ if err := cleanDir(*pkgDir); err != nil {
+ log.Fatalf("Cannot clean %s: %v", *pkgDir, err)
+ }
+
+ buildOptions.Write = true
+ buildOptions.MinifyWhitespace = true
+ buildOptions.MinifyIdentifiers = true
+ buildOptions.MinifySyntax = true
+
+ runEsbuild(*buildOptions)
+
+ if err := precompressWasm(); err != nil {
+ log.Fatalf("Could not pre-recompress wasm: %v", err)
+ }
+
+ log.Printf("Generating types...\n")
+ if err := runYarn("pkg-types"); err != nil {
+ log.Fatalf("Type generation failed: %v", err)
+ }
+
+ if err := updateVersion(); err != nil {
+ log.Fatalf("Cannot update version: %v", err)
+ }
+
+ if err := copyReadme(); err != nil {
+ log.Fatalf("Cannot copy readme: %v", err)
+ }
+
+ log.Printf("Built package version %s", version.Long())
+}
+
+func precompressWasm() error {
+ log.Printf("Pre-compressing main.wasm...\n")
+ return precompress.Precompress(path.Join(*pkgDir, "main.wasm"), precompress.Options{
+ FastCompression: *fastCompression,
+ })
+}
+
+func updateVersion() error {
+ packageJSONBytes, err := os.ReadFile("package.json.tmpl")
+ if err != nil {
+ return fmt.Errorf("Could not read package.json: %w", err)
+ }
+
+ var packageJSON map[string]any
+ packageJSONBytes, err = hujson.Standardize(packageJSONBytes)
+ if err != nil {
+ return fmt.Errorf("Could not standardize template package.json: %w", err)
+ }
+ if err := json.Unmarshal(packageJSONBytes, &packageJSON); err != nil {
+ return fmt.Errorf("Could not unmarshal package.json: %w", err)
+ }
+ packageJSON["version"] = version.Long()
+
+ packageJSONBytes, err = json.MarshalIndent(packageJSON, "", " ")
+ if err != nil {
+ return fmt.Errorf("Could not marshal package.json: %w", err)
+ }
+
+ return os.WriteFile(path.Join(*pkgDir, "package.json"), packageJSONBytes, 0644)
+}
+
+func copyReadme() error {
+ readmeBytes, err := os.ReadFile("README.pkg.md")
+ if err != nil {
+ return fmt.Errorf("Could not read README.pkg.md: %w", err)
+ }
+ return os.WriteFile(path.Join(*pkgDir, "README.md"), readmeBytes, 0644)
+}
diff --git a/cmd/tsconnect/dev-pkg.go b/cmd/tsconnect/dev-pkg.go
index de534c3b2..cb5ebf39e 100644
--- a/cmd/tsconnect/dev-pkg.go
+++ b/cmd/tsconnect/dev-pkg.go
@@ -1,18 +1,18 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !plan9
-
-package main
-
-import (
- "log"
-)
-
-func runDevPkg() {
- buildOptions, err := commonPkgSetup(devMode)
- if err != nil {
- log.Fatalf("Cannot setup: %v", err)
- }
- runEsbuildServe(*buildOptions)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !plan9
+
+package main
+
+import (
+ "log"
+)
+
+func runDevPkg() {
+ buildOptions, err := commonPkgSetup(devMode)
+ if err != nil {
+ log.Fatalf("Cannot setup: %v", err)
+ }
+ runEsbuildServe(*buildOptions)
+}
diff --git a/cmd/tsconnect/dev.go b/cmd/tsconnect/dev.go
index 87b10adaf..161eb3b86 100644
--- a/cmd/tsconnect/dev.go
+++ b/cmd/tsconnect/dev.go
@@ -1,18 +1,18 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !plan9
-
-package main
-
-import (
- "log"
-)
-
-func runDev() {
- buildOptions, err := commonSetup(devMode)
- if err != nil {
- log.Fatalf("Cannot setup: %v", err)
- }
- runEsbuildServe(*buildOptions)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !plan9
+
+package main
+
+import (
+ "log"
+)
+
+func runDev() {
+ buildOptions, err := commonSetup(devMode)
+ if err != nil {
+ log.Fatalf("Cannot setup: %v", err)
+ }
+ runEsbuildServe(*buildOptions)
+}
diff --git a/cmd/tsconnect/dist/placeholder b/cmd/tsconnect/dist/placeholder
index 4af99d997..dddaba4d7 100644
--- a/cmd/tsconnect/dist/placeholder
+++ b/cmd/tsconnect/dist/placeholder
@@ -1,2 +1,2 @@
-This is here to make sure the dist/ directory exists for the go:embed command
-in serve.go.
+This is here to make sure the dist/ directory exists for the go:embed command
+in serve.go.
diff --git a/cmd/tsconnect/index.html b/cmd/tsconnect/index.html
index 3db45fdef..39aa7571a 100644
--- a/cmd/tsconnect/index.html
+++ b/cmd/tsconnect/index.html
@@ -1,20 +1,20 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Tailscale Connect</title>
- <link rel="stylesheet" type="text/css" href="dist/index.css" />
- <script src="dist/index.js" defer></script>
- </head>
- <body class="flex flex-col h-screen overflow-hidden">
- <!-- Placeholder so that we don't have an empty page while the JS loads.
- It should match the markup generated by Header component. -->
- <div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2">
- <header class="container mx-auto px-4 flex flex-row items-center">
- <h1 class="text-3xl font-bold grow">Tailscale Connect</h1>
- <div class="text-gray-600">Loading…</div>
- </header>
- </div>
- </body>
-</html>
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Tailscale Connect</title>
+ <link rel="stylesheet" type="text/css" href="dist/index.css" />
+ <script src="dist/index.js" defer></script>
+ </head>
+ <body class="flex flex-col h-screen overflow-hidden">
+ <!-- Placeholder so that we don't have an empty page while the JS loads.
+ It should match the markup generated by Header component. -->
+ <div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2">
+ <header class="container mx-auto px-4 flex flex-row items-center">
+ <h1 class="text-3xl font-bold grow">Tailscale Connect</h1>
+ <div class="text-gray-600">Loading…</div>
+ </header>
+ </div>
+ </body>
+</html>
diff --git a/cmd/tsconnect/package.json b/cmd/tsconnect/package.json
index bf4eb7c09..8ea726cc6 100644
--- a/cmd/tsconnect/package.json
+++ b/cmd/tsconnect/package.json
@@ -1,25 +1,25 @@
-{
- "name": "tsconnect",
- "version": "0.0.1",
- "license": "BSD-3-Clause",
- "devDependencies": {
- "@types/golang-wasm-exec": "^1.15.0",
- "@types/qrcode": "^1.4.2",
- "dts-bundle-generator": "^6.12.0",
- "preact": "^10.10.0",
- "qrcode": "^1.5.0",
- "tailwindcss": "^3.1.6",
- "typescript": "^4.7.4",
- "xterm": "^5.1.0",
- "xterm-addon-fit": "^0.7.0",
- "xterm-addon-web-links": "^0.8.0"
- },
- "scripts": {
- "lint": "tsc --noEmit",
- "pkg-types": "dts-bundle-generator --inline-declare-global=true --no-banner -o pkg/pkg.d.ts src/pkg/pkg.ts"
- },
- "prettier": {
- "semi": false,
- "printWidth": 80
- }
-}
+{
+ "name": "tsconnect",
+ "version": "0.0.1",
+ "license": "BSD-3-Clause",
+ "devDependencies": {
+ "@types/golang-wasm-exec": "^1.15.0",
+ "@types/qrcode": "^1.4.2",
+ "dts-bundle-generator": "^6.12.0",
+ "preact": "^10.10.0",
+ "qrcode": "^1.5.0",
+ "tailwindcss": "^3.1.6",
+ "typescript": "^4.7.4",
+ "xterm": "^5.1.0",
+ "xterm-addon-fit": "^0.7.0",
+ "xterm-addon-web-links": "^0.8.0"
+ },
+ "scripts": {
+ "lint": "tsc --noEmit",
+ "pkg-types": "dts-bundle-generator --inline-declare-global=true --no-banner -o pkg/pkg.d.ts src/pkg/pkg.ts"
+ },
+ "prettier": {
+ "semi": false,
+ "printWidth": 80
+ }
+}
diff --git a/cmd/tsconnect/package.json.tmpl b/cmd/tsconnect/package.json.tmpl
index 404b896ea..0263bf481 100644
--- a/cmd/tsconnect/package.json.tmpl
+++ b/cmd/tsconnect/package.json.tmpl
@@ -1,16 +1,16 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Template for the package.json that is generated by the build-pkg command.
-// The version number will be replaced by the current Tailscale client version
-// number.
-{
- "author": "Tailscale Inc.",
- "description": "Tailscale Connect SDK",
- "license": "BSD-3-Clause",
- "name": "@tailscale/connect",
- "type": "module",
- "main": "./pkg.js",
- "types": "./pkg.d.ts",
- "version": "AUTO_GENERATED"
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Template for the package.json that is generated by the build-pkg command.
+// The version number will be replaced by the current Tailscale client version
+// number.
+{
+ "author": "Tailscale Inc.",
+ "description": "Tailscale Connect SDK",
+ "license": "BSD-3-Clause",
+ "name": "@tailscale/connect",
+ "type": "module",
+ "main": "./pkg.js",
+ "types": "./pkg.d.ts",
+ "version": "AUTO_GENERATED"
+}
diff --git a/cmd/tsconnect/serve.go b/cmd/tsconnect/serve.go
index d780bdd57..80844bea7 100644
--- a/cmd/tsconnect/serve.go
+++ b/cmd/tsconnect/serve.go
@@ -1,144 +1,144 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !plan9
-
-package main
-
-import (
- "bytes"
- "embed"
- "encoding/json"
- "fmt"
- "io"
- "io/fs"
- "log"
- "net/http"
- "os"
- "path"
- "time"
-
- "tailscale.com/tsweb"
- "tailscale.com/util/precompress"
-)
-
-//go:embed index.html
-var embeddedFS embed.FS
-
-//go:embed dist/*
-var embeddedDistFS embed.FS
-
-var serveStartTime = time.Now()
-
-func runServe() {
- mux := http.NewServeMux()
-
- var distFS fs.FS
- if *distDir == "./dist" {
- var err error
- distFS, err = fs.Sub(embeddedDistFS, "dist")
- if err != nil {
- log.Fatalf("Could not drop dist/ prefix from embedded FS: %v", err)
- }
- } else {
- distFS = os.DirFS(*distDir)
- }
-
- indexBytes, err := generateServeIndex(distFS)
- if err != nil {
- log.Fatalf("Could not generate index.html: %v", err)
- }
- mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- http.ServeContent(w, r, "index.html", serveStartTime, bytes.NewReader(indexBytes))
- }))
- mux.Handle("/dist/", http.StripPrefix("/dist/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- handleServeDist(w, r, distFS)
- })))
- tsweb.Debugger(mux)
-
- log.Printf("Listening on %s", *addr)
- err = http.ListenAndServe(*addr, mux)
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func generateServeIndex(distFS fs.FS) ([]byte, error) {
- log.Printf("Generating index.html...\n")
- rawIndexBytes, err := embeddedFS.ReadFile("index.html")
- if err != nil {
- return nil, fmt.Errorf("Could not read index.html: %w", err)
- }
-
- esbuildMetadataFile, err := distFS.Open("esbuild-metadata.json")
- if err != nil {
- return nil, fmt.Errorf("Could not open esbuild-metadata.json: %w", err)
- }
- defer esbuildMetadataFile.Close()
- esbuildMetadataBytes, err := io.ReadAll(esbuildMetadataFile)
- if err != nil {
- return nil, fmt.Errorf("Could not read esbuild-metadata.json: %w", err)
- }
- var esbuildMetadata EsbuildMetadata
- if err := json.Unmarshal(esbuildMetadataBytes, &esbuildMetadata); err != nil {
- return nil, fmt.Errorf("Could not parse esbuild-metadata.json: %w", err)
- }
- entryPointsToHashedDistPaths := make(map[string]string)
- mainWasmPath := ""
- for outputPath, output := range esbuildMetadata.Outputs {
- if output.EntryPoint != "" {
- entryPointsToHashedDistPaths[output.EntryPoint] = path.Join("dist", outputPath)
- }
- if path.Ext(outputPath) == ".wasm" {
- for input := range output.Inputs {
- if input == "src/main.wasm" {
- mainWasmPath = path.Join("dist", outputPath)
- break
- }
- }
- }
- }
-
- indexBytes := rawIndexBytes
- for entryPointPath, defaultDistPath := range entryPointsToDefaultDistPaths {
- hashedDistPath := entryPointsToHashedDistPaths[entryPointPath]
- if hashedDistPath != "" {
- indexBytes = bytes.ReplaceAll(indexBytes, []byte(defaultDistPath), []byte(hashedDistPath))
- }
- }
- if mainWasmPath != "" {
- mainWasmPrefetch := fmt.Sprintf("</title>\n<link rel='preload' as='fetch' crossorigin='anonymous' href='%s'>", mainWasmPath)
- indexBytes = bytes.ReplaceAll(indexBytes, []byte("</title>"), []byte(mainWasmPrefetch))
- }
-
- return indexBytes, nil
-}
-
-var entryPointsToDefaultDistPaths = map[string]string{
- "src/app/index.css": "dist/index.css",
- "src/app/index.ts": "dist/index.js",
-}
-
-func handleServeDist(w http.ResponseWriter, r *http.Request, distFS fs.FS) {
- path := r.URL.Path
- f, err := precompress.OpenPrecompressedFile(w, r, path, distFS)
- if err != nil {
- http.Error(w, err.Error(), http.StatusNotFound)
- return
- }
- defer f.Close()
-
- // fs.File does not claim to implement Seeker, but in practice it does.
- fSeeker, ok := f.(io.ReadSeeker)
- if !ok {
- http.Error(w, "Not seekable", http.StatusInternalServerError)
- return
- }
-
- // Aggressively cache static assets, since we cache-bust our assets with
- // hashed filenames.
- w.Header().Set("Cache-Control", "public, max-age=31535996")
- w.Header().Set("Vary", "Accept-Encoding")
-
- http.ServeContent(w, r, path, serveStartTime, fSeeker)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !plan9
+
+package main
+
+import (
+ "bytes"
+ "embed"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/fs"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "time"
+
+ "tailscale.com/tsweb"
+ "tailscale.com/util/precompress"
+)
+
+//go:embed index.html
+var embeddedFS embed.FS
+
+//go:embed dist/*
+var embeddedDistFS embed.FS
+
+var serveStartTime = time.Now()
+
+func runServe() {
+ mux := http.NewServeMux()
+
+ var distFS fs.FS
+ if *distDir == "./dist" {
+ var err error
+ distFS, err = fs.Sub(embeddedDistFS, "dist")
+ if err != nil {
+ log.Fatalf("Could not drop dist/ prefix from embedded FS: %v", err)
+ }
+ } else {
+ distFS = os.DirFS(*distDir)
+ }
+
+ indexBytes, err := generateServeIndex(distFS)
+ if err != nil {
+ log.Fatalf("Could not generate index.html: %v", err)
+ }
+ mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ http.ServeContent(w, r, "index.html", serveStartTime, bytes.NewReader(indexBytes))
+ }))
+ mux.Handle("/dist/", http.StripPrefix("/dist/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ handleServeDist(w, r, distFS)
+ })))
+ tsweb.Debugger(mux)
+
+ log.Printf("Listening on %s", *addr)
+ err = http.ListenAndServe(*addr, mux)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func generateServeIndex(distFS fs.FS) ([]byte, error) {
+ log.Printf("Generating index.html...\n")
+ rawIndexBytes, err := embeddedFS.ReadFile("index.html")
+ if err != nil {
+ return nil, fmt.Errorf("Could not read index.html: %w", err)
+ }
+
+ esbuildMetadataFile, err := distFS.Open("esbuild-metadata.json")
+ if err != nil {
+ return nil, fmt.Errorf("Could not open esbuild-metadata.json: %w", err)
+ }
+ defer esbuildMetadataFile.Close()
+ esbuildMetadataBytes, err := io.ReadAll(esbuildMetadataFile)
+ if err != nil {
+ return nil, fmt.Errorf("Could not read esbuild-metadata.json: %w", err)
+ }
+ var esbuildMetadata EsbuildMetadata
+ if err := json.Unmarshal(esbuildMetadataBytes, &esbuildMetadata); err != nil {
+ return nil, fmt.Errorf("Could not parse esbuild-metadata.json: %w", err)
+ }
+ entryPointsToHashedDistPaths := make(map[string]string)
+ mainWasmPath := ""
+ for outputPath, output := range esbuildMetadata.Outputs {
+ if output.EntryPoint != "" {
+ entryPointsToHashedDistPaths[output.EntryPoint] = path.Join("dist", outputPath)
+ }
+ if path.Ext(outputPath) == ".wasm" {
+ for input := range output.Inputs {
+ if input == "src/main.wasm" {
+ mainWasmPath = path.Join("dist", outputPath)
+ break
+ }
+ }
+ }
+ }
+
+ indexBytes := rawIndexBytes
+ for entryPointPath, defaultDistPath := range entryPointsToDefaultDistPaths {
+ hashedDistPath := entryPointsToHashedDistPaths[entryPointPath]
+ if hashedDistPath != "" {
+ indexBytes = bytes.ReplaceAll(indexBytes, []byte(defaultDistPath), []byte(hashedDistPath))
+ }
+ }
+ if mainWasmPath != "" {
+ mainWasmPrefetch := fmt.Sprintf("</title>\n<link rel='preload' as='fetch' crossorigin='anonymous' href='%s'>", mainWasmPath)
+ indexBytes = bytes.ReplaceAll(indexBytes, []byte("</title>"), []byte(mainWasmPrefetch))
+ }
+
+ return indexBytes, nil
+}
+
+var entryPointsToDefaultDistPaths = map[string]string{
+ "src/app/index.css": "dist/index.css",
+ "src/app/index.ts": "dist/index.js",
+}
+
+func handleServeDist(w http.ResponseWriter, r *http.Request, distFS fs.FS) {
+ path := r.URL.Path
+ f, err := precompress.OpenPrecompressedFile(w, r, path, distFS)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+ defer f.Close()
+
+ // fs.File does not claim to implement Seeker, but in practice it does.
+ fSeeker, ok := f.(io.ReadSeeker)
+ if !ok {
+ http.Error(w, "Not seekable", http.StatusInternalServerError)
+ return
+ }
+
+ // Aggressively cache static assets, since we cache-bust our assets with
+ // hashed filenames.
+ w.Header().Set("Cache-Control", "public, max-age=31535996")
+ w.Header().Set("Vary", "Accept-Encoding")
+
+ http.ServeContent(w, r, path, serveStartTime, fSeeker)
+}
diff --git a/cmd/tsconnect/src/app/app.tsx b/cmd/tsconnect/src/app/app.tsx
index ee538eaea..c0aa7a5e8 100644
--- a/cmd/tsconnect/src/app/app.tsx
+++ b/cmd/tsconnect/src/app/app.tsx
@@ -1,147 +1,147 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-import { render, Component } from "preact"
-import { URLDisplay } from "./url-display"
-import { Header } from "./header"
-import { GoPanicDisplay } from "./go-panic-display"
-import { SSH } from "./ssh"
-
-type AppState = {
- ipn?: IPN
- ipnState: IPNState
- netMap?: IPNNetMap
- browseToURL?: string
- goPanicError?: string
-}
-
-class App extends Component<{}, AppState> {
- state: AppState = { ipnState: "NoState" }
- #goPanicTimeout?: number
-
- render() {
- const { ipn, ipnState, goPanicError, netMap, browseToURL } = this.state
-
- let goPanicDisplay
- if (goPanicError) {
- goPanicDisplay = (
- <GoPanicDisplay error={goPanicError} dismiss={this.clearGoPanic} />
- )
- }
-
- let urlDisplay
- if (browseToURL) {
- urlDisplay = <URLDisplay url={browseToURL} />
- }
-
- let machineAuthInstructions
- if (ipnState === "NeedsMachineAuth") {
- machineAuthInstructions = (
- <div class="container mx-auto px-4 text-center">
- An administrator needs to approve this device.
- </div>
- )
- }
-
- const lockedOut = netMap?.lockedOut
- let lockedOutInstructions
- if (lockedOut) {
- lockedOutInstructions = (
- <div class="container mx-auto px-4 text-center space-y-4">
- <p>This instance of Tailscale Connect needs to be signed, due to
- {" "}<a href="https://tailscale.com/kb/1226/tailnet-lock/" class="link">tailnet lock</a>{" "}
- being enabled on this domain.
- </p>
-
- <p>
- Run the following command on a device with a trusted tailnet lock key:
- <pre>tailscale lock sign {netMap.self.nodeKey}</pre>
- </p>
- </div>
- )
- }
-
- let ssh
- if (ipn && ipnState === "Running" && netMap && !lockedOut) {
- ssh = <SSH netMap={netMap} ipn={ipn} />
- }
-
- return (
- <>
- <Header state={ipnState} ipn={ipn} />
- {goPanicDisplay}
- <div class="flex-grow flex flex-col justify-center overflow-hidden">
- {urlDisplay}
- {machineAuthInstructions}
- {lockedOutInstructions}
- {ssh}
- </div>
- </>
- )
- }
-
- runWithIPN(ipn: IPN) {
- this.setState({ ipn }, () => {
- ipn.run({
- notifyState: this.handleIPNState,
- notifyNetMap: this.handleNetMap,
- notifyBrowseToURL: this.handleBrowseToURL,
- notifyPanicRecover: this.handleGoPanic,
- })
- })
- }
-
- handleIPNState = (state: IPNState) => {
- const { ipn } = this.state
- this.setState({ ipnState: state })
- if (state === "NeedsLogin") {
- ipn?.login()
- } else if (["Running", "NeedsMachineAuth"].includes(state)) {
- this.setState({ browseToURL: undefined })
- }
- }
-
- handleNetMap = (netMapStr: string) => {
- const netMap = JSON.parse(netMapStr) as IPNNetMap
- if (DEBUG) {
- console.log("Received net map: " + JSON.stringify(netMap, null, 2))
- }
- this.setState({ netMap })
- }
-
- handleBrowseToURL = (url: string) => {
- if (this.state.ipnState === "Running") {
- // Ignore URL requests if we're already running -- it's most likely an
- // SSH check mode trigger and we already linkify the displayed URL
- // in the terminal.
- return
- }
- this.setState({ browseToURL: url })
- }
-
- handleGoPanic = (error: string) => {
- if (DEBUG) {
- console.error("Go panic", error)
- }
- this.setState({ goPanicError: error })
- if (this.#goPanicTimeout) {
- window.clearTimeout(this.#goPanicTimeout)
- }
- this.#goPanicTimeout = window.setTimeout(this.clearGoPanic, 10000)
- }
-
- clearGoPanic = () => {
- window.clearTimeout(this.#goPanicTimeout)
- this.#goPanicTimeout = undefined
- this.setState({ goPanicError: undefined })
- }
-}
-
-export function renderApp(): Promise<App> {
- return new Promise((resolve) => {
- render(
- <App ref={(app) => (app ? resolve(app) : undefined)} />,
- document.body
- )
- })
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+import { render, Component } from "preact"
+import { URLDisplay } from "./url-display"
+import { Header } from "./header"
+import { GoPanicDisplay } from "./go-panic-display"
+import { SSH } from "./ssh"
+
+type AppState = {
+ ipn?: IPN
+ ipnState: IPNState
+ netMap?: IPNNetMap
+ browseToURL?: string
+ goPanicError?: string
+}
+
+class App extends Component<{}, AppState> {
+ state: AppState = { ipnState: "NoState" }
+ #goPanicTimeout?: number
+
+ render() {
+ const { ipn, ipnState, goPanicError, netMap, browseToURL } = this.state
+
+ let goPanicDisplay
+ if (goPanicError) {
+ goPanicDisplay = (
+ <GoPanicDisplay error={goPanicError} dismiss={this.clearGoPanic} />
+ )
+ }
+
+ let urlDisplay
+ if (browseToURL) {
+ urlDisplay = <URLDisplay url={browseToURL} />
+ }
+
+ let machineAuthInstructions
+ if (ipnState === "NeedsMachineAuth") {
+ machineAuthInstructions = (
+ <div class="container mx-auto px-4 text-center">
+ An administrator needs to approve this device.
+ </div>
+ )
+ }
+
+ const lockedOut = netMap?.lockedOut
+ let lockedOutInstructions
+ if (lockedOut) {
+ lockedOutInstructions = (
+ <div class="container mx-auto px-4 text-center space-y-4">
+ <p>This instance of Tailscale Connect needs to be signed, due to
+ {" "}<a href="https://tailscale.com/kb/1226/tailnet-lock/" class="link">tailnet lock</a>{" "}
+ being enabled on this domain.
+ </p>
+
+ <p>
+ Run the following command on a device with a trusted tailnet lock key:
+ <pre>tailscale lock sign {netMap.self.nodeKey}</pre>
+ </p>
+ </div>
+ )
+ }
+
+ let ssh
+ if (ipn && ipnState === "Running" && netMap && !lockedOut) {
+ ssh = <SSH netMap={netMap} ipn={ipn} />
+ }
+
+ return (
+ <>
+ <Header state={ipnState} ipn={ipn} />
+ {goPanicDisplay}
+ <div class="flex-grow flex flex-col justify-center overflow-hidden">
+ {urlDisplay}
+ {machineAuthInstructions}
+ {lockedOutInstructions}
+ {ssh}
+ </div>
+ </>
+ )
+ }
+
+ runWithIPN(ipn: IPN) {
+ this.setState({ ipn }, () => {
+ ipn.run({
+ notifyState: this.handleIPNState,
+ notifyNetMap: this.handleNetMap,
+ notifyBrowseToURL: this.handleBrowseToURL,
+ notifyPanicRecover: this.handleGoPanic,
+ })
+ })
+ }
+
+ handleIPNState = (state: IPNState) => {
+ const { ipn } = this.state
+ this.setState({ ipnState: state })
+ if (state === "NeedsLogin") {
+ ipn?.login()
+ } else if (["Running", "NeedsMachineAuth"].includes(state)) {
+ this.setState({ browseToURL: undefined })
+ }
+ }
+
+ handleNetMap = (netMapStr: string) => {
+ const netMap = JSON.parse(netMapStr) as IPNNetMap
+ if (DEBUG) {
+ console.log("Received net map: " + JSON.stringify(netMap, null, 2))
+ }
+ this.setState({ netMap })
+ }
+
+ handleBrowseToURL = (url: string) => {
+ if (this.state.ipnState === "Running") {
+ // Ignore URL requests if we're already running -- it's most likely an
+ // SSH check mode trigger and we already linkify the displayed URL
+ // in the terminal.
+ return
+ }
+ this.setState({ browseToURL: url })
+ }
+
+ handleGoPanic = (error: string) => {
+ if (DEBUG) {
+ console.error("Go panic", error)
+ }
+ this.setState({ goPanicError: error })
+ if (this.#goPanicTimeout) {
+ window.clearTimeout(this.#goPanicTimeout)
+ }
+ this.#goPanicTimeout = window.setTimeout(this.clearGoPanic, 10000)
+ }
+
+ clearGoPanic = () => {
+ window.clearTimeout(this.#goPanicTimeout)
+ this.#goPanicTimeout = undefined
+ this.setState({ goPanicError: undefined })
+ }
+}
+
+export function renderApp(): Promise<App> {
+ return new Promise((resolve) => {
+ render(
+ <App ref={(app) => (app ? resolve(app) : undefined)} />,
+ document.body
+ )
+ })
+}
diff --git a/cmd/tsconnect/src/app/go-panic-display.tsx b/cmd/tsconnect/src/app/go-panic-display.tsx
index 5dd7095a2..aab35c4d5 100644
--- a/cmd/tsconnect/src/app/go-panic-display.tsx
+++ b/cmd/tsconnect/src/app/go-panic-display.tsx
@@ -1,20 +1,20 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-export function GoPanicDisplay({
- error,
- dismiss,
-}: {
- error: string
- dismiss: () => void
-}) {
- return (
- <div
- class="rounded bg-red-500 p-2 absolute top-2 right-2 text-white font-bold text-right cursor-pointer"
- onClick={dismiss}
- >
- Tailscale has encountered an error.
- <div class="text-sm font-normal">Click to reload</div>
- </div>
- )
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+export function GoPanicDisplay({
+ error,
+ dismiss,
+}: {
+ error: string
+ dismiss: () => void
+}) {
+ return (
+ <div
+ class="rounded bg-red-500 p-2 absolute top-2 right-2 text-white font-bold text-right cursor-pointer"
+ onClick={dismiss}
+ >
+ Tailscale has encountered an error.
+ <div class="text-sm font-normal">Click to reload</div>
+ </div>
+ )
+}
diff --git a/cmd/tsconnect/src/app/header.tsx b/cmd/tsconnect/src/app/header.tsx
index 099ff2f8c..8449f4563 100644
--- a/cmd/tsconnect/src/app/header.tsx
+++ b/cmd/tsconnect/src/app/header.tsx
@@ -1,37 +1,37 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-export function Header({ state, ipn }: { state: IPNState; ipn?: IPN }) {
- const stateText = STATE_LABELS[state]
-
- let logoutButton
- if (state === "Running") {
- logoutButton = (
- <button
- class="button bg-gray-500 border-gray-500 text-white hover:bg-gray-600 hover:border-gray-600 ml-2 font-bold"
- onClick={() => ipn?.logout()}
- >
- Logout
- </button>
- )
- }
- return (
- <div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2">
- <header class="container mx-auto px-4 flex flex-row items-center">
- <h1 class="text-3xl font-bold grow">Tailscale Connect</h1>
- <div class="text-gray-600">{stateText}</div>
- {logoutButton}
- </header>
- </div>
- )
-}
-
-const STATE_LABELS = {
- NoState: "Initializing…",
- InUseOtherUser: "In-use by another user",
- NeedsLogin: "Needs login",
- NeedsMachineAuth: "Needs approval",
- Stopped: "Stopped",
- Starting: "Starting…",
- Running: "Running",
-} as const
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+export function Header({ state, ipn }: { state: IPNState; ipn?: IPN }) {
+ const stateText = STATE_LABELS[state]
+
+ let logoutButton
+ if (state === "Running") {
+ logoutButton = (
+ <button
+ class="button bg-gray-500 border-gray-500 text-white hover:bg-gray-600 hover:border-gray-600 ml-2 font-bold"
+ onClick={() => ipn?.logout()}
+ >
+ Logout
+ </button>
+ )
+ }
+ return (
+ <div class="bg-gray-100 border-b border-gray-200 pt-4 pb-2">
+ <header class="container mx-auto px-4 flex flex-row items-center">
+ <h1 class="text-3xl font-bold grow">Tailscale Connect</h1>
+ <div class="text-gray-600">{stateText}</div>
+ {logoutButton}
+ </header>
+ </div>
+ )
+}
+
+const STATE_LABELS = {
+ NoState: "Initializing…",
+ InUseOtherUser: "In-use by another user",
+ NeedsLogin: "Needs login",
+ NeedsMachineAuth: "Needs approval",
+ Stopped: "Stopped",
+ Starting: "Starting…",
+ Running: "Running",
+} as const
diff --git a/cmd/tsconnect/src/app/index.css b/cmd/tsconnect/src/app/index.css
index 751b313d9..848b83d12 100644
--- a/cmd/tsconnect/src/app/index.css
+++ b/cmd/tsconnect/src/app/index.css
@@ -1,74 +1,74 @@
-/* Copyright (c) Tailscale Inc & AUTHORS */
-/* SPDX-License-Identifier: BSD-3-Clause */
-
-@import "xterm/css/xterm.css";
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-.link {
- @apply text-blue-600;
-}
-
-.link:hover {
- @apply underline;
-}
-
-.button {
- @apply font-medium py-1 px-2 rounded-md border border-transparent text-center cursor-pointer;
- transition-property: background-color, border-color, color, box-shadow;
- transition-duration: 120ms;
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
- min-width: 80px;
-}
-.button:focus {
- @apply outline-none ring;
-}
-.button:disabled {
- @apply pointer-events-none select-none;
-}
-
-.input {
- @apply appearance-none leading-tight rounded-md bg-white border border-gray-300 hover:border-gray-400 transition-colors px-3;
- height: 2.375rem;
-}
-
-.input::placeholder {
- @apply text-gray-400;
-}
-
-.input:disabled {
- @apply border-gray-200;
- @apply bg-gray-50;
- @apply cursor-not-allowed;
-}
-
-.input:focus {
- @apply outline-none ring border-transparent;
-}
-
-.select {
- @apply appearance-none py-2 px-3 leading-tight rounded-md bg-white border border-gray-300;
-}
-
-.select-with-arrow {
- @apply relative;
-}
-
-.select-with-arrow .select {
- width: 100%;
-}
-
-.select-with-arrow::after {
- @apply absolute;
- content: "";
- top: 50%;
- right: 0.5rem;
- transform: translate(-0.3em, -0.15em);
- width: 0.6em;
- height: 0.4em;
- opacity: 0.6;
- background-color: currentColor;
- clip-path: polygon(100% 0%, 0 0%, 50% 100%);
-}
+/* Copyright (c) Tailscale Inc & AUTHORS */
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+@import "xterm/css/xterm.css";
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+.link {
+ @apply text-blue-600;
+}
+
+.link:hover {
+ @apply underline;
+}
+
+.button {
+ @apply font-medium py-1 px-2 rounded-md border border-transparent text-center cursor-pointer;
+ transition-property: background-color, border-color, color, box-shadow;
+ transition-duration: 120ms;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
+ min-width: 80px;
+}
+.button:focus {
+ @apply outline-none ring;
+}
+.button:disabled {
+ @apply pointer-events-none select-none;
+}
+
+.input {
+ @apply appearance-none leading-tight rounded-md bg-white border border-gray-300 hover:border-gray-400 transition-colors px-3;
+ height: 2.375rem;
+}
+
+.input::placeholder {
+ @apply text-gray-400;
+}
+
+.input:disabled {
+ @apply border-gray-200;
+ @apply bg-gray-50;
+ @apply cursor-not-allowed;
+}
+
+.input:focus {
+ @apply outline-none ring border-transparent;
+}
+
+.select {
+ @apply appearance-none py-2 px-3 leading-tight rounded-md bg-white border border-gray-300;
+}
+
+.select-with-arrow {
+ @apply relative;
+}
+
+.select-with-arrow .select {
+ width: 100%;
+}
+
+.select-with-arrow::after {
+ @apply absolute;
+ content: "";
+ top: 50%;
+ right: 0.5rem;
+ transform: translate(-0.3em, -0.15em);
+ width: 0.6em;
+ height: 0.4em;
+ opacity: 0.6;
+ background-color: currentColor;
+ clip-path: polygon(100% 0%, 0 0%, 50% 100%);
+}
diff --git a/cmd/tsconnect/src/app/index.ts b/cmd/tsconnect/src/app/index.ts
index 24ca45439..1432188ae 100644
--- a/cmd/tsconnect/src/app/index.ts
+++ b/cmd/tsconnect/src/app/index.ts
@@ -1,36 +1,36 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-import "../wasm_exec"
-import wasmUrl from "./main.wasm"
-import { sessionStateStorage } from "../lib/js-state-store"
-import { renderApp } from "./app"
-
-async function main() {
- const app = await renderApp()
- const go = new Go()
- const wasmInstance = await WebAssembly.instantiateStreaming(
- fetch(`./dist/${wasmUrl}`),
- go.importObject
- )
- // The Go process should never exit, if it does then it's an unhandled panic.
- go.run(wasmInstance.instance).then(() =>
- app.handleGoPanic("Unexpected shutdown")
- )
-
- const params = new URLSearchParams(window.location.search)
- const authKey = params.get("authkey") ?? undefined
-
- const ipn = newIPN({
- // Persist IPN state in sessionStorage in development, so that we don't need
- // to re-authorize every time we reload the page.
- stateStorage: DEBUG ? sessionStateStorage : undefined,
- // authKey allows for an auth key to be
- // specified as a url param which automatically
- // authorizes the client for use.
- authKey: DEBUG ? authKey : undefined,
- })
- app.runWithIPN(ipn)
-}
-
-main()
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+import "../wasm_exec"
+import wasmUrl from "./main.wasm"
+import { sessionStateStorage } from "../lib/js-state-store"
+import { renderApp } from "./app"
+
+async function main() {
+ const app = await renderApp()
+ const go = new Go()
+ const wasmInstance = await WebAssembly.instantiateStreaming(
+ fetch(`./dist/${wasmUrl}`),
+ go.importObject
+ )
+ // The Go process should never exit, if it does then it's an unhandled panic.
+ go.run(wasmInstance.instance).then(() =>
+ app.handleGoPanic("Unexpected shutdown")
+ )
+
+ const params = new URLSearchParams(window.location.search)
+ const authKey = params.get("authkey") ?? undefined
+
+ const ipn = newIPN({
+ // Persist IPN state in sessionStorage in development, so that we don't need
+ // to re-authorize every time we reload the page.
+ stateStorage: DEBUG ? sessionStateStorage : undefined,
+ // authKey allows for an auth key to be
+ // specified as a url param which automatically
+ // authorizes the client for use.
+ authKey: DEBUG ? authKey : undefined,
+ })
+ app.runWithIPN(ipn)
+}
+
+main()
diff --git a/cmd/tsconnect/src/app/ssh.tsx b/cmd/tsconnect/src/app/ssh.tsx
index df81745bd..1534fd5db 100644
--- a/cmd/tsconnect/src/app/ssh.tsx
+++ b/cmd/tsconnect/src/app/ssh.tsx
@@ -1,157 +1,157 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-import { useState, useCallback, useMemo, useEffect, useRef } from "preact/hooks"
-import { createPortal } from "preact/compat"
-import type { VNode } from "preact"
-import { runSSHSession, SSHSessionDef } from "../lib/ssh"
-
-export function SSH({ netMap, ipn }: { netMap: IPNNetMap; ipn: IPN }) {
- const [sshSessionDef, setSSHSessionDef] = useState<SSHFormSessionDef | null>(
- null
- )
- const clearSSHSessionDef = useCallback(() => setSSHSessionDef(null), [])
- if (sshSessionDef) {
- const sshSession = (
- <SSHSession def={sshSessionDef} ipn={ipn} onDone={clearSSHSessionDef} />
- )
- if (sshSessionDef.newWindow) {
- return <NewWindow close={clearSSHSessionDef}>{sshSession}</NewWindow>
- }
- return sshSession
- }
- const sshPeers = netMap.peers.filter(
- (p) => p.tailscaleSSHEnabled && p.online !== false
- )
-
- if (sshPeers.length == 0) {
- return <NoSSHPeers />
- }
-
- return <SSHForm sshPeers={sshPeers} onSubmit={setSSHSessionDef} />
-}
-
-type SSHFormSessionDef = SSHSessionDef & { newWindow?: boolean }
-
-function SSHSession({
- def,
- ipn,
- onDone,
-}: {
- def: SSHSessionDef
- ipn: IPN
- onDone: () => void
-}) {
- const ref = useRef<HTMLDivElement>(null)
- useEffect(() => {
- if (ref.current) {
- runSSHSession(ref.current, def, ipn, {
- onConnectionProgress: (p) => console.log("Connection progress", p),
- onConnected() {},
- onError: (err) => console.error(err),
- onDone,
- })
- }
- }, [ref])
-
- return <div class="flex-grow bg-black p-2 overflow-hidden" ref={ref} />
-}
-
-function NoSSHPeers() {
- return (
- <div class="container mx-auto px-4 text-center">
- None of your machines have{" "}
- <a href="https://tailscale.com/kb/1193/tailscale-ssh/" class="link">
- Tailscale SSH
- </a>
- {" "}enabled. Give it a try!
- </div>
- )
-}
-
-function SSHForm({
- sshPeers,
- onSubmit,
-}: {
- sshPeers: IPNNetMapPeerNode[]
- onSubmit: (def: SSHFormSessionDef) => void
-}) {
- sshPeers = sshPeers.slice().sort((a, b) => a.name.localeCompare(b.name))
- const [username, setUsername] = useState("")
- const [hostname, setHostname] = useState(sshPeers[0].name)
- return (
- <form
- class="container mx-auto px-4 flex justify-center"
- onSubmit={(e) => {
- e.preventDefault()
- onSubmit({ username, hostname })
- }}
- >
- <input
- type="text"
- class="input username"
- placeholder="Username"
- onChange={(e) => setUsername(e.currentTarget.value)}
- />
- <div class="select-with-arrow mx-2">
- <select
- class="select"
- onChange={(e) => setHostname(e.currentTarget.value)}
- >
- {sshPeers.map((p) => (
- <option key={p.nodeKey}>{p.name.split(".")[0]}</option>
- ))}
- </select>
- </div>
- <input
- type="submit"
- class="button bg-green-500 border-green-500 text-white hover:bg-green-600 hover:border-green-600"
- value="SSH"
- onClick={(e) => {
- if (e.altKey) {
- e.preventDefault()
- e.stopPropagation()
- onSubmit({ username, hostname, newWindow: true })
- }
- }}
- />
- </form>
- )
-}
-
-const NewWindow = ({
- children,
- close,
-}: {
- children: VNode
- close: () => void
-}) => {
- const newWindow = useMemo(() => {
- const newWindow = window.open(undefined, undefined, "width=600,height=400")
- if (newWindow) {
- const containerNode = newWindow.document.createElement("div")
- containerNode.className = "h-screen flex flex-col overflow-hidden"
- newWindow.document.body.appendChild(containerNode)
-
- for (const linkNode of document.querySelectorAll(
- "head link[rel=stylesheet]"
- )) {
- const newLink = document.createElement("link")
- newLink.rel = "stylesheet"
- newLink.href = (linkNode as HTMLLinkElement).href
- newWindow.document.head.appendChild(newLink)
- }
- }
- return newWindow
- }, [])
- if (!newWindow) {
- console.error("Could not open window")
- return null
- }
- newWindow.onbeforeunload = () => {
- close()
- }
-
- useEffect(() => () => newWindow.close(), [])
- return createPortal(children, newWindow.document.body.lastChild as Element)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+import { useState, useCallback, useMemo, useEffect, useRef } from "preact/hooks"
+import { createPortal } from "preact/compat"
+import type { VNode } from "preact"
+import { runSSHSession, SSHSessionDef } from "../lib/ssh"
+
+export function SSH({ netMap, ipn }: { netMap: IPNNetMap; ipn: IPN }) {
+ const [sshSessionDef, setSSHSessionDef] = useState<SSHFormSessionDef | null>(
+ null
+ )
+ const clearSSHSessionDef = useCallback(() => setSSHSessionDef(null), [])
+ if (sshSessionDef) {
+ const sshSession = (
+ <SSHSession def={sshSessionDef} ipn={ipn} onDone={clearSSHSessionDef} />
+ )
+ if (sshSessionDef.newWindow) {
+ return <NewWindow close={clearSSHSessionDef}>{sshSession}</NewWindow>
+ }
+ return sshSession
+ }
+ const sshPeers = netMap.peers.filter(
+ (p) => p.tailscaleSSHEnabled && p.online !== false
+ )
+
+ if (sshPeers.length == 0) {
+ return <NoSSHPeers />
+ }
+
+ return <SSHForm sshPeers={sshPeers} onSubmit={setSSHSessionDef} />
+}
+
+type SSHFormSessionDef = SSHSessionDef & { newWindow?: boolean }
+
+function SSHSession({
+ def,
+ ipn,
+ onDone,
+}: {
+ def: SSHSessionDef
+ ipn: IPN
+ onDone: () => void
+}) {
+ const ref = useRef<HTMLDivElement>(null)
+ useEffect(() => {
+ if (ref.current) {
+ runSSHSession(ref.current, def, ipn, {
+ onConnectionProgress: (p) => console.log("Connection progress", p),
+ onConnected() {},
+ onError: (err) => console.error(err),
+ onDone,
+ })
+ }
+ }, [ref])
+
+ return <div class="flex-grow bg-black p-2 overflow-hidden" ref={ref} />
+}
+
+function NoSSHPeers() {
+ return (
+ <div class="container mx-auto px-4 text-center">
+ None of your machines have{" "}
+ <a href="https://tailscale.com/kb/1193/tailscale-ssh/" class="link">
+ Tailscale SSH
+ </a>
+ {" "}enabled. Give it a try!
+ </div>
+ )
+}
+
+function SSHForm({
+ sshPeers,
+ onSubmit,
+}: {
+ sshPeers: IPNNetMapPeerNode[]
+ onSubmit: (def: SSHFormSessionDef) => void
+}) {
+ sshPeers = sshPeers.slice().sort((a, b) => a.name.localeCompare(b.name))
+ const [username, setUsername] = useState("")
+ const [hostname, setHostname] = useState(sshPeers[0].name)
+ return (
+ <form
+ class="container mx-auto px-4 flex justify-center"
+ onSubmit={(e) => {
+ e.preventDefault()
+ onSubmit({ username, hostname })
+ }}
+ >
+ <input
+ type="text"
+ class="input username"
+ placeholder="Username"
+ onChange={(e) => setUsername(e.currentTarget.value)}
+ />
+ <div class="select-with-arrow mx-2">
+ <select
+ class="select"
+ onChange={(e) => setHostname(e.currentTarget.value)}
+ >
+ {sshPeers.map((p) => (
+ <option key={p.nodeKey}>{p.name.split(".")[0]}</option>
+ ))}
+ </select>
+ </div>
+ <input
+ type="submit"
+ class="button bg-green-500 border-green-500 text-white hover:bg-green-600 hover:border-green-600"
+ value="SSH"
+ onClick={(e) => {
+ if (e.altKey) {
+ e.preventDefault()
+ e.stopPropagation()
+ onSubmit({ username, hostname, newWindow: true })
+ }
+ }}
+ />
+ </form>
+ )
+}
+
+const NewWindow = ({
+ children,
+ close,
+}: {
+ children: VNode
+ close: () => void
+}) => {
+ const newWindow = useMemo(() => {
+ const newWindow = window.open(undefined, undefined, "width=600,height=400")
+ if (newWindow) {
+ const containerNode = newWindow.document.createElement("div")
+ containerNode.className = "h-screen flex flex-col overflow-hidden"
+ newWindow.document.body.appendChild(containerNode)
+
+ for (const linkNode of document.querySelectorAll(
+ "head link[rel=stylesheet]"
+ )) {
+ const newLink = document.createElement("link")
+ newLink.rel = "stylesheet"
+ newLink.href = (linkNode as HTMLLinkElement).href
+ newWindow.document.head.appendChild(newLink)
+ }
+ }
+ return newWindow
+ }, [])
+ if (!newWindow) {
+ console.error("Could not open window")
+ return null
+ }
+ newWindow.onbeforeunload = () => {
+ close()
+ }
+
+ useEffect(() => () => newWindow.close(), [])
+ return createPortal(children, newWindow.document.body.lastChild as Element)
+}
diff --git a/cmd/tsconnect/src/app/url-display.tsx b/cmd/tsconnect/src/app/url-display.tsx
index fc82c7fb9..c9b590181 100644
--- a/cmd/tsconnect/src/app/url-display.tsx
+++ b/cmd/tsconnect/src/app/url-display.tsx
@@ -1,31 +1,31 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-import { useState } from "preact/hooks"
-import * as qrcode from "qrcode"
-
-export function URLDisplay({ url }: { url: string }) {
- const [dataURL, setDataURL] = useState("")
- qrcode.toDataURL(url, { width: 512 }, (err, dataURL) => {
- if (err) {
- console.error("Error generating QR code", err)
- } else {
- setDataURL(dataURL)
- }
- })
-
- return (
- <div class="flex flex-col items-center justify-items-center">
- <a href={url} class="link" target="_blank">
- <img
- src={dataURL}
- class="mx-auto"
- width="256"
- height="256"
- alt="QR Code of URL"
- />
- {url}
- </a>
- </div>
- )
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+import { useState } from "preact/hooks"
+import * as qrcode from "qrcode"
+
+export function URLDisplay({ url }: { url: string }) {
+ const [dataURL, setDataURL] = useState("")
+ qrcode.toDataURL(url, { width: 512 }, (err, dataURL) => {
+ if (err) {
+ console.error("Error generating QR code", err)
+ } else {
+ setDataURL(dataURL)
+ }
+ })
+
+ return (
+ <div class="flex flex-col items-center justify-items-center">
+ <a href={url} class="link" target="_blank">
+ <img
+ src={dataURL}
+ class="mx-auto"
+ width="256"
+ height="256"
+ alt="QR Code of URL"
+ />
+ {url}
+ </a>
+ </div>
+ )
+}
diff --git a/cmd/tsconnect/src/lib/js-state-store.ts b/cmd/tsconnect/src/lib/js-state-store.ts
index e57dfd98e..7685e28a9 100644
--- a/cmd/tsconnect/src/lib/js-state-store.ts
+++ b/cmd/tsconnect/src/lib/js-state-store.ts
@@ -1,13 +1,13 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-/** @fileoverview Callbacks used by jsStateStore to persist IPN state. */
-
-export const sessionStateStorage: IPNStateStorage = {
- setState(id, value) {
- window.sessionStorage[`ipn-state-${id}`] = value
- },
- getState(id) {
- return window.sessionStorage[`ipn-state-${id}`] || ""
- },
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+/** @fileoverview Callbacks used by jsStateStore to persist IPN state. */
+
+export const sessionStateStorage: IPNStateStorage = {
+ setState(id, value) {
+ window.sessionStorage[`ipn-state-${id}`] = value
+ },
+ getState(id) {
+ return window.sessionStorage[`ipn-state-${id}`] || ""
+ },
+}
diff --git a/cmd/tsconnect/src/pkg/pkg.css b/cmd/tsconnect/src/pkg/pkg.css
index 76ea21f5b..60146d5b7 100644
--- a/cmd/tsconnect/src/pkg/pkg.css
+++ b/cmd/tsconnect/src/pkg/pkg.css
@@ -1,8 +1,8 @@
-/* Copyright (c) Tailscale Inc & AUTHORS */
-/* SPDX-License-Identifier: BSD-3-Clause */
-
-@import "xterm/css/xterm.css";
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+/* Copyright (c) Tailscale Inc & AUTHORS */
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+@import "xterm/css/xterm.css";
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/cmd/tsconnect/src/pkg/pkg.ts b/cmd/tsconnect/src/pkg/pkg.ts
index 4d535cb40..c0dcb5652 100644
--- a/cmd/tsconnect/src/pkg/pkg.ts
+++ b/cmd/tsconnect/src/pkg/pkg.ts
@@ -1,40 +1,40 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-// Type definitions need to be manually imported for dts-bundle-generator to
-// discover them.
-/// <reference path="../types/esbuild.d.ts" />
-/// <reference path="../types/wasm_js.d.ts" />
-
-import "../wasm_exec"
-import wasmURL from "./main.wasm"
-
-/**
- * Superset of the IPNConfig type, with additional configuration that is
- * needed for the package to function.
- */
-type IPNPackageConfig = IPNConfig & {
- // Auth key used to initialize the Tailscale client (required)
- authKey: string
- // URL of the main.wasm file that is included in the page, if it is not
- // accessible via a relative URL.
- wasmURL?: string
- // Function invoked if the Go process panics or unexpectedly exits.
- panicHandler: (err: string) => void
-}
-
-export async function createIPN(config: IPNPackageConfig): Promise<IPN> {
- const go = new Go()
- const wasmInstance = await WebAssembly.instantiateStreaming(
- fetch(config.wasmURL ?? wasmURL),
- go.importObject
- )
- // The Go process should never exit, if it does then it's an unhandled panic.
- go.run(wasmInstance.instance).then(() =>
- config.panicHandler("Unexpected shutdown")
- )
-
- return newIPN(config)
-}
-
-export { runSSHSession } from "../lib/ssh"
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+// Type definitions need to be manually imported for dts-bundle-generator to
+// discover them.
+/// <reference path="../types/esbuild.d.ts" />
+/// <reference path="../types/wasm_js.d.ts" />
+
+import "../wasm_exec"
+import wasmURL from "./main.wasm"
+
+/**
+ * Superset of the IPNConfig type, with additional configuration that is
+ * needed for the package to function.
+ */
+type IPNPackageConfig = IPNConfig & {
+ // Auth key used to initialize the Tailscale client (required)
+ authKey: string
+ // URL of the main.wasm file that is included in the page, if it is not
+ // accessible via a relative URL.
+ wasmURL?: string
+ // Function invoked if the Go process panics or unexpectedly exits.
+ panicHandler: (err: string) => void
+}
+
+export async function createIPN(config: IPNPackageConfig): Promise<IPN> {
+ const go = new Go()
+ const wasmInstance = await WebAssembly.instantiateStreaming(
+ fetch(config.wasmURL ?? wasmURL),
+ go.importObject
+ )
+ // The Go process should never exit, if it does then it's an unhandled panic.
+ go.run(wasmInstance.instance).then(() =>
+ config.panicHandler("Unexpected shutdown")
+ )
+
+ return newIPN(config)
+}
+
+export { runSSHSession } from "../lib/ssh"
diff --git a/cmd/tsconnect/src/types/esbuild.d.ts b/cmd/tsconnect/src/types/esbuild.d.ts
index ef28f7b1c..7153b4244 100644
--- a/cmd/tsconnect/src/types/esbuild.d.ts
+++ b/cmd/tsconnect/src/types/esbuild.d.ts
@@ -1,14 +1,14 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-/**
- * @fileoverview Type definitions for types generated by the esbuild build
- * process.
- */
-
-declare module "*.wasm" {
- const path: string
- export default path
-}
-
-declare const DEBUG: boolean
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+/**
+ * @fileoverview Type definitions for types generated by the esbuild build
+ * process.
+ */
+
+declare module "*.wasm" {
+ const path: string
+ export default path
+}
+
+declare const DEBUG: boolean
diff --git a/cmd/tsconnect/src/types/wasm_js.d.ts b/cmd/tsconnect/src/types/wasm_js.d.ts
index 492197ccb..82822c508 100644
--- a/cmd/tsconnect/src/types/wasm_js.d.ts
+++ b/cmd/tsconnect/src/types/wasm_js.d.ts
@@ -1,103 +1,103 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-/**
- * @fileoverview Type definitions for types exported by the wasm_js.go Go
- * module.
- */
-
-declare global {
- function newIPN(config: IPNConfig): IPN
-
- interface IPN {
- run(callbacks: IPNCallbacks): void
- login(): void
- logout(): void
- ssh(
- host: string,
- username: string,
- termConfig: {
- writeFn: (data: string) => void
- writeErrorFn: (err: string) => void
- setReadFn: (readFn: (data: string) => void) => void
- rows: number
- cols: number
- /** Defaults to 5 seconds */
- timeoutSeconds?: number
- onConnectionProgress: (message: string) => void
- onConnected: () => void
- onDone: () => void
- }
- ): IPNSSHSession
- fetch(url: string): Promise<{
- status: number
- statusText: string
- text: () => Promise<string>
- }>
- }
-
- interface IPNSSHSession {
- resize(rows: number, cols: number): boolean
- close(): boolean
- }
-
- interface IPNStateStorage {
- setState(id: string, value: string): void
- getState(id: string): string
- }
-
- type IPNConfig = {
- stateStorage?: IPNStateStorage
- authKey?: string
- controlURL?: string
- hostname?: string
- }
-
- type IPNCallbacks = {
- notifyState: (state: IPNState) => void
- notifyNetMap: (netMapStr: string) => void
- notifyBrowseToURL: (url: string) => void
- notifyPanicRecover: (err: string) => void
- }
-
- type IPNNetMap = {
- self: IPNNetMapSelfNode
- peers: IPNNetMapPeerNode[]
- lockedOut: boolean
- }
-
- type IPNNetMapNode = {
- name: string
- addresses: string[]
- machineKey: string
- nodeKey: string
- }
-
- type IPNNetMapSelfNode = IPNNetMapNode & {
- machineStatus: IPNMachineStatus
- }
-
- type IPNNetMapPeerNode = IPNNetMapNode & {
- online?: boolean
- tailscaleSSHEnabled: boolean
- }
-
- /** Mirrors values from ipn/backend.go */
- type IPNState =
- | "NoState"
- | "InUseOtherUser"
- | "NeedsLogin"
- | "NeedsMachineAuth"
- | "Stopped"
- | "Starting"
- | "Running"
-
- /** Mirrors values from MachineStatus in tailcfg.go */
- type IPNMachineStatus =
- | "MachineUnknown"
- | "MachineUnauthorized"
- | "MachineAuthorized"
- | "MachineInvalid"
-}
-
-export {}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+/**
+ * @fileoverview Type definitions for types exported by the wasm_js.go Go
+ * module.
+ */
+
+declare global {
+ function newIPN(config: IPNConfig): IPN
+
+ interface IPN {
+ run(callbacks: IPNCallbacks): void
+ login(): void
+ logout(): void
+ ssh(
+ host: string,
+ username: string,
+ termConfig: {
+ writeFn: (data: string) => void
+ writeErrorFn: (err: string) => void
+ setReadFn: (readFn: (data: string) => void) => void
+ rows: number
+ cols: number
+ /** Defaults to 5 seconds */
+ timeoutSeconds?: number
+ onConnectionProgress: (message: string) => void
+ onConnected: () => void
+ onDone: () => void
+ }
+ ): IPNSSHSession
+ fetch(url: string): Promise<{
+ status: number
+ statusText: string
+ text: () => Promise<string>
+ }>
+ }
+
+ interface IPNSSHSession {
+ resize(rows: number, cols: number): boolean
+ close(): boolean
+ }
+
+ interface IPNStateStorage {
+ setState(id: string, value: string): void
+ getState(id: string): string
+ }
+
+ type IPNConfig = {
+ stateStorage?: IPNStateStorage
+ authKey?: string
+ controlURL?: string
+ hostname?: string
+ }
+
+ type IPNCallbacks = {
+ notifyState: (state: IPNState) => void
+ notifyNetMap: (netMapStr: string) => void
+ notifyBrowseToURL: (url: string) => void
+ notifyPanicRecover: (err: string) => void
+ }
+
+ type IPNNetMap = {
+ self: IPNNetMapSelfNode
+ peers: IPNNetMapPeerNode[]
+ lockedOut: boolean
+ }
+
+ type IPNNetMapNode = {
+ name: string
+ addresses: string[]
+ machineKey: string
+ nodeKey: string
+ }
+
+ type IPNNetMapSelfNode = IPNNetMapNode & {
+ machineStatus: IPNMachineStatus
+ }
+
+ type IPNNetMapPeerNode = IPNNetMapNode & {
+ online?: boolean
+ tailscaleSSHEnabled: boolean
+ }
+
+ /** Mirrors values from ipn/backend.go */
+ type IPNState =
+ | "NoState"
+ | "InUseOtherUser"
+ | "NeedsLogin"
+ | "NeedsMachineAuth"
+ | "Stopped"
+ | "Starting"
+ | "Running"
+
+ /** Mirrors values from MachineStatus in tailcfg.go */
+ type IPNMachineStatus =
+ | "MachineUnknown"
+ | "MachineUnauthorized"
+ | "MachineAuthorized"
+ | "MachineInvalid"
+}
+
+export {}
diff --git a/cmd/tsconnect/tailwind.config.js b/cmd/tsconnect/tailwind.config.js
index 31823000b..38bc5b97b 100644
--- a/cmd/tsconnect/tailwind.config.js
+++ b/cmd/tsconnect/tailwind.config.js
@@ -1,8 +1,8 @@
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- content: ["./index.html", "./src/**/*.ts", "./src/**/*.tsx"],
- theme: {
- extend: {},
- },
- plugins: [],
-}
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./index.html", "./src/**/*.ts", "./src/**/*.tsx"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
diff --git a/cmd/tsconnect/tsconfig.json b/cmd/tsconnect/tsconfig.json
index 52c25c727..1148e2ef0 100644
--- a/cmd/tsconnect/tsconfig.json
+++ b/cmd/tsconnect/tsconfig.json
@@ -1,15 +1,15 @@
-{
- "compilerOptions": {
- "target": "ES2017",
- "module": "ES2020",
- "moduleResolution": "node",
- "isolatedModules": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "sourceMap": true,
- "jsx": "react-jsx",
- "jsxImportSource": "preact"
- },
- "include": ["src/**/*"],
- "exclude": ["node_modules"]
-}
+{
+ "compilerOptions": {
+ "target": "ES2017",
+ "module": "ES2020",
+ "moduleResolution": "node",
+ "isolatedModules": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "sourceMap": true,
+ "jsx": "react-jsx",
+ "jsxImportSource": "preact"
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules"]
+}
diff --git a/cmd/tsconnect/tsconnect.go b/cmd/tsconnect/tsconnect.go
index 4c8a0a52e..60ea6ef82 100644
--- a/cmd/tsconnect/tsconnect.go
+++ b/cmd/tsconnect/tsconnect.go
@@ -1,71 +1,71 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !plan9
-
-// The tsconnect command builds and serves the static site that is generated for
-// the Tailscale Connect JS/WASM client. Can be run in 3 modes:
-// - dev: builds the site and serves it. JS and CSS changes can be picked up
-// with a reload.
-// - build: builds the site and writes it to dist/
-// - serve: serves the site from dist/ (embedded in the binary)
-package main // import "tailscale.com/cmd/tsconnect"
-
-import (
- "flag"
- "fmt"
- "log"
- "os"
-)
-
-var (
- addr = flag.String("addr", ":9090", "address to listen on")
- distDir = flag.String("distdir", "./dist", "path of directory to place build output in")
- pkgDir = flag.String("pkgdir", "./pkg", "path of directory to place NPM package build output in")
- yarnPath = flag.String("yarnpath", "", "path yarn executable used to install JavaScript dependencies")
- fastCompression = flag.Bool("fast-compression", false, "Use faster compression when building, to speed up build time. Meant to iterative/debugging use only.")
- devControl = flag.String("dev-control", "", "URL of a development control server to be used with dev. If provided without specifying dev, an error will be returned.")
- rootDir = flag.String("rootdir", "", "Root directory of repo. If not specified, will be inferred from the cwd.")
-)
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- if len(flag.Args()) != 1 {
- flag.Usage()
- }
-
- switch flag.Arg(0) {
- case "dev":
- runDev()
- case "dev-pkg":
- runDevPkg()
- case "build":
- runBuild()
- case "build-pkg":
- runBuildPkg()
- case "serve":
- runServe()
- default:
- log.Printf("Unknown command: %s", flag.Arg(0))
- flag.Usage()
- }
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, `
-usage: tsconnect {dev|build|serve}
-`[1:])
-
- flag.PrintDefaults()
- fmt.Fprintf(os.Stderr, `
-
-tsconnect implements development/build/serving workflows for Tailscale Connect.
-It can be invoked with one of three subcommands:
-
-- dev: Run in development mode, allowing JS and CSS changes to be picked up without a rebuilt or restart.
-- build: Run in production build mode (generating static assets)
-- serve: Run in production serve mode (serving static assets)
-`[1:])
- os.Exit(2)
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !plan9
+
+// The tsconnect command builds and serves the static site that is generated for
+// the Tailscale Connect JS/WASM client. Can be run in 3 modes:
+// - dev: builds the site and serves it. JS and CSS changes can be picked up
+// with a reload.
+// - build: builds the site and writes it to dist/
+// - serve: serves the site from dist/ (embedded in the binary)
+package main // import "tailscale.com/cmd/tsconnect"
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+)
+
+var (
+ addr = flag.String("addr", ":9090", "address to listen on")
+ distDir = flag.String("distdir", "./dist", "path of directory to place build output in")
+ pkgDir = flag.String("pkgdir", "./pkg", "path of directory to place NPM package build output in")
+ yarnPath = flag.String("yarnpath", "", "path yarn executable used to install JavaScript dependencies")
+ fastCompression = flag.Bool("fast-compression", false, "Use faster compression when building, to speed up build time. Meant to iterative/debugging use only.")
+ devControl = flag.String("dev-control", "", "URL of a development control server to be used with dev. If provided without specifying dev, an error will be returned.")
+ rootDir = flag.String("rootdir", "", "Root directory of repo. If not specified, will be inferred from the cwd.")
+)
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if len(flag.Args()) != 1 {
+ flag.Usage()
+ }
+
+ switch flag.Arg(0) {
+ case "dev":
+ runDev()
+ case "dev-pkg":
+ runDevPkg()
+ case "build":
+ runBuild()
+ case "build-pkg":
+ runBuildPkg()
+ case "serve":
+ runServe()
+ default:
+ log.Printf("Unknown command: %s", flag.Arg(0))
+ flag.Usage()
+ }
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, `
+usage: tsconnect {dev|build|serve}
+`[1:])
+
+ flag.PrintDefaults()
+ fmt.Fprintf(os.Stderr, `
+
+tsconnect implements development/build/serving workflows for Tailscale Connect.
+It can be invoked with one of three subcommands:
+
+- dev: Run in development mode, allowing JS and CSS changes to be picked up without a rebuilt or restart.
+- build: Run in production build mode (generating static assets)
+- serve: Run in production serve mode (serving static assets)
+`[1:])
+ os.Exit(2)
+}
diff --git a/cmd/tsconnect/yarn.lock b/cmd/tsconnect/yarn.lock
index 663a1244e..914b4e6d0 100644
--- a/cmd/tsconnect/yarn.lock
+++ b/cmd/tsconnect/yarn.lock
@@ -1,713 +1,713 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@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"
-
-"@types/golang-wasm-exec@^1.15.0":
- version "1.15.0"
- resolved "https://registry.yarnpkg.com/@types/golang-wasm-exec/-/golang-wasm-exec-1.15.0.tgz#d0aafbb2b0dc07eaf45dfb83bfb6cdd5b2b3c55c"
- integrity sha512-FrL97mp7WW8LqNinVkzTVKOIQKuYjQqgucnh41+1vRQ+bf1LT8uh++KRf9otZPXsa6H1p8ruIGz1BmCGttOL6Q==
-
-"@types/node@*":
- version "18.6.1"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.1.tgz#828e4785ccca13f44e2fb6852ae0ef11e3e20ba5"
- integrity sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg==
-
-"@types/qrcode@^1.4.2":
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74"
- integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ==
- dependencies:
- "@types/node" "*"
-
-acorn-node@^1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
- integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
- dependencies:
- acorn "^7.0.0"
- acorn-walk "^7.0.0"
- xtend "^4.0.2"
-
-acorn-walk@^7.0.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
- integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-
-acorn@^7.0.0:
- version "7.4.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
- integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-
-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@^4.0.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@~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.2:
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
- integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
-
-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==
-
-braces@^3.0.2, 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"
-
-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==
-
-chokidar@^3.5.3:
- 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"
-
-cliui@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
- integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
- dependencies:
- string-width "^4.2.0"
- strip-ansi "^6.0.0"
- wrap-ansi "^6.2.0"
-
-cliui@^7.0.2:
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
- integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
- dependencies:
- string-width "^4.2.0"
- strip-ansi "^6.0.0"
- wrap-ansi "^7.0.0"
-
-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.4, 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==
-
-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==
-
-decamelize@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-
-defined@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
- integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==
-
-detective@^5.2.1:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
- integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
- dependencies:
- acorn-node "^1.8.2"
- defined "^1.0.0"
- minimist "^1.2.6"
-
-didyoumean@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
- integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
-
-dijkstrajs@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
- integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==
-
-dlv@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
- integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
-
-dts-bundle-generator@^6.12.0:
- version "6.12.0"
- resolved "https://registry.yarnpkg.com/dts-bundle-generator/-/dts-bundle-generator-6.12.0.tgz#0a221bdce5fdd309a56c8556e645f16ed87ab07d"
- integrity sha512-k/QAvuVaLIdyWRUHduDrWBe4j8PcE6TDt06+f32KHbW7/SmUPbX1O23fFtQgKwUyTBkbIjJFOFtNrF97tJcKug==
- dependencies:
- typescript ">=3.0.1"
- yargs "^17.2.1"
-
-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==
-
-encode-utf8@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda"
- integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-fast-glob@^3.2.11:
- 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"
-
-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"
-
-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"
-
-find-up@^4.1.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"
-
-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==
-
-get-caller-file@^2.0.1, get-caller-file@^2.0.5:
- 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==
-
-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.2:
- 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"
-
-has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
-
-is-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-core-module@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
- integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
- dependencies:
- has "^1.0.3"
-
-is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
-
-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@^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-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==
-
-lilconfig@^2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
- integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
-
-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"
-
-merge2@^1.3.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
- integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-
-micromatch@^4.0.4:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
- integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
- dependencies:
- braces "^3.0.2"
- picomatch "^2.3.1"
-
-minimist@^1.2.6:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
- integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
-
-nanoid@^3.3.4:
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
- integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-
-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==
-
-object-hash@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
- integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
-
-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-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-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==
-
-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-parse@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
- integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-picocolors@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
- integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
- integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-pify@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
- integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
-
-pngjs@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
- integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
-
-postcss-import@^14.1.0:
- version "14.1.0"
- resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
- integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
- dependencies:
- postcss-value-parser "^4.0.0"
- read-cache "^1.0.0"
- resolve "^1.1.7"
-
-postcss-js@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
- integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
- dependencies:
- camelcase-css "^2.0.1"
-
-postcss-load-config@^3.1.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
- integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
- dependencies:
- lilconfig "^2.0.5"
- yaml "^1.10.2"
-
-postcss-nested@5.0.6:
- version "5.0.6"
- resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc"
- integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
- dependencies:
- postcss-selector-parser "^6.0.6"
-
-postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.6:
- version "6.0.10"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
- integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
- dependencies:
- cssesc "^3.0.0"
- util-deprecate "^1.0.2"
-
-postcss-value-parser@^4.0.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@^8.4.14:
- version "8.4.14"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
- integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
- dependencies:
- nanoid "^3.3.4"
- picocolors "^1.0.0"
- source-map-js "^1.0.2"
-
-preact@^10.10.0:
- version "10.10.0"
- resolved "https://registry.yarnpkg.com/preact/-/preact-10.10.0.tgz#7434750a24b59dae1957d95dc0aa47a4a8e9a180"
- integrity sha512-fszkg1iJJjq68I4lI8ZsmBiaoQiQHbxf1lNq+72EmC/mZOsFF5zn3k1yv9QGoFgIXzgsdSKtYymLJsrJPoamjQ==
-
-qrcode@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
- integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==
- dependencies:
- dijkstrajs "^1.0.1"
- encode-utf8 "^1.0.3"
- pngjs "^5.0.0"
- yargs "^15.3.1"
-
-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==
-
-quick-lru@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
- integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
-
-read-cache@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
- integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
- dependencies:
- pify "^2.3.0"
-
-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"
-
-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-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==
-
-resolve@^1.1.7, resolve@^1.22.1:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-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==
-
-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"
-
-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=
-
-source-map-js@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
- integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-
-string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
- 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"
-
-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"
-
-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==
-
-tailwindcss@^3.1.6:
- version "3.1.6"
- resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.6.tgz#bcb719357776c39e6376a8d84e9834b2b19a49f1"
- integrity sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==
- dependencies:
- arg "^5.0.2"
- chokidar "^3.5.3"
- color-name "^1.1.4"
- detective "^5.2.1"
- didyoumean "^1.2.2"
- dlv "^1.1.3"
- fast-glob "^3.2.11"
- glob-parent "^6.0.2"
- is-glob "^4.0.3"
- lilconfig "^2.0.5"
- normalize-path "^3.0.0"
- object-hash "^3.0.0"
- picocolors "^1.0.0"
- postcss "^8.4.14"
- postcss-import "^14.1.0"
- postcss-js "^4.0.0"
- postcss-load-config "^3.1.4"
- postcss-nested "5.0.6"
- postcss-selector-parser "^6.0.10"
- postcss-value-parser "^4.2.0"
- quick-lru "^5.1.1"
- resolve "^1.22.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"
-
-typescript@>=3.0.1, typescript@^4.7.4:
- version "4.7.4"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
- integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
-
-util-deprecate@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
- integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-
-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=
-
-wrap-ansi@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
- integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.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"
-
-xtend@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
-xterm-addon-fit@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz#b8ade6d96e63b47443862088f6670b49fb752c6a"
- integrity sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==
-
-xterm-addon-web-links@^0.8.0:
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.8.0.tgz#2cb1d57129271022569208578b0bf4774e7e6ea9"
- integrity sha512-J4tKngmIu20ytX9SEJjAP3UGksah7iALqBtfTwT9ZnmFHVplCumYQsUJfKuS+JwMhjsjH61YXfndenLNvjRrEw==
-
-xterm@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0.tgz#3e160d60e6801c864b55adf19171c49d2ff2b4fc"
- integrity sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==
-
-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==
-
-y18n@^5.0.5:
- version "5.0.8"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
- integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
-
-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@^18.1.2:
- version "18.1.3"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
- integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
- dependencies:
- camelcase "^5.0.0"
- decamelize "^1.2.0"
-
-yargs-parser@^21.0.0:
- version "21.1.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
- integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
-
-yargs@^15.3.1:
- version "15.4.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
- integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
- dependencies:
- cliui "^6.0.0"
- decamelize "^1.2.0"
- find-up "^4.1.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 "^4.2.0"
- which-module "^2.0.0"
- y18n "^4.0.0"
- yargs-parser "^18.1.2"
-
-yargs@^17.2.1:
- version "17.5.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
- integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
- dependencies:
- cliui "^7.0.2"
- escalade "^3.1.1"
- get-caller-file "^2.0.5"
- require-directory "^2.1.1"
- string-width "^4.2.3"
- y18n "^5.0.5"
- yargs-parser "^21.0.0"
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@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"
+
+"@types/golang-wasm-exec@^1.15.0":
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/@types/golang-wasm-exec/-/golang-wasm-exec-1.15.0.tgz#d0aafbb2b0dc07eaf45dfb83bfb6cdd5b2b3c55c"
+ integrity sha512-FrL97mp7WW8LqNinVkzTVKOIQKuYjQqgucnh41+1vRQ+bf1LT8uh++KRf9otZPXsa6H1p8ruIGz1BmCGttOL6Q==
+
+"@types/node@*":
+ version "18.6.1"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.1.tgz#828e4785ccca13f44e2fb6852ae0ef11e3e20ba5"
+ integrity sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg==
+
+"@types/qrcode@^1.4.2":
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74"
+ integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ==
+ dependencies:
+ "@types/node" "*"
+
+acorn-node@^1.8.2:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
+ integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
+ dependencies:
+ acorn "^7.0.0"
+ acorn-walk "^7.0.0"
+ xtend "^4.0.2"
+
+acorn-walk@^7.0.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
+ integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
+
+acorn@^7.0.0:
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+
+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@^4.0.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@~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.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
+ integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
+
+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==
+
+braces@^3.0.2, 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"
+
+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==
+
+chokidar@^3.5.3:
+ 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"
+
+cliui@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
+ integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^6.2.0"
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+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.4, 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==
+
+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==
+
+decamelize@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+defined@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+ integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==
+
+detective@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
+ integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
+ dependencies:
+ acorn-node "^1.8.2"
+ defined "^1.0.0"
+ minimist "^1.2.6"
+
+didyoumean@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
+ integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
+
+dijkstrajs@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257"
+ integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg==
+
+dlv@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
+ integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
+
+dts-bundle-generator@^6.12.0:
+ version "6.12.0"
+ resolved "https://registry.yarnpkg.com/dts-bundle-generator/-/dts-bundle-generator-6.12.0.tgz#0a221bdce5fdd309a56c8556e645f16ed87ab07d"
+ integrity sha512-k/QAvuVaLIdyWRUHduDrWBe4j8PcE6TDt06+f32KHbW7/SmUPbX1O23fFtQgKwUyTBkbIjJFOFtNrF97tJcKug==
+ dependencies:
+ typescript ">=3.0.1"
+ yargs "^17.2.1"
+
+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==
+
+encode-utf8@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda"
+ integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+fast-glob@^3.2.11:
+ 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"
+
+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"
+
+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"
+
+find-up@^4.1.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"
+
+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==
+
+get-caller-file@^2.0.1, get-caller-file@^2.0.5:
+ 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==
+
+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.2:
+ 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"
+
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
+is-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-core-module@^2.9.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
+ integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
+ dependencies:
+ has "^1.0.3"
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+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@^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-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==
+
+lilconfig@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
+ integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
+
+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"
+
+merge2@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+minimist@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+ integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
+
+nanoid@^3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
+ integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
+
+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==
+
+object-hash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+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-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-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==
+
+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-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+
+pngjs@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
+ integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
+
+postcss-import@^14.1.0:
+ version "14.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
+ integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
+ dependencies:
+ postcss-value-parser "^4.0.0"
+ read-cache "^1.0.0"
+ resolve "^1.1.7"
+
+postcss-js@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
+ integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
+ dependencies:
+ camelcase-css "^2.0.1"
+
+postcss-load-config@^3.1.4:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
+ integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
+ dependencies:
+ lilconfig "^2.0.5"
+ yaml "^1.10.2"
+
+postcss-nested@5.0.6:
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc"
+ integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==
+ dependencies:
+ postcss-selector-parser "^6.0.6"
+
+postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.6:
+ version "6.0.10"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
+ integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.0.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@^8.4.14:
+ version "8.4.14"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
+ integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
+ dependencies:
+ nanoid "^3.3.4"
+ picocolors "^1.0.0"
+ source-map-js "^1.0.2"
+
+preact@^10.10.0:
+ version "10.10.0"
+ resolved "https://registry.yarnpkg.com/preact/-/preact-10.10.0.tgz#7434750a24b59dae1957d95dc0aa47a4a8e9a180"
+ integrity sha512-fszkg1iJJjq68I4lI8ZsmBiaoQiQHbxf1lNq+72EmC/mZOsFF5zn3k1yv9QGoFgIXzgsdSKtYymLJsrJPoamjQ==
+
+qrcode@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b"
+ integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ==
+ dependencies:
+ dijkstrajs "^1.0.1"
+ encode-utf8 "^1.0.3"
+ pngjs "^5.0.0"
+ yargs "^15.3.1"
+
+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==
+
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
+read-cache@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+ integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
+ dependencies:
+ pify "^2.3.0"
+
+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"
+
+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-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==
+
+resolve@^1.1.7, resolve@^1.22.1:
+ version "1.22.1"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
+ integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
+ dependencies:
+ is-core-module "^2.9.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+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==
+
+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"
+
+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=
+
+source-map-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+ integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ 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"
+
+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"
+
+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==
+
+tailwindcss@^3.1.6:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.1.6.tgz#bcb719357776c39e6376a8d84e9834b2b19a49f1"
+ integrity sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==
+ dependencies:
+ arg "^5.0.2"
+ chokidar "^3.5.3"
+ color-name "^1.1.4"
+ detective "^5.2.1"
+ didyoumean "^1.2.2"
+ dlv "^1.1.3"
+ fast-glob "^3.2.11"
+ glob-parent "^6.0.2"
+ is-glob "^4.0.3"
+ lilconfig "^2.0.5"
+ normalize-path "^3.0.0"
+ object-hash "^3.0.0"
+ picocolors "^1.0.0"
+ postcss "^8.4.14"
+ postcss-import "^14.1.0"
+ postcss-js "^4.0.0"
+ postcss-load-config "^3.1.4"
+ postcss-nested "5.0.6"
+ postcss-selector-parser "^6.0.10"
+ postcss-value-parser "^4.2.0"
+ quick-lru "^5.1.1"
+ resolve "^1.22.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"
+
+typescript@>=3.0.1, typescript@^4.7.4:
+ version "4.7.4"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
+ integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
+
+util-deprecate@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+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=
+
+wrap-ansi@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.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"
+
+xtend@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+xterm-addon-fit@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz#b8ade6d96e63b47443862088f6670b49fb752c6a"
+ integrity sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==
+
+xterm-addon-web-links@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.8.0.tgz#2cb1d57129271022569208578b0bf4774e7e6ea9"
+ integrity sha512-J4tKngmIu20ytX9SEJjAP3UGksah7iALqBtfTwT9ZnmFHVplCumYQsUJfKuS+JwMhjsjH61YXfndenLNvjRrEw==
+
+xterm@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.1.0.tgz#3e160d60e6801c864b55adf19171c49d2ff2b4fc"
+ integrity sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==
+
+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==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+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@^18.1.2:
+ version "18.1.3"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+ integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
+yargs-parser@^21.0.0:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^15.3.1:
+ version "15.4.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
+ integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
+ dependencies:
+ cliui "^6.0.0"
+ decamelize "^1.2.0"
+ find-up "^4.1.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 "^4.2.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^18.1.2"
+
+yargs@^17.2.1:
+ version "17.5.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e"
+ integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.0.0"