Compare commits
No commits in common. "main" and "19a2b3d44332e650d4301a6b79ad7d11e1643823" have entirely different histories.
main
...
19a2b3d443
|
|
@ -1,4 +1,2 @@
|
||||||
*/.env
|
*/.env
|
||||||
test
|
test
|
||||||
*/.DS_STORE
|
|
||||||
.DS_STORE
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
||||||
"editor.tabSize": 2
|
|
||||||
}
|
|
||||||
23
README.md
23
README.md
|
|
@ -1,23 +0,0 @@
|
||||||
# watchtogether
|
|
||||||
|
|
||||||
This was a project that I created over 7 days of working while having covid :)
|
|
||||||
|
|
||||||
I probably won't do much with the codebase, but enjoy how I basically figured out how to sync video streams with multiple clients
|
|
||||||
|
|
||||||
## The Stack
|
|
||||||
|
|
||||||
- frontend
|
|
||||||
|
|
||||||
- next js
|
|
||||||
- websockets
|
|
||||||
- chakra-ui
|
|
||||||
- react-player
|
|
||||||
|
|
||||||
- backend
|
|
||||||
|
|
||||||
- go
|
|
||||||
- gorilla/websockets
|
|
||||||
|
|
||||||
## how 2 deploy?
|
|
||||||
|
|
||||||
you don't
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
cmd/watchtogether/watchtogether
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="PROJECT_FILES" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AutoImportSettings">
|
|
||||||
<option name="autoReloadType" value="ALL" />
|
|
||||||
</component>
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" beforeDir="false" afterPath="$PROJECT_DIR$/../frontend/src/pages/player.tsx" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="FileTemplateManagerImpl">
|
|
||||||
<option name="RECENT_TEMPLATES">
|
|
||||||
<list>
|
|
||||||
<option value="Go File" />
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="GOROOT" url="file:///usr/lib/go" />
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
|
||||||
</component>
|
|
||||||
<component name="GitSEFilterConfiguration">
|
|
||||||
<file-type-list>
|
|
||||||
<filtered-out-file-type name="LOCAL_BRANCH" />
|
|
||||||
<filtered-out-file-type name="REMOTE_BRANCH" />
|
|
||||||
<filtered-out-file-type name="TAG" />
|
|
||||||
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
|
|
||||||
</file-type-list>
|
|
||||||
</component>
|
|
||||||
<component name="GoLibraries">
|
|
||||||
<option name="indexEntireGoPath" value="false" />
|
|
||||||
</component>
|
|
||||||
<component name="MarkdownSettingsMigration">
|
|
||||||
<option name="stateVersion" value="1" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectId" id="2456l5ltkI1NptLGqpacBxKAWdj" />
|
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
|
||||||
<ConfirmationsSetting value="2" id="Add" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent">
|
|
||||||
<property name="ASKED_ADD_EXTERNAL_FILES" value="true" />
|
|
||||||
<property name="DefaultGoTemplateProperty" value="Go File" />
|
|
||||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
|
||||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
|
||||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
|
||||||
<property name="go.format.on.save.advertiser.fired" value="true" />
|
|
||||||
<property name="go.formatter.settings.were.checked" value="true" />
|
|
||||||
<property name="go.import.settings.migrated" value="true" />
|
|
||||||
<property name="go.modules.go.list.on.any.changes.was.set" value="true" />
|
|
||||||
<property name="go.sdk.automatically.set" value="true" />
|
|
||||||
<property name="go.watchers.conflict.with.on.save.actions.check.performed" value="true" />
|
|
||||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="RunManager">
|
|
||||||
<configuration name="go build github.com/qpixel/watchtogether/cmd/watchtogether" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
|
||||||
<module name="backend" />
|
|
||||||
<working_directory value="$PROJECT_DIR$" />
|
|
||||||
<kind value="PACKAGE" />
|
|
||||||
<package value="github.com/qpixel/watchtogether/cmd/watchtogether" />
|
|
||||||
<directory value="$PROJECT_DIR$" />
|
|
||||||
<filePath value="$PROJECT_DIR$/cmd/watchtogether/main.go" />
|
|
||||||
<method v="2" />
|
|
||||||
</configuration>
|
|
||||||
<recent_temporary>
|
|
||||||
<list>
|
|
||||||
<item itemvalue="Go Build.go build github.com/qpixel/watchtogether/cmd/watchtogether" />
|
|
||||||
</list>
|
|
||||||
</recent_temporary>
|
|
||||||
</component>
|
|
||||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
<component name="Vcs.Log.Tabs.Properties">
|
|
||||||
<option name="TAB_STATES">
|
|
||||||
<map>
|
|
||||||
<entry key="MAIN">
|
|
||||||
<value>
|
|
||||||
<State />
|
|
||||||
</value>
|
|
||||||
</entry>
|
|
||||||
</map>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="VcsManagerConfiguration">
|
|
||||||
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="VgoProject">
|
|
||||||
<integration-enabled>true</integration-enabled>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
localhost:3001
|
|
||||||
|
|
||||||
file_server
|
|
||||||
reverse_proxy 127.0.0.1:8080
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
# backend
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
VERSION=v1.0.0
|
|
||||||
COMMIT_HASH=$(git rev-parse --short HEAD)
|
|
||||||
ENVIRONMENT=$ENV
|
|
||||||
BUILDSTRING="$VERSION-$COMMIT_HASH-$ENVIRONMENT"
|
|
||||||
echo The environment is "$ENVIRONMENT"
|
|
||||||
echo Building watch together backend "$VERSION-$COMMIT_HASH"
|
|
||||||
if [[ "$ENVIRONMENT" == "dev" ]]; then
|
|
||||||
go build -gcflags="all=-N -l" -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/qpixel/watchtogether/cmd/watchtogether/main.ENVIRONMENT=${ENVIRONMENT}";
|
|
||||||
else
|
|
||||||
go build -ldflags "-X github.com/qpixel/watchtogether/cmd/watchtogether/main.VERSION=${BUILDSTRING} -X github.com/ubergeek77/uberbot/v2/core.ENVIRONMENT=${ENVIRONMENT}";
|
|
||||||
fi
|
|
||||||
|
|
@ -1,62 +1,72 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"flag"
|
||||||
"github.com/gorilla/mux"
|
"fmt"
|
||||||
"github.com/qpixel/watchtogether/internal/ws"
|
"github.com/peterbourgon/ff/v3"
|
||||||
tlog "github.com/ubergeek77/tinylog"
|
"github.com/qpixel/watchtogether/internal/logger"
|
||||||
"net/http"
|
"github.com/qpixel/watchtogether/internal/server"
|
||||||
|
"github.com/ubergeek77/tinylog"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = tlog.NewTaggedLogger("Logger", tlog.NewColor("38;5;111"))
|
type flags struct {
|
||||||
|
loglvl int
|
||||||
|
port int
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
func newFlags(args []string) (flgs flags, err error) {
|
||||||
VERSION string
|
fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
|
||||||
ENVIRONMENT string
|
|
||||||
)
|
var (
|
||||||
|
loglvl = fs.Int("loglvl", tinylog.TraceLevel, "sets the log level (also via LOG_LEVEL)")
|
||||||
|
port = fs.Int("port", 4000, "sets the port to use (also via PORT)")
|
||||||
|
)
|
||||||
|
// Parse the command line flags from above
|
||||||
|
err = ff.Parse(fs, args[1:], ff.WithEnvVarNoPrefix())
|
||||||
|
if err != nil {
|
||||||
|
return flgs, err
|
||||||
|
}
|
||||||
|
return flags{
|
||||||
|
loglvl: *loglvl,
|
||||||
|
port: *port,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
r := mux.NewRouter()
|
if err := run(os.Args); err != nil {
|
||||||
hub := ws.NewHub()
|
tinylog.DefaultLogger().Errorf("error from main.run(): %s\n", err)
|
||||||
go hub.Run()
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
r.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
}
|
||||||
ws.ServeWs(hub, w, r)
|
|
||||||
})
|
func run(args []string) error {
|
||||||
r.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
flgs, err := newFlags(args)
|
||||||
resp := make(map[string]interface{})
|
if err != nil {
|
||||||
resp["status"] = "ok"
|
return err
|
||||||
resp["users"] = len(hub.Clients)
|
}
|
||||||
jsonResp, err := json.Marshal(resp)
|
// setup logger with defaults
|
||||||
if err != nil {
|
lgr := logger.NewLogger(flgs.loglvl, "WatchTogether")
|
||||||
log.Fatalf("error in marshaling json. err: %s", err.Error())
|
|
||||||
}
|
lgr.Infof("go runtime ver: %s", runtime.Version())
|
||||||
_, err = w.Write(jsonResp)
|
lgr.Infof("Logging level has been set to %d", lgr.LogLevel)
|
||||||
if err != nil {
|
|
||||||
return
|
mr := server.NewMuxRouter()
|
||||||
}
|
|
||||||
return
|
serverDriver := server.NewDriver()
|
||||||
})
|
|
||||||
r.Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
params := server.NewServerParams(lgr, serverDriver)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
resp := make(map[string]interface{})
|
s, err := server.NewServer(mr, params)
|
||||||
resp["status"] = "ok"
|
if err != nil {
|
||||||
jsonResp, err := json.Marshal(resp)
|
lgr.Errorf("err: %s", err)
|
||||||
if err != nil {
|
lgr.Fatal("error in server.NewServer")
|
||||||
log.Fatalf("error in marshaling json. err: %s", err.Error())
|
}
|
||||||
}
|
|
||||||
_, err = w.Write(jsonResp)
|
s.Addr = fmt.Sprintf(":%d", flgs.port)
|
||||||
if err != nil {
|
|
||||||
return
|
return s.ListenAndServe()
|
||||||
}
|
|
||||||
return
|
|
||||||
})
|
|
||||||
log.Infof("starting backend")
|
|
||||||
log.Infof("running version %s. environment: %s", VERSION, ENVIRONMENT)
|
|
||||||
err := http.ListenAndServe(":8080", r)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("%s", err.Error())
|
|
||||||
log.Fatalf("unable to serve on port 8080")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version: "3.9"
|
|
||||||
services:
|
|
||||||
caddy:
|
|
||||||
|
|
@ -2,8 +2,16 @@ module github.com/qpixel/watchtogether
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
replace (
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/qpixel/tloghttp => ../../tloghttp
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
github.com/qpixel/tlogbuilder => ../../tlogbuilder
|
||||||
github.com/ubergeek77/tinylog v1.0.0 // indirect
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/justinas/alice v1.2.0
|
||||||
|
github.com/peterbourgon/ff/v3 v3.1.2
|
||||||
|
github.com/qpixel/tloghttp v0.0.0-20211222065322-cd8d1a945a36
|
||||||
|
github.com/qpixel/tlogbuilder v0.0.0
|
||||||
|
github.com/ubergeek77/tinylog v1.0.0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
|
||||||
|
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||||
|
github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=
|
||||||
|
github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=
|
||||||
github.com/ubergeek77/tinylog v1.0.0 h1:gsq98mbig3LDWhsizOe2tid12wHUz/mrkDlmgJ0MZG4=
|
github.com/ubergeek77/tinylog v1.0.0 h1:gsq98mbig3LDWhsizOe2tid12wHUz/mrkDlmgJ0MZG4=
|
||||||
github.com/ubergeek77/tinylog v1.0.0/go.mod h1:NzUi4PkRG2hACL4cGgmW7db6EaKjAeqrqlVQnJdw78Q=
|
github.com/ubergeek77/tinylog v1.0.0/go.mod h1:NzUi4PkRG2hACL4cGgmW7db6EaKjAeqrqlVQnJdw78Q=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2018 The Go Cloud Development Kit Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// @gilcrest - removed TLSServer interface
|
||||||
|
|
||||||
|
// Package driver defines an interface for custom HTTP listeners.
|
||||||
|
// Application code should use package server.
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server dispatches requests to an http.Handler.
|
||||||
|
type Server interface {
|
||||||
|
// ListenAndServe listens on the TCP network address addr and then
|
||||||
|
// calls Serve with handler to handle requests on incoming connections.
|
||||||
|
// The addr argument will be a non-empty string specifying "host:port".
|
||||||
|
// The http.Handler will always be non-nil.
|
||||||
|
// Drivers must block until serving is done (or
|
||||||
|
// return an error if serving can't occur for some reason), serve
|
||||||
|
// requests to the given http.Handler, and be interruptable by Shutdown.
|
||||||
|
// Drivers should use the given address if they serve using TCP directly.
|
||||||
|
ListenAndServe(addr string, h http.Handler) error
|
||||||
|
|
||||||
|
// Shutdown gracefully shuts down the server without interrupting
|
||||||
|
// any active connections. If the provided context expires before
|
||||||
|
// the shutdown is complete, Shutdown returns the context's error,
|
||||||
|
// otherwise it returns any error returned from closing the Server's
|
||||||
|
// underlying Listener(s).
|
||||||
|
Shutdown(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ubergeek77/tinylog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLogger(lvl int, tag string) *tinylog.Logger {
|
||||||
|
// cfg contains our custom config for tinylog
|
||||||
|
cfg := tinylog.NewConfig()
|
||||||
|
cfg.LogLevel = lvl
|
||||||
|
cfg.LogPrefix = tinylog.GenerateTag(tag, tinylog.NewColor("38;5;133"), cfg)
|
||||||
|
|
||||||
|
//initialize the instance of tinylog
|
||||||
|
lgr := tinylog.NewLogger(cfg)
|
||||||
|
|
||||||
|
return lgr
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/justinas/alice"
|
||||||
|
"github.com/qpixel/tlogbuilder"
|
||||||
|
"github.com/qpixel/tloghttp"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
//Copyright (c) 2017 Dan Gillis
|
||||||
|
//
|
||||||
|
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
//of this software and associated documentation files (the "Software"), to deal
|
||||||
|
//in the Software without restriction, including without limitation the rights
|
||||||
|
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
//copies of the Software, and to permit persons to whom the Software is
|
||||||
|
//furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
//The above copyright notice and this permission notice shall be included in all
|
||||||
|
//copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
//SOFTWARE.
|
||||||
|
|
||||||
|
// LoggerChain returns a middleware chain (via alice.Chain)
|
||||||
|
// initialized with all the standard middleware handlers for logging. The logger
|
||||||
|
// will be added to the request context for subsequent use with pre-populated
|
||||||
|
// fields, including the request method, url, status, size, duration, remote IP,
|
||||||
|
// user agent, referer. A unique Request ID is also added to the logger, context
|
||||||
|
// and response headers.
|
||||||
|
func (s *Server) loggerChain() alice.Chain {
|
||||||
|
ac := alice.New(tloghttp.NewHandler(s.logger),
|
||||||
|
tloghttp.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
||||||
|
tlogbuilder.CreateBuilder(tloghttp.FromRequest(r)).
|
||||||
|
Info().
|
||||||
|
Str("method", r.Method).
|
||||||
|
Stringer("url", r.URL).
|
||||||
|
Int("status", status).
|
||||||
|
Int("size", size).
|
||||||
|
Dur("duration", duration).
|
||||||
|
Msg("request logged").
|
||||||
|
Build()
|
||||||
|
}),
|
||||||
|
tloghttp.RemoteAddrHandler("remote_ip"),
|
||||||
|
tloghttp.UserAgentHandler("user_agent"),
|
||||||
|
tloghttp.RefererHandler("referer"),
|
||||||
|
//tloghttp.RequestIDHandler("request_id", "Request-Id"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
const (
|
||||||
|
contentTypeHeaderKey string = "Content-Type"
|
||||||
|
appJSONContentTypeHeaderVal string = "application/json",
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) routes() {
|
||||||
|
s.router.Handle("/", func(http.ResponseWriter, *http.Response) {
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
// Copyright 2018 The Go Cloud Development Kit Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// @QPixel edits - I have made a copy of the go-api-basic server code and made
|
||||||
|
// the following changes:
|
||||||
|
//
|
||||||
|
// - removed zerolog dependency
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/qpixel/watchtogether/internal/driver"
|
||||||
|
"github.com/ubergeek77/tinylog"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const pathPrefix = "/api"
|
||||||
|
|
||||||
|
// Server represents an HTTP server
|
||||||
|
type Server struct {
|
||||||
|
router *mux.Router
|
||||||
|
driver driver.Server
|
||||||
|
|
||||||
|
logger *tinylog.Logger
|
||||||
|
|
||||||
|
Addr string
|
||||||
|
|
||||||
|
// Authorization
|
||||||
|
|
||||||
|
// Services
|
||||||
|
}
|
||||||
|
|
||||||
|
//type LoggerService interface {
|
||||||
|
// Read() logger.LoggerResponse
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
// SvrParams is the set of configuration parameters for a Server
|
||||||
|
type SvrParams struct {
|
||||||
|
// Logger is used for the server logging
|
||||||
|
Logger *tinylog.Logger
|
||||||
|
|
||||||
|
// Driver serves HTTP requests
|
||||||
|
Driver driver.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerParams is an initializer for ServerParams
|
||||||
|
func NewServerParams(lgr *tinylog.Logger, d driver.Server) *SvrParams {
|
||||||
|
options := &SvrParams{
|
||||||
|
Logger: lgr,
|
||||||
|
Driver: d,
|
||||||
|
}
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServer initializes a new Server and registers
|
||||||
|
// routes to the router mux
|
||||||
|
// todo add error checking
|
||||||
|
func NewServer(r *mux.Router, params *SvrParams) (*Server, error) {
|
||||||
|
s := &Server{router: r}
|
||||||
|
s.logger = params.Logger
|
||||||
|
s.driver = params.Driver
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListenAndServe() error {
|
||||||
|
if s.Addr == "" {
|
||||||
|
return errors.New("server Addr is empty")
|
||||||
|
}
|
||||||
|
if s.router == nil {
|
||||||
|
return errors.New("server router is nil")
|
||||||
|
}
|
||||||
|
if s.driver == nil {
|
||||||
|
return errors.New("server driver is nil")
|
||||||
|
}
|
||||||
|
s.logger.Infof("server is listening on %s", s.Addr)
|
||||||
|
return s.driver.ListenAndServe(s.Addr, s.router)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown will gracefully shut down the server without interrupting any active connections
|
||||||
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
|
if s.driver == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.driver.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Driver implements the driver.Server interface. The zero value is a valid http.Server
|
||||||
|
type Driver struct {
|
||||||
|
Server http.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDriver intializes a Driver with http.Server using default timeouts
|
||||||
|
func NewDriver() *Driver {
|
||||||
|
return &Driver{
|
||||||
|
Server: http.Server{
|
||||||
|
ReadTimeout: 30 * time.Second,
|
||||||
|
WriteTimeout: 30 * time.Second,
|
||||||
|
IdleTimeout: 120 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenAndServe sets the address and handler on Driver's http.Server
|
||||||
|
func (d *Driver) ListenAndServe(addr string, h http.Handler) error {
|
||||||
|
d.Server.Addr = addr
|
||||||
|
d.Server.Handler = h
|
||||||
|
return d.Server.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown gracefully shuts down the server without interrupting any active connections,
|
||||||
|
// by calling Shutdown on Driver's http.Server
|
||||||
|
func (d *Driver) Shutdown(ctx context.Context) error {
|
||||||
|
return d.Server.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMuxRouter initializes a gorilla/mux router and
|
||||||
|
// adds the /api subroute to it
|
||||||
|
func NewMuxRouter() *mux.Router {
|
||||||
|
// initializer gorilla/mux router
|
||||||
|
r := mux.NewRouter()
|
||||||
|
|
||||||
|
// send Router through PathPrefix method to validate any standard
|
||||||
|
// subroutes you may want for your APIs. e.g. I always want to be
|
||||||
|
// sure that every request has "/api" as part of its path prefix
|
||||||
|
// without having to put it into every handle path in my various
|
||||||
|
// routing functions
|
||||||
|
s := r.PathPrefix(pathPrefix).Subrouter()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func decoderErr(err error) error {
|
||||||
|
switch {
|
||||||
|
case err == io.EOF:
|
||||||
|
return errors.New("request body cannot be empty")
|
||||||
|
case err == io.ErrUnexpectedEOF:
|
||||||
|
return errors.New("malformed json")
|
||||||
|
case err != nil:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// time allowed to write a message to the peer.
|
|
||||||
writeWait = 10 * time.Second
|
|
||||||
|
|
||||||
pongWait = 60 * time.Second
|
|
||||||
|
|
||||||
pingPeriod = (pongWait * 9) / 10
|
|
||||||
|
|
||||||
maxMessageSize = 512
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
newline = []byte{'\n'}
|
|
||||||
space = []byte{' '}
|
|
||||||
)
|
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
|
||||||
ReadBufferSize: 1024,
|
|
||||||
WriteBufferSize: 1024,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
hub *Hub
|
|
||||||
conn *websocket.Conn
|
|
||||||
send chan []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// readPump pumps messages from the websocket connection to the hub.
|
|
||||||
//
|
|
||||||
// The application runs readPump in a per-connection goroutine. The application
|
|
||||||
// ensures that there is at most one reader on a connection by executing all
|
|
||||||
// reads from this goroutine.
|
|
||||||
func (c *Client) readPump() {
|
|
||||||
defer func() {
|
|
||||||
c.hub.unregister <- c
|
|
||||||
c.conn.Close()
|
|
||||||
}()
|
|
||||||
c.conn.SetReadLimit(maxMessageSize)
|
|
||||||
c.conn.SetReadDeadline(time.Now().Add(pongWait))
|
|
||||||
c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
|
|
||||||
for {
|
|
||||||
_, message, err := c.conn.ReadMessage()
|
|
||||||
if err != nil {
|
|
||||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
|
||||||
log.Infof("error: %v", err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
|
|
||||||
c.hub.broadcast <- RawMessage{
|
|
||||||
Client: c,
|
|
||||||
Data: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// writePump pumps messages from the hub to the websocket connection.
|
|
||||||
//
|
|
||||||
// A goroutine running writePump is started for each connection. The
|
|
||||||
// application ensures that there is at most one writer to a connection by
|
|
||||||
// executing all writes from this goroutine.
|
|
||||||
func (c *Client) writePump() {
|
|
||||||
ticker := time.NewTicker(pingPeriod)
|
|
||||||
defer func() {
|
|
||||||
ticker.Stop()
|
|
||||||
c.conn.Close()
|
|
||||||
}()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case message, ok := <-c.send:
|
|
||||||
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
||||||
if !ok {
|
|
||||||
// The hub closed the channel.
|
|
||||||
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err := c.conn.NextWriter(websocket.TextMessage)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write(message)
|
|
||||||
|
|
||||||
// Add queued chat messages to the current websocket message.
|
|
||||||
n := len(c.send)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
w.Write(newline)
|
|
||||||
w.Write(<-c.send)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := w.Close(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-ticker.C:
|
|
||||||
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
|
|
||||||
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServeWs handles websocket requests from the peer.
|
|
||||||
func ServeWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
|
|
||||||
upgrader.CheckOrigin = func(r *http.Request) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}
|
|
||||||
client.hub.register <- client
|
|
||||||
|
|
||||||
// Allow collection of memory referenced by the caller by doing all work in
|
|
||||||
// new goroutines.
|
|
||||||
go client.writePump()
|
|
||||||
go client.readPump()
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
//todo better data deserialization
|
|
||||||
|
|
||||||
type IdentityData struct {
|
|
||||||
ClientID string `json:"clientID"`
|
|
||||||
User User `json:"user"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleIdentifyEvent(message *Message) {
|
|
||||||
d := message.Data.(map[string]interface{})
|
|
||||||
if id, ok := d["clientID"]; ok {
|
|
||||||
log.Infof("Client %s has sent identify event", id.(string))
|
|
||||||
}
|
|
||||||
user := d["user"].(map[string]interface{})
|
|
||||||
userId := user["id"].(string)
|
|
||||||
playhead := message.hub.State.playhead
|
|
||||||
paused := message.hub.State.paused
|
|
||||||
m := Message{
|
|
||||||
MessageData: MessageData{
|
|
||||||
Type: Identify,
|
|
||||||
Data: map[string]interface{}{
|
|
||||||
"admin": message.hub.State.IsAdmin(userId),
|
|
||||||
"playlist": "http://localhost:8081/BelleOpening.m3u8",
|
|
||||||
"hasController": message.hub.State.IsController(userId),
|
|
||||||
"playhead": playhead,
|
|
||||||
"paused": paused,
|
|
||||||
"user": d["user"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
message.send <- m.SerializeMessage().Data
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePingEvent(message *Message) {
|
|
||||||
m := Message{
|
|
||||||
message.Client,
|
|
||||||
MessageData{
|
|
||||||
Type: Pong,
|
|
||||||
Data: nil,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
message.send <- m.SerializeMessage().Data
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleGetPlayhead(message *Message) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleSetPlayhead(message *Message) {
|
|
||||||
d := message.Data.(map[string]interface{})
|
|
||||||
m := Message{
|
|
||||||
MessageData: MessageData{
|
|
||||||
Type: SetPlayhead,
|
|
||||||
Data: map[string]interface{}{
|
|
||||||
"playhead": d["playhead"],
|
|
||||||
"paused": d["paused"],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
log.Infof("Received SetPlayhead event. playhead is at %s", d["playhead"])
|
|
||||||
err := message.hub.State.setPlayhead(d["playhead"].(float64))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("unable to set playhead. %s", err)
|
|
||||||
}
|
|
||||||
err = message.hub.State.setPaused(d["paused"].(bool))
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("unable to set paused. %s", err)
|
|
||||||
}
|
|
||||||
for client := range message.Client.hub.Clients {
|
|
||||||
if client == message.Client {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
client.send <- m.SerializeMessage().Data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
type Hub struct {
|
|
||||||
// Registered Clients
|
|
||||||
Clients map[*Client]bool
|
|
||||||
|
|
||||||
// State
|
|
||||||
State *State
|
|
||||||
|
|
||||||
// Inbound messages from the Clients
|
|
||||||
broadcast chan RawMessage
|
|
||||||
|
|
||||||
// Register requests from the Clients
|
|
||||||
register chan *Client
|
|
||||||
|
|
||||||
// Unregister requests from Clients
|
|
||||||
unregister chan *Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHub() *Hub {
|
|
||||||
return &Hub{
|
|
||||||
broadcast: make(chan RawMessage),
|
|
||||||
register: make(chan *Client),
|
|
||||||
unregister: make(chan *Client),
|
|
||||||
Clients: make(map[*Client]bool),
|
|
||||||
State: NewState(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hub) handleMessage(rm RawMessage) {
|
|
||||||
m := rm.UnserializeData()
|
|
||||||
switch m.Type {
|
|
||||||
case Identify:
|
|
||||||
handleIdentifyEvent(&m)
|
|
||||||
case Ping:
|
|
||||||
handlePingEvent(&m)
|
|
||||||
case GetPlayhead:
|
|
||||||
handleGetPlayhead(&m)
|
|
||||||
case SetPlayhead:
|
|
||||||
handleSetPlayhead(&m)
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Hub) Run() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case client := <-h.register:
|
|
||||||
h.Clients[client] = true
|
|
||||||
case client := <-h.unregister:
|
|
||||||
if _, ok := h.Clients[client]; ok {
|
|
||||||
delete(h.Clients, client)
|
|
||||||
close(client.send)
|
|
||||||
}
|
|
||||||
case message := <-h.broadcast:
|
|
||||||
go h.handleMessage(message)
|
|
||||||
//for client := range h.Clients {
|
|
||||||
// select {
|
|
||||||
// case client.send <- message:
|
|
||||||
// default:
|
|
||||||
// close(client.send)
|
|
||||||
// delete(h.Clients, client)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
tlog "github.com/ubergeek77/tinylog"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = tlog.NewTaggedLogger("WS", tlog.NewColor("38;5;111"))
|
|
||||||
|
|
||||||
type MessageTypes float64
|
|
||||||
|
|
||||||
// todo rewrite to use an event handler system
|
|
||||||
const (
|
|
||||||
Ping MessageTypes = iota
|
|
||||||
Pong
|
|
||||||
Identify
|
|
||||||
GetPlayhead
|
|
||||||
SetPlayhead
|
|
||||||
)
|
|
||||||
|
|
||||||
type MessageData struct {
|
|
||||||
Type MessageTypes `json:"type"`
|
|
||||||
RawData json.RawMessage `json:"data,omitempty"`
|
|
||||||
Data interface{} `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
*Client
|
|
||||||
MessageData
|
|
||||||
}
|
|
||||||
|
|
||||||
type RawMessage struct {
|
|
||||||
Client *Client
|
|
||||||
Data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm RawMessage) UnserializeData() Message {
|
|
||||||
var md MessageData
|
|
||||||
if err := json.Unmarshal(rm.Data, &md); err != nil {
|
|
||||||
log.Errorf("error unmarshalling message, %s", err.Error())
|
|
||||||
}
|
|
||||||
if md.RawData != nil && len(md.RawData) > 0 {
|
|
||||||
if err := json.Unmarshal(md.RawData, &md.Data); err != nil {
|
|
||||||
// handle error
|
|
||||||
log.Errorf("error unmarshalling data, %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Message{
|
|
||||||
Client: rm.Client,
|
|
||||||
MessageData: md,
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Message) SerializeMessage() RawMessage {
|
|
||||||
var err error
|
|
||||||
if m.Data != nil {
|
|
||||||
m.RawData, err = json.Marshal(m.Data)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("unable to marshal data, %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data, err := json.Marshal(m.MessageData)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("unable to marshal message, %s", err.Error())
|
|
||||||
}
|
|
||||||
return RawMessage{
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type State struct {
|
|
||||||
sync.RWMutex
|
|
||||||
|
|
||||||
playhead float64
|
|
||||||
controllerUserId string
|
|
||||||
adminUserId string
|
|
||||||
paused bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewState() *State {
|
|
||||||
return &State{
|
|
||||||
playhead: 0,
|
|
||||||
controllerUserId: "218072060923084802",
|
|
||||||
adminUserId: "218072060923084802",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) setPlayhead(playhead float64) error {
|
|
||||||
if s == nil {
|
|
||||||
return errors.New("unable to find state")
|
|
||||||
}
|
|
||||||
s.Lock()
|
|
||||||
defer s.Unlock()
|
|
||||||
s.playhead = playhead
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (s *State) setPaused(paused bool) error {
|
|
||||||
if s == nil {
|
|
||||||
return errors.New("unable to find state")
|
|
||||||
}
|
|
||||||
s.Lock()
|
|
||||||
defer s.Unlock()
|
|
||||||
s.paused = paused
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (s *State) IsController(userID string) bool {
|
|
||||||
if userID == s.controllerUserId {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
func (s *State) IsAdmin(userID string) bool {
|
|
||||||
if userID == s.adminUserId {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package ws
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package services
|
||||||
|
|
||||||
|
import "github.com/ubergeek77/tinylog"
|
||||||
|
|
||||||
|
// LoggerService reads and updates the logger state
|
||||||
|
type LoggerService struct {
|
||||||
|
Logger tinylog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLoggerService creates a new instance of the logging service
|
||||||
|
func NewLoggerService(logger tinylog.Logger) *LoggerService {
|
||||||
|
return &LoggerService{Logger: logger}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
DISCORD_ID=
|
|
||||||
DISCORD_SECRET=
|
|
||||||
SECRET=
|
|
||||||
NEXT_PUBLIC_CLIENT_ID=
|
|
||||||
NEXTAUTH_URL=
|
|
||||||
NEXT_PUBLIC_WS_URI=
|
|
||||||
|
|
@ -32,5 +32,3 @@ yarn-error.log*
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
|
||||||
≈
|
|
||||||
|
|
@ -1 +1,39 @@
|
||||||
# frontend
|
# Example app with [chakra-ui](https://github.com/chakra-ui/chakra-ui) and TypeScript
|
||||||
|
|
||||||
|
This example features how to use [chakra-ui](https://github.com/chakra-ui/chakra-ui) as the component library within a Next.js app with TypeScript.
|
||||||
|
|
||||||
|
Next.js and chakra-ui have built-in TypeScript declarations, so we'll get autocompletion for their modules straight away.
|
||||||
|
|
||||||
|
We are connecting the Next.js `_app.js` with `chakra-ui`'s Provider and theme so the pages can have app-wide dark/light mode. We are also creating some components which shows the usage of `chakra-ui`'s style props.
|
||||||
|
|
||||||
|
## Preview
|
||||||
|
|
||||||
|
Preview the example live on [StackBlitz](http://stackblitz.com/):
|
||||||
|
|
||||||
|
[](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/with-chakra-ui-typescript)
|
||||||
|
|
||||||
|
## Deploy your own
|
||||||
|
|
||||||
|
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
|
||||||
|
|
||||||
|
[](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-chakra-ui-typescript&project-name=with-chakra-ui-typescript&repository-name=with-chakra-ui-typescript)
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
### Using `create-next-app`
|
||||||
|
|
||||||
|
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-next-app --example with-chakra-ui-typescript with-chakra-ui-typescript-app
|
||||||
|
# or
|
||||||
|
yarn create next-app --example with-chakra-ui-typescript with-chakra-ui-typescript-app
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Chakra has supported Gradients and RTL in `v1.1`. To utilize RTL, [add RTL direction and swap](https://chakra-ui.com/docs/features/rtl-support).
|
||||||
|
|
||||||
|
If you don't have multi-direction app, you should make `<Html lang="ar" dir="rtl">` inside `_document.ts`.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
|
||||||
enabled: process.env.ANALYZE === 'true'
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = withBundleAnalyzer({})
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "frontend",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next",
|
"dev": "next",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start"
|
||||||
"analyze": "cross-env ANALYZE=true next build",
|
|
||||||
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
|
|
||||||
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chakra-ui/icons": "^1.0.5",
|
"@chakra-ui/icons": "^1.0.5",
|
||||||
|
|
@ -15,30 +11,19 @@
|
||||||
"@chakra-ui/theme-tools": "1.1.2",
|
"@chakra-ui/theme-tools": "1.1.2",
|
||||||
"@emotion/react": "11.1.5",
|
"@emotion/react": "11.1.5",
|
||||||
"@emotion/styled": "11.1.5",
|
"@emotion/styled": "11.1.5",
|
||||||
"consola": "^2.15.3",
|
|
||||||
"events": "^3.3.0",
|
|
||||||
"framer-motion": "^4.0.3",
|
"framer-motion": "^4.0.3",
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"next-auth": "^4.1.2",
|
"next-auth": "^4.1.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-player": "^2.9.0",
|
"react-player": "^2.9.0",
|
||||||
"uuid": "^8.3.2",
|
"websocket": "^1.0.34"
|
||||||
"ws": "^8.4.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next/bundle-analyzer": "^12.0.8",
|
|
||||||
"@types/events": "^3.0.0",
|
|
||||||
"@types/node": "^14.6.0",
|
"@types/node": "^14.6.0",
|
||||||
"@types/react": "^17.0.3",
|
"@types/react": "^17.0.3",
|
||||||
"@types/react-dom": "^17.0.3",
|
"@types/react-dom": "^17.0.3",
|
||||||
"@types/uuid": "^8.3.4",
|
|
||||||
"@types/websocket": "^1.0.4",
|
"@types/websocket": "^1.0.4",
|
||||||
"@types/ws": "^8.2.2",
|
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"typescript": "4.3.2"
|
"typescript": "4.3.2"
|
||||||
},
|
|
||||||
"volta": {
|
|
||||||
"node": "16.13.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,19 @@
|
||||||
import React, { FC } from "react";
|
import { Flex, useColorMode, FlexProps } from '@chakra-ui/react'
|
||||||
import { Flex, useColorMode, FlexProps } from "@chakra-ui/react";
|
|
||||||
|
|
||||||
export const Container: FC<FlexProps> = (props: FlexProps) => {
|
export const Container = (props: FlexProps) => {
|
||||||
const { colorMode } = useColorMode();
|
const { colorMode } = useColorMode()
|
||||||
|
|
||||||
const bgColor = { light: "gray.50", dark: "gray.900" };
|
const bgColor = { light: 'gray.50', dark: 'gray.900' }
|
||||||
|
|
||||||
const color = { light: "black", dark: "white" };
|
const color = { light: 'black', dark: 'white' }
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
|
alignItems="center"
|
||||||
justifyContent="flex-start"
|
justifyContent="flex-start"
|
||||||
bg={bgColor[colorMode]}
|
bg={bgColor[colorMode]}
|
||||||
color={color[colorMode]}
|
color={color[colorMode]}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
Container.defaultProps = {
|
|
||||||
alignItems: "center",
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import { Box, Flex, Heading } from "@chakra-ui/layout";
|
|
||||||
import { Text } from "@chakra-ui/react";
|
|
||||||
import React, { FC } from "react";
|
|
||||||
|
|
||||||
const Header: FC = ({ children }) => {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
as="header"
|
|
||||||
position="fixed"
|
|
||||||
w="100%"
|
|
||||||
justifyContent="space-between"
|
|
||||||
outline="1"
|
|
||||||
padding="1"
|
|
||||||
>
|
|
||||||
<Flex
|
|
||||||
alignSelf="flex-start"
|
|
||||||
bgGradient="linear(to-l, #7928CA, #FF0080)"
|
|
||||||
bgClip="text"
|
|
||||||
height="100%"
|
|
||||||
>
|
|
||||||
<Heading fontSize="2rem">Watch Together</Heading>
|
|
||||||
<Text
|
|
||||||
fontStyle="italic"
|
|
||||||
ml="2"
|
|
||||||
mt="1"
|
|
||||||
fontSize="2xl"
|
|
||||||
fontWeight="semibold"
|
|
||||||
>
|
|
||||||
admin
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
|
||||||
{children}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Header;
|
|
||||||
|
|
@ -1,23 +1,12 @@
|
||||||
import { Flex, Heading, keyframes } from "@chakra-ui/react";
|
import { Flex, Heading } from "@chakra-ui/react";
|
||||||
import { css } from "@emotion/react";
|
|
||||||
|
|
||||||
const gradient = keyframes`
|
|
||||||
0% { background-position: 0% 0%; }
|
|
||||||
100% { background-position: 100% 0%; }
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const Hero = ({ title }: { title: string }) => (
|
export const Hero = ({ title }: { title: string }) => (
|
||||||
<Flex
|
<Flex
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
height="100vh"
|
height="100vh"
|
||||||
backgroundImage="linear-gradient(90deg,#cf5c5c,#c19b4a,#def2a0,#c6ee4a,#42eca6,#64b3d9,#208ea2,#498ada,#5b73df,#897ed3,#cf5c5c,#c19b4a)"
|
bgGradient="linear(to-l, #7928CA, #FF0080)"
|
||||||
backgroundSize="1100% 100%"
|
|
||||||
bgClip="text"
|
bgClip="text"
|
||||||
css={css`
|
|
||||||
animation: ${gradient} 14s linear infinite;
|
|
||||||
`}
|
|
||||||
>
|
>
|
||||||
<Heading fontSize="6vw">{title}</Heading>
|
<Heading fontSize="6vw">{title}</Heading>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,19 @@
|
||||||
import { Box } from "@chakra-ui/react";
|
import React, { FC } from "react";
|
||||||
import React, { forwardRef } from "react";
|
import ReactPlayer, { ReactPlayerProps } from "react-player";
|
||||||
import ReactPlayer, { Config, ReactPlayerProps } from "react-player";
|
|
||||||
|
|
||||||
const Player = forwardRef<ReactPlayer, ReactPlayerProps>((props, ref) => {
|
type PlayerProps = { id: string } & ReactPlayerProps;
|
||||||
const config: Config = {
|
|
||||||
|
const Player: FC<PlayerProps> = ({ id, config }) => {
|
||||||
|
return <ReactPlayer url={id} config={config} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
Player.defaultProps = {
|
||||||
|
id: "",
|
||||||
|
config: {
|
||||||
file: {
|
file: {
|
||||||
forceHLS: true,
|
forceHLS: true,
|
||||||
},
|
},
|
||||||
};
|
},
|
||||||
// useEffect(() => {
|
};
|
||||||
// if (playerRef.current && typeof props.identity !== "undefined") {
|
|
||||||
// console.log(props.identity.playhead);
|
|
||||||
// playerRef.current.seekTo(props.identity.playhead);
|
|
||||||
// setPaused(props.identity.paused);
|
|
||||||
// }
|
|
||||||
// }, []);
|
|
||||||
// socket.emitter.once(SocketEvents.SetPlayhead, (e) => {
|
|
||||||
// console.log(e);
|
|
||||||
// playerRef.current.seekTo(e.playhead);
|
|
||||||
// setPaused(e.paused);
|
|
||||||
// });
|
|
||||||
// const onSeek = (playedSeconds: number) => {
|
|
||||||
// if (!props.identity.admin) return;
|
|
||||||
// if (paused) {
|
|
||||||
// socket?.send(
|
|
||||||
// MessageUtil.encode(
|
|
||||||
// new Message(MessageTypes.SetPlayhead, {
|
|
||||||
// playhead: playedSeconds,
|
|
||||||
// paused: true,
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// socket?.send(
|
|
||||||
// MessageUtil.encode(
|
|
||||||
// new Message(MessageTypes.SetPlayhead, {
|
|
||||||
// playhead: playedSeconds,
|
|
||||||
// paused: false,
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
// const onPause = () => {
|
|
||||||
// if (!props.identity.admin) return;
|
|
||||||
// setPaused(true);
|
|
||||||
// socket?.send(
|
|
||||||
// MessageUtil.encode(
|
|
||||||
// new Message(MessageTypes.SetPlayhead, {
|
|
||||||
// playhead: playerRef.current.getCurrentTime(),
|
|
||||||
// paused: true,
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
// const onPlay = () => {
|
|
||||||
// if (!props.identity.admin) return;
|
|
||||||
// setPaused(false);
|
|
||||||
// socket?.send(
|
|
||||||
// MessageUtil.encode(
|
|
||||||
// new Message(MessageTypes.SetPlayhead, {
|
|
||||||
// playhead: playerRef.current.getCurrentTime(),
|
|
||||||
// paused: false,
|
|
||||||
// })
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
return (
|
|
||||||
<Box height="100vh" width="100vw">
|
|
||||||
<ReactPlayer
|
|
||||||
url={props.url}
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
config={config}
|
|
||||||
ref={ref}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Player;
|
export default Player;
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { Avatar } from "@chakra-ui/avatar";
|
|
||||||
import { Box, Flex, Text } from "@chakra-ui/layout";
|
|
||||||
import { Session } from "next-auth";
|
|
||||||
import React, { FC } from "react";
|
|
||||||
|
|
||||||
interface UserDataProps {
|
|
||||||
user: Session["user"];
|
|
||||||
}
|
|
||||||
|
|
||||||
const UserData: FC<UserDataProps> = ({ user: { name, image } }) => {
|
|
||||||
return (
|
|
||||||
<Flex alignSelf="flex-end" mr="2" mt="1">
|
|
||||||
<Avatar src={image} />
|
|
||||||
<Box ml="3" mt="2">
|
|
||||||
<Text fontWeight="bold">{name}</Text>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UserData;
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
import { User } from "next-auth";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import PlayerSocket from "../ws/websocket";
|
|
||||||
|
|
||||||
interface useWSProps {
|
|
||||||
user: User;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo write websocket reconnector
|
|
||||||
const useWS = ({ user }: useWSProps): PlayerSocket | null => {
|
|
||||||
if (typeof window === "undefined") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// todo checkout usecallback
|
|
||||||
const [socket, setSocket] = useState<PlayerSocket>(null);
|
|
||||||
useEffect(() => {
|
|
||||||
if (socket !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let internalSocket = new PlayerSocket(user);
|
|
||||||
setSocket(internalSocket);
|
|
||||||
return () => {
|
|
||||||
if (internalSocket.readyState !== WebSocket.OPEN) {
|
|
||||||
return internalSocket.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return socket;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useWS;
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
export enum MessageTypes {
|
|
||||||
Ping,
|
|
||||||
Pong,
|
|
||||||
Identify,
|
|
||||||
GetPlayhead,
|
|
||||||
SetPlayhead,
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMessage {
|
|
||||||
type: MessageTypes;
|
|
||||||
data?: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IMessage;
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
interface IUser {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IUser;
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import IUser from "./IUser";
|
|
||||||
|
|
||||||
interface IdentityData {
|
|
||||||
admin?: boolean;
|
|
||||||
hasController?: boolean;
|
|
||||||
clientID?: string;
|
|
||||||
playlist?: string;
|
|
||||||
playhead?: number;
|
|
||||||
paused?: boolean;
|
|
||||||
user: IUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IdentityData;
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export default interface SetPlayheadEvent {
|
|
||||||
playhead: number;
|
|
||||||
paused: boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
enum SocketEvents {
|
|
||||||
Identify = "Identify",
|
|
||||||
SetPlayhead = "SetPlayhead",
|
|
||||||
GetPlayhead = "GetPlayhead",
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SocketEvents;
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import NextDocument, { Html, Head, Main, NextScript } from "next/document";
|
import NextDocument, { Html, Head, Main, NextScript } from 'next/document'
|
||||||
import { ColorModeScript } from "@chakra-ui/react";
|
import { ColorModeScript } from '@chakra-ui/react'
|
||||||
import theme from "../theme";
|
|
||||||
|
|
||||||
export default class Document extends NextDocument {
|
export default class Document extends NextDocument {
|
||||||
render() {
|
render() {
|
||||||
|
|
@ -9,11 +8,11 @@ export default class Document extends NextDocument {
|
||||||
<Head />
|
<Head />
|
||||||
<body>
|
<body>
|
||||||
{/* Make Color mode to persists when you refresh the page. */}
|
{/* Make Color mode to persists when you refresh the page. */}
|
||||||
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
|
<ColorModeScript />
|
||||||
<Main />
|
<Main />
|
||||||
<NextScript />
|
<NextScript />
|
||||||
</body>
|
</body>
|
||||||
</Html>
|
</Html>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { Text } from "@chakra-ui/layout";
|
|
||||||
import { Flex as Box } from "@chakra-ui/react";
|
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
|
||||||
import { Session } from "next-auth";
|
|
||||||
import { getSession } from "next-auth/react";
|
|
||||||
import React from "react";
|
|
||||||
import { Container } from "../../components/Container";
|
|
||||||
import Header from "../../components/Header";
|
|
||||||
import UserData from "../../components/UserData";
|
|
||||||
|
|
||||||
interface AdminPageProps {
|
|
||||||
isAuthed: boolean;
|
|
||||||
isAdmin: boolean;
|
|
||||||
session?: Session;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AdminPage: NextPage<AdminPageProps> = ({
|
|
||||||
isAuthed,
|
|
||||||
isAdmin,
|
|
||||||
session,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Container height="100vh">
|
|
||||||
<Header>
|
|
||||||
<UserData user={session.user} />
|
|
||||||
</Header>
|
|
||||||
<Container
|
|
||||||
height="30vh"
|
|
||||||
mt="5rem"
|
|
||||||
backgroundColor="gray.700"
|
|
||||||
width="100vw"
|
|
||||||
>
|
|
||||||
<Text>Hello</Text>
|
|
||||||
</Container>
|
|
||||||
</Container>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
|
||||||
const session = await getSession(context);
|
|
||||||
if (session) {
|
|
||||||
const isAdmin = session.user.name.includes("qpixel");
|
|
||||||
if (!isAdmin) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: "/",
|
|
||||||
permanent: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
isAuthed: true,
|
|
||||||
isAdmin: isAdmin,
|
|
||||||
session: session,
|
|
||||||
} as AdminPageProps,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
isAdmin: false,
|
|
||||||
isAuthed: false,
|
|
||||||
} as AdminPageProps,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AdminPage;
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
|
||||||
import React, { useEffect } from "react";
|
|
||||||
import { Container } from "../../components/Container";
|
|
||||||
import { Text } from "@chakra-ui/react";
|
|
||||||
import { useRouter } from "next/router";
|
|
||||||
import {
|
|
||||||
getSession,
|
|
||||||
signOut,
|
|
||||||
SignOutResponse,
|
|
||||||
useSession,
|
|
||||||
} from "next-auth/react";
|
|
||||||
|
|
||||||
const SignOutPage: NextPage = () => {
|
|
||||||
const router = useRouter();
|
|
||||||
const session = useSession();
|
|
||||||
let data: SignOutResponse | null;
|
|
||||||
const signout = async () => {
|
|
||||||
data = await signOut({ redirect: false, callbackUrl: "/" });
|
|
||||||
};
|
|
||||||
if (session) {
|
|
||||||
useEffect(() => {
|
|
||||||
signout();
|
|
||||||
setTimeout(() => {
|
|
||||||
if (data) {
|
|
||||||
router.push(data.url);
|
|
||||||
} else {
|
|
||||||
router.push("/");
|
|
||||||
}
|
|
||||||
}, 600);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Container height="100vh">
|
|
||||||
<Text>Signing out!</Text>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
|
||||||
const session = await getSession(context);
|
|
||||||
if (!session) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: "/",
|
|
||||||
permanent: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
props: {},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SignOutPage;
|
|
||||||
|
|
@ -12,10 +12,4 @@ export default NextAuth({
|
||||||
jwt: {
|
jwt: {
|
||||||
secret: process.env.SECRET,
|
secret: process.env.SECRET,
|
||||||
},
|
},
|
||||||
callbacks: {
|
|
||||||
async session({ session, token }) {
|
|
||||||
session.user.id = token.sub;
|
|
||||||
return session;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,14 @@
|
||||||
import { Button, Link as ChakraLink, Text } from "@chakra-ui/react";
|
import { Button, Text } from "@chakra-ui/react";
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
import { GetServerSideProps, NextPage } from "next";
|
||||||
import { getSession, signIn } from "next-auth/react";
|
import { getSession, signIn } from "next-auth/react";
|
||||||
import Head from "next/head";
|
|
||||||
import Link from "next/link";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Container } from "../components/Container";
|
import { Container } from "../components/Container";
|
||||||
import { Footer } from "../components/Footer";
|
import { Footer } from "../components/Footer";
|
||||||
import { Hero } from "../components/Hero";
|
import { Hero } from "../components/Hero";
|
||||||
import { Main } from "../components/Main";
|
import { Main } from "../components/Main";
|
||||||
import { isDev } from "../util";
|
|
||||||
|
|
||||||
const Index: NextPage = () => {
|
const Index: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Watch Together</title>
|
|
||||||
</Head>
|
|
||||||
<Container height="100vh">
|
<Container height="100vh">
|
||||||
<Hero />
|
<Hero />
|
||||||
<Main>
|
<Main>
|
||||||
|
|
@ -23,27 +16,20 @@ const Index: NextPage = () => {
|
||||||
maxWidth="200"
|
maxWidth="200"
|
||||||
alignSelf="center"
|
alignSelf="center"
|
||||||
onClick={() => signIn("discord")}
|
onClick={() => signIn("discord")}
|
||||||
disabled={!isDev()}
|
|
||||||
>
|
>
|
||||||
Login With Discord
|
Login With Discord
|
||||||
</Button>
|
</Button>
|
||||||
</Main>
|
</Main>
|
||||||
<Footer>
|
<Footer>
|
||||||
<ChakraLink>
|
|
||||||
<Link href="https://velvox.dev">
|
|
||||||
<Text>©2022 Velvox</Text>
|
<Text>©2022 Velvox</Text>
|
||||||
</Link>
|
|
||||||
</ChakraLink>
|
|
||||||
</Footer>
|
</Footer>
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||||
const session = await getSession(context);
|
const session = getSession(context);
|
||||||
const isDev = true;
|
if (session) {
|
||||||
if (session && !isDev) {
|
|
||||||
return {
|
return {
|
||||||
redirect: {
|
redirect: {
|
||||||
destination: "/player",
|
destination: "/player",
|
||||||
|
|
|
||||||
|
|
@ -1,118 +1,16 @@
|
||||||
import { GetServerSideProps, NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import { User } from "next-auth";
|
import dynamic from "next/dynamic";
|
||||||
import { getSession } from "next-auth/react";
|
import React from "react";
|
||||||
import Head from "next/head";
|
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import ReactPlayer from "react-player";
|
|
||||||
import { Container } from "../components/Container";
|
import { Container } from "../components/Container";
|
||||||
import Player from "../components/Player";
|
|
||||||
import useWS from "../hooks/useWS";
|
|
||||||
import IdentityData from "../interfaces/Identity";
|
|
||||||
import { MessageTypes } from "../interfaces/IMessage";
|
|
||||||
import SetPlayheadEvent from "../interfaces/Playhead";
|
|
||||||
import SocketEvents from "../interfaces/SocketEvents";
|
|
||||||
import { isBrowser } from "../util";
|
|
||||||
import Message from "../util/Message";
|
|
||||||
import MessageUtil from "../util/MessageUtil";
|
|
||||||
|
|
||||||
interface PlayerPageProps {
|
const Player = dynamic(() => import("../components/Player"));
|
||||||
user: User;
|
|
||||||
}
|
|
||||||
// types for the function
|
|
||||||
|
|
||||||
const PlayerPage: NextPage<PlayerPageProps> = ({ user }) => {
|
const PlayerPage: NextPage = () => {
|
||||||
const socket = useWS({ user });
|
|
||||||
const playerRef = useRef<ReactPlayer>();
|
|
||||||
const [id, setID] = useState<string>("");
|
|
||||||
const [identity, setIdentity] = useState<IdentityData>();
|
|
||||||
const [paused, setPaused] = useState<boolean>(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isBrowser() && typeof socket !== "undefined") {
|
|
||||||
socket?.emitter.once(SocketEvents.Identify, (e: IdentityData) => {
|
|
||||||
setID(e.playlist);
|
|
||||||
setIdentity(e);
|
|
||||||
playerRef?.current.seekTo(e.playhead);
|
|
||||||
setPaused(e.paused);
|
|
||||||
});
|
|
||||||
socket?.emitter.on(SocketEvents.SetPlayhead, (e: SetPlayheadEvent) => {
|
|
||||||
console.log(e.paused);
|
|
||||||
setPaused(e.paused);
|
|
||||||
playerRef.current.seekTo(e.playhead);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [socket]);
|
|
||||||
const onPlay = () => {
|
|
||||||
if (!identity.admin) return;
|
|
||||||
setPaused(false);
|
|
||||||
socket?.send(
|
|
||||||
MessageUtil.encode(
|
|
||||||
new Message(MessageTypes.SetPlayhead, {
|
|
||||||
playhead: playerRef.current.getCurrentTime(),
|
|
||||||
paused: false,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const onSeek = (playedSeconds: number) => {
|
|
||||||
if (!identity.admin) return;
|
|
||||||
socket.send(
|
|
||||||
MessageUtil.encode(
|
|
||||||
new Message(MessageTypes.SetPlayhead, {
|
|
||||||
playhead: playedSeconds,
|
|
||||||
paused: paused,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const onPause = () => {
|
|
||||||
console.log("running now");
|
|
||||||
if (!identity.admin) return;
|
|
||||||
setPaused(true);
|
|
||||||
socket?.send(
|
|
||||||
MessageUtil.encode(
|
|
||||||
new Message(MessageTypes.SetPlayhead, {
|
|
||||||
playhead: playerRef.current.getCurrentTime(),
|
|
||||||
paused: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container height="100vh">
|
||||||
<Head>
|
<Player />
|
||||||
<title>Watch Together</title>
|
|
||||||
</Head>
|
|
||||||
<Container height="100vh" background={"#000"}>
|
|
||||||
<Player
|
|
||||||
url={id}
|
|
||||||
onPlay={onPlay}
|
|
||||||
onPause={onPause}
|
|
||||||
onSeek={onSeek}
|
|
||||||
controls={identity?.hasController}
|
|
||||||
playing={!paused}
|
|
||||||
ref={playerRef}
|
|
||||||
/>
|
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
|
||||||
const session = await getSession(context);
|
|
||||||
if (!session) {
|
|
||||||
return {
|
|
||||||
redirect: {
|
|
||||||
destination: "/",
|
|
||||||
permanent: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
user: session.user,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PlayerPage;
|
export default PlayerPage;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import IMessage, { MessageTypes } from "../interfaces/IMessage";
|
|
||||||
|
|
||||||
export default class Message implements IMessage {
|
|
||||||
constructor(public type: MessageTypes, public data?: unknown) {}
|
|
||||||
|
|
||||||
toJSON(): Record<string, unknown> {
|
|
||||||
return {
|
|
||||||
type: this.type,
|
|
||||||
data: this.data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
// inspired by aether/aero
|
|
||||||
|
|
||||||
import Message from "./Message";
|
|
||||||
|
|
||||||
export default class MessageUtil {
|
|
||||||
static encode(message: Message): string {
|
|
||||||
return JSON.stringify(message);
|
|
||||||
}
|
|
||||||
static decode(message: string): Message | null {
|
|
||||||
const parsed = JSON.parse(message);
|
|
||||||
if (typeof parsed.type !== "number") {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Message(parsed.type, parsed.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
const useAPI = () => {};
|
||||||
|
|
||||||
|
export default useAPI;
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
export function isDev() {
|
|
||||||
return process.env.NODE_ENV === "development";
|
|
||||||
}
|
|
||||||
export function isBrowser() {
|
|
||||||
return typeof window !== "undefined";
|
|
||||||
}
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
import { User } from "next-auth";
|
|
||||||
import EventEmitter from "events";
|
|
||||||
import IdentityData from "../interfaces/Identity";
|
|
||||||
import { MessageTypes } from "../interfaces/IMessage";
|
|
||||||
import Message from "../util/Message";
|
|
||||||
import MessageUtil from "../util/MessageUtil";
|
|
||||||
|
|
||||||
// browser socket
|
|
||||||
// todo: write a shim for this
|
|
||||||
let Websocket: typeof WebSocket;
|
|
||||||
if (typeof window !== "undefined") {
|
|
||||||
Websocket = window.WebSocket;
|
|
||||||
} else {
|
|
||||||
Websocket = require("ws");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class PlayerSocket extends Websocket {
|
|
||||||
private clientID: string;
|
|
||||||
public emitter: EventEmitter;
|
|
||||||
constructor(private user: User) {
|
|
||||||
super(process.env.NEXT_PUBLIC_WS_URI);
|
|
||||||
this.emitter = new EventEmitter();
|
|
||||||
this.clientID = process.env.NEXT_PUBLIC_CLIENT_ID;
|
|
||||||
this.onopen = this.onOpen;
|
|
||||||
this.onmessage = this.onMessage;
|
|
||||||
this.onclose = this.onClose;
|
|
||||||
}
|
|
||||||
close(code?: number, reason?: string): void {
|
|
||||||
this.emitter.removeAllListeners();
|
|
||||||
super.close(code, reason);
|
|
||||||
}
|
|
||||||
onMessage(evt: MessageEvent<any>) {
|
|
||||||
let message = MessageUtil.decode(evt.data);
|
|
||||||
if (message.type === MessageTypes["Ping"]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.emitter.emit(MessageTypes[message.type], message.data);
|
|
||||||
}
|
|
||||||
onOpen() {
|
|
||||||
this.send(
|
|
||||||
MessageUtil.encode(
|
|
||||||
new Message(MessageTypes.Identify, {
|
|
||||||
clientID: this.clientID,
|
|
||||||
user: {
|
|
||||||
id: this.user.id,
|
|
||||||
name: this.user.name,
|
|
||||||
},
|
|
||||||
} as IdentityData)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.emitter.emit("open");
|
|
||||||
this.pingEvent();
|
|
||||||
}
|
|
||||||
pingEvent() {
|
|
||||||
let interval = setInterval(() => {
|
|
||||||
if (!this.open) {
|
|
||||||
clearInterval(interval);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("[WS] running ping event");
|
|
||||||
this.send(
|
|
||||||
MessageUtil.encode(
|
|
||||||
new Message(MessageTypes.Ping, {
|
|
||||||
clientID: this.clientID,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}, 20000);
|
|
||||||
}
|
|
||||||
onClose(event: CloseEvent) {
|
|
||||||
console.log("[WS] socket connection closed");
|
|
||||||
this.emitter.emit("closed");
|
|
||||||
}
|
|
||||||
get open() {
|
|
||||||
return this.readyState === this.OPEN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,9 +12,8 @@
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve"
|
||||||
"typeRoots": ["types/"]
|
|
||||||
},
|
},
|
||||||
"include": ["types/*.d.ts", "**/*.ts", "**/*.tsx", "next-seo.config.js"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ declare namespace NodeJS {
|
||||||
export interface ProcessEnv {
|
export interface ProcessEnv {
|
||||||
DISCORD_ID: string;
|
DISCORD_ID: string;
|
||||||
DISCORD_SECRET: string;
|
DISCORD_SECRET: string;
|
||||||
|
API_PORT: string;
|
||||||
SECRET: string;
|
SECRET: string;
|
||||||
NEXT_PUBLIC_CLIENT_ID: string;
|
|
||||||
NEXT_PUBLIC_WS_URI: string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import NextAuth, { Session as NextSession, User as NextUser } from "next-auth";
|
|
||||||
|
|
||||||
declare module "next-auth" {
|
|
||||||
interface User extends NextUser {
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
interface Session extends NextSession {
|
|
||||||
user: User;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -818,13 +818,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
|
resolved "https://registry.yarnpkg.com/@napi-rs/triples/-/triples-1.0.3.tgz#76d6d0c3f4d16013c61e45dfca5ff1e6c31ae53c"
|
||||||
integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
|
integrity sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA==
|
||||||
|
|
||||||
"@next/bundle-analyzer@^12.0.8":
|
|
||||||
version "12.0.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.0.8.tgz#a4fef1b14f8a4a87c09d97a3d909deddc88d12f8"
|
|
||||||
integrity sha512-tRwFyAkJA0h+rwt4exq31T59qo4qwp7vPoR3yC8gIpK/E5NAwafyk40aNpk4OWhiQ2IvJMFutukMzY3xl79NXA==
|
|
||||||
dependencies:
|
|
||||||
webpack-bundle-analyzer "4.3.0"
|
|
||||||
|
|
||||||
"@next/env@12.0.7":
|
"@next/env@12.0.7":
|
||||||
version "12.0.7"
|
version "12.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.7.tgz#316f7bd1b6b69f554d2676cfc91a16bc7e32ee79"
|
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.0.7.tgz#316f7bd1b6b69f554d2676cfc91a16bc7e32ee79"
|
||||||
|
|
@ -917,11 +910,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.1.tgz#ed0da773bd5f794d0603f5a5b5cee6d2354e5660"
|
resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.1.tgz#ed0da773bd5f794d0603f5a5b5cee6d2354e5660"
|
||||||
integrity sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg==
|
integrity sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg==
|
||||||
|
|
||||||
"@polka/url@^1.0.0-next.20":
|
|
||||||
version "1.0.0-next.21"
|
|
||||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
|
|
||||||
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
|
|
||||||
|
|
||||||
"@popperjs/core@^2.9.3":
|
"@popperjs/core@^2.9.3":
|
||||||
version "2.11.0"
|
version "2.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.0.tgz#6734f8ebc106a0860dff7f92bf90df193f0935d7"
|
||||||
|
|
@ -954,11 +942,6 @@
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
tslib "^2.1.0"
|
tslib "^2.1.0"
|
||||||
|
|
||||||
"@types/events@^3.0.0":
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
|
||||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
|
||||||
|
|
||||||
"@types/lodash.mergewith@4.6.6":
|
"@types/lodash.mergewith@4.6.6":
|
||||||
version "4.6.6"
|
version "4.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10"
|
resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10"
|
||||||
|
|
@ -1017,11 +1000,6 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf"
|
resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf"
|
||||||
integrity sha512-PeHg/AtdW6aaIO2a+98Xj7rWY4KC1E6yOy7AFknJQ7VXUGNrMlyxDFxJo7HqLtjQms/ZhhQX52mLVW/EX3JGOw==
|
integrity sha512-PeHg/AtdW6aaIO2a+98Xj7rWY4KC1E6yOy7AFknJQ7VXUGNrMlyxDFxJo7HqLtjQms/ZhhQX52mLVW/EX3JGOw==
|
||||||
|
|
||||||
"@types/uuid@^8.3.4":
|
|
||||||
version "8.3.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
|
|
||||||
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
|
|
||||||
|
|
||||||
"@types/warning@^3.0.0":
|
"@types/warning@^3.0.0":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
|
resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
|
||||||
|
|
@ -1034,28 +1012,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
"@types/ws@^8.2.2":
|
|
||||||
version "8.2.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.2.2.tgz#7c5be4decb19500ae6b3d563043cd407bf366c21"
|
|
||||||
integrity sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==
|
|
||||||
dependencies:
|
|
||||||
"@types/node" "*"
|
|
||||||
|
|
||||||
acorn-walk@^8.0.0:
|
|
||||||
version "8.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
|
|
||||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
|
|
||||||
|
|
||||||
acorn@8.5.0:
|
acorn@8.5.0:
|
||||||
version "8.5.0"
|
version "8.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2"
|
||||||
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==
|
||||||
|
|
||||||
acorn@^8.0.4:
|
|
||||||
version "8.7.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
|
|
||||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
|
|
||||||
|
|
||||||
anser@1.4.9:
|
anser@1.4.9:
|
||||||
version "1.4.9"
|
version "1.4.9"
|
||||||
resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760"
|
resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.9.tgz#1f85423a5dcf8da4631a341665ff675b96845760"
|
||||||
|
|
@ -1251,6 +1212,13 @@ buffer@5.6.0:
|
||||||
base64-js "^1.0.2"
|
base64-js "^1.0.2"
|
||||||
ieee754 "^1.1.4"
|
ieee754 "^1.1.4"
|
||||||
|
|
||||||
|
bufferutil@^4.0.1:
|
||||||
|
version "4.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433"
|
||||||
|
integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build "^4.3.0"
|
||||||
|
|
||||||
builtin-status-codes@^3.0.0:
|
builtin-status-codes@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
|
|
@ -1296,14 +1264,6 @@ chalk@4.0.0:
|
||||||
ansi-styles "^4.1.0"
|
ansi-styles "^4.1.0"
|
||||||
supports-color "^7.1.0"
|
supports-color "^7.1.0"
|
||||||
|
|
||||||
chalk@^4.1.0:
|
|
||||||
version "4.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^4.1.0"
|
|
||||||
supports-color "^7.1.0"
|
|
||||||
|
|
||||||
chokidar@3.5.1:
|
chokidar@3.5.1:
|
||||||
version "3.5.1"
|
version "3.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
|
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a"
|
||||||
|
|
@ -1361,11 +1321,6 @@ colorette@^1.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
|
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
|
||||||
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
|
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
|
||||||
|
|
||||||
commander@^6.2.0:
|
|
||||||
version "6.2.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
|
|
||||||
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
|
|
||||||
|
|
||||||
commondir@^1.0.1:
|
commondir@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||||
|
|
@ -1376,11 +1331,6 @@ compute-scroll-into-view@1.0.14:
|
||||||
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz#80e3ebb25d6aa89f42e533956cb4b16a04cfe759"
|
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz#80e3ebb25d6aa89f42e533956cb4b16a04cfe759"
|
||||||
integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==
|
integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ==
|
||||||
|
|
||||||
consola@^2.15.3:
|
|
||||||
version "2.15.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550"
|
|
||||||
integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==
|
|
||||||
|
|
||||||
constants-browserify@1.0.0:
|
constants-browserify@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||||
|
|
@ -1454,22 +1404,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
sha.js "^2.4.8"
|
sha.js "^2.4.8"
|
||||||
|
|
||||||
cross-env@^7.0.3:
|
|
||||||
version "7.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
|
||||||
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
|
||||||
dependencies:
|
|
||||||
cross-spawn "^7.0.1"
|
|
||||||
|
|
||||||
cross-spawn@^7.0.1:
|
|
||||||
version "7.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
|
||||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
|
||||||
dependencies:
|
|
||||||
path-key "^3.1.0"
|
|
||||||
shebang-command "^2.0.0"
|
|
||||||
which "^2.0.1"
|
|
||||||
|
|
||||||
crypto-browserify@3.12.0:
|
crypto-browserify@3.12.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||||
|
|
@ -1518,12 +1452,20 @@ csstype@^3.0.2, csstype@^3.0.9:
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5"
|
||||||
integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
|
integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==
|
||||||
|
|
||||||
|
d@1, d@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
|
||||||
|
integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
|
||||||
|
dependencies:
|
||||||
|
es5-ext "^0.10.50"
|
||||||
|
type "^1.0.1"
|
||||||
|
|
||||||
data-uri-to-buffer@3.0.1:
|
data-uri-to-buffer@3.0.1:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
|
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
|
||||||
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
|
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
|
||||||
|
|
||||||
debug@2:
|
debug@2, debug@^2.2.0:
|
||||||
version "2.6.9"
|
version "2.6.9"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||||
|
|
@ -1574,11 +1516,6 @@ domain-browser@4.19.0:
|
||||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
|
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.19.0.tgz#1093e17c0a17dbd521182fe90d49ac1370054af1"
|
||||||
integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==
|
integrity sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==
|
||||||
|
|
||||||
duplexer@^0.1.2:
|
|
||||||
version "0.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
|
|
||||||
integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
|
|
||||||
|
|
||||||
electron-to-chromium@^1.3.723:
|
electron-to-chromium@^1.3.723:
|
||||||
version "1.4.26"
|
version "1.4.26"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.26.tgz#d71b9da220543cf10614a576c3d5ebbe43d96efb"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.26.tgz#d71b9da220543cf10614a576c3d5ebbe43d96efb"
|
||||||
|
|
@ -1651,11 +1588,37 @@ es-to-primitive@^1.2.1:
|
||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
|
es5-ext@^0.10.35, es5-ext@^0.10.50:
|
||||||
|
version "0.10.53"
|
||||||
|
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
|
||||||
|
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
|
||||||
|
dependencies:
|
||||||
|
es6-iterator "~2.0.3"
|
||||||
|
es6-symbol "~3.1.3"
|
||||||
|
next-tick "~1.0.0"
|
||||||
|
|
||||||
|
es6-iterator@~2.0.3:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
|
||||||
|
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
|
||||||
|
dependencies:
|
||||||
|
d "1"
|
||||||
|
es5-ext "^0.10.35"
|
||||||
|
es6-symbol "^3.1.1"
|
||||||
|
|
||||||
es6-object-assign@^1.1.0:
|
es6-object-assign@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
|
resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
|
||||||
integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
|
integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
|
||||||
|
|
||||||
|
es6-symbol@^3.1.1, es6-symbol@~3.1.3:
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
|
||||||
|
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
|
||||||
|
dependencies:
|
||||||
|
d "^1.0.1"
|
||||||
|
ext "^1.1.2"
|
||||||
|
|
||||||
escalade@^3.1.1:
|
escalade@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||||
|
|
@ -1676,7 +1639,7 @@ etag@1.8.1:
|
||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
|
||||||
|
|
||||||
events@3.3.0, events@^3.3.0:
|
events@3.3.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
|
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
|
||||||
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
|
||||||
|
|
@ -1689,6 +1652,13 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
||||||
md5.js "^1.3.4"
|
md5.js "^1.3.4"
|
||||||
safe-buffer "^5.1.1"
|
safe-buffer "^5.1.1"
|
||||||
|
|
||||||
|
ext@^1.1.2:
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52"
|
||||||
|
integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==
|
||||||
|
dependencies:
|
||||||
|
type "^2.5.0"
|
||||||
|
|
||||||
fill-range@^7.0.1:
|
fill-range@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
|
||||||
|
|
@ -1806,13 +1776,6 @@ graceful-fs@^4.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
|
||||||
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
|
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
|
||||||
|
|
||||||
gzip-size@^6.0.0:
|
|
||||||
version "6.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
|
|
||||||
integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
|
|
||||||
dependencies:
|
|
||||||
duplexer "^0.1.2"
|
|
||||||
|
|
||||||
has-bigints@^1.0.1:
|
has-bigints@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
|
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
|
||||||
|
|
@ -2097,6 +2060,11 @@ is-typed-array@^1.1.3, is-typed-array@^1.1.7:
|
||||||
foreach "^2.0.5"
|
foreach "^2.0.5"
|
||||||
has-tostringtag "^1.0.0"
|
has-tostringtag "^1.0.0"
|
||||||
|
|
||||||
|
is-typedarray@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||||
|
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
|
||||||
|
|
||||||
is-weakref@^1.0.1:
|
is-weakref@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
|
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
|
||||||
|
|
@ -2104,11 +2072,6 @@ is-weakref@^1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind "^1.0.2"
|
call-bind "^1.0.2"
|
||||||
|
|
||||||
isexe@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
|
||||||
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
|
|
||||||
|
|
||||||
jest-worker@27.0.0-next.5:
|
jest-worker@27.0.0-next.5:
|
||||||
version "27.0.0-next.5"
|
version "27.0.0-next.5"
|
||||||
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28"
|
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.0-next.5.tgz#5985ee29b12a4e191f4aae4bb73b97971d86ec28"
|
||||||
|
|
@ -2176,11 +2139,6 @@ lodash.sortby@^4.7.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||||
|
|
||||||
lodash@^4.17.20:
|
|
||||||
version "4.17.21"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
|
||||||
|
|
||||||
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
|
@ -2244,11 +2202,6 @@ minimist@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||||
|
|
||||||
mrmime@^1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b"
|
|
||||||
integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==
|
|
||||||
|
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
|
@ -2274,6 +2227,11 @@ next-auth@^4.1.2:
|
||||||
preact-render-to-string "^5.1.19"
|
preact-render-to-string "^5.1.19"
|
||||||
uuid "^8.3.2"
|
uuid "^8.3.2"
|
||||||
|
|
||||||
|
next-tick@~1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
||||||
|
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
|
||||||
|
|
||||||
next@latest:
|
next@latest:
|
||||||
version "12.0.7"
|
version "12.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/next/-/next-12.0.7.tgz#33ebf229b81b06e583ab5ae7613cffe1ca2103fc"
|
resolved "https://registry.yarnpkg.com/next/-/next-12.0.7.tgz#33ebf229b81b06e583ab5ae7613cffe1ca2103fc"
|
||||||
|
|
@ -2346,6 +2304,11 @@ node-fetch@2.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
|
node-gyp-build@^4.3.0:
|
||||||
|
version "4.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
|
||||||
|
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
|
||||||
|
|
||||||
node-html-parser@1.4.9:
|
node-html-parser@1.4.9:
|
||||||
version "1.4.9"
|
version "1.4.9"
|
||||||
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c"
|
resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c"
|
||||||
|
|
@ -2411,11 +2374,6 @@ oidc-token-hash@^5.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6"
|
resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6"
|
||||||
integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==
|
integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==
|
||||||
|
|
||||||
opener@^1.5.2:
|
|
||||||
version "1.5.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
|
|
||||||
integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
|
|
||||||
|
|
||||||
openid-client@^5.1.0:
|
openid-client@^5.1.0:
|
||||||
version "5.1.2"
|
version "5.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.1.2.tgz#a80cc6a7d8d7159ad97c51781338f5a954396bba"
|
resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.1.2.tgz#a80cc6a7d8d7159ad97c51781338f5a954396bba"
|
||||||
|
|
@ -2500,11 +2458,6 @@ path-exists@^4.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||||
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
|
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
|
||||||
|
|
||||||
path-key@^3.1.0:
|
|
||||||
version "3.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
|
||||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
|
||||||
|
|
||||||
path-parse@^1.0.6:
|
path-parse@^1.0.6:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||||
|
|
@ -2835,18 +2788,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
shebang-command@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
|
||||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
|
||||||
dependencies:
|
|
||||||
shebang-regex "^3.0.0"
|
|
||||||
|
|
||||||
shebang-regex@^3.0.0:
|
|
||||||
version "3.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
|
||||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
|
||||||
|
|
||||||
shell-quote@1.7.3:
|
shell-quote@1.7.3:
|
||||||
version "1.7.3"
|
version "1.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
|
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
|
||||||
|
|
@ -2861,15 +2802,6 @@ side-channel@^1.0.4:
|
||||||
get-intrinsic "^1.0.2"
|
get-intrinsic "^1.0.2"
|
||||||
object-inspect "^1.9.0"
|
object-inspect "^1.9.0"
|
||||||
|
|
||||||
sirv@^1.0.7:
|
|
||||||
version "1.0.19"
|
|
||||||
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49"
|
|
||||||
integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==
|
|
||||||
dependencies:
|
|
||||||
"@polka/url" "^1.0.0-next.20"
|
|
||||||
mrmime "^1.0.0"
|
|
||||||
totalist "^1.0.0"
|
|
||||||
|
|
||||||
source-map@0.7.3:
|
source-map@0.7.3:
|
||||||
version "0.7.3"
|
version "0.7.3"
|
||||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
|
||||||
|
|
@ -3061,11 +2993,6 @@ toidentifier@1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||||
|
|
||||||
totalist@^1.0.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
|
||||||
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
|
|
||||||
|
|
||||||
tr46@^1.0.1:
|
tr46@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||||
|
|
@ -3093,6 +3020,23 @@ type-fest@^0.7.1:
|
||||||
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
|
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48"
|
||||||
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
|
integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==
|
||||||
|
|
||||||
|
type@^1.0.1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
|
||||||
|
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
|
||||||
|
|
||||||
|
type@^2.5.0:
|
||||||
|
version "2.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/type/-/type-2.5.0.tgz#0a2e78c2e77907b252abe5f298c1b01c63f0db3d"
|
||||||
|
integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==
|
||||||
|
|
||||||
|
typedarray-to-buffer@^3.1.5:
|
||||||
|
version "3.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||||
|
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
|
||||||
|
dependencies:
|
||||||
|
is-typedarray "^1.0.0"
|
||||||
|
|
||||||
typescript@4.3.2:
|
typescript@4.3.2:
|
||||||
version "4.3.2"
|
version "4.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
|
||||||
|
|
@ -3133,6 +3077,13 @@ use-subscription@1.5.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
utf-8-validate@^5.0.2:
|
||||||
|
version "5.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.8.tgz#4a735a61661dbb1c59a0868c397d2fe263f14e58"
|
||||||
|
integrity sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build "^4.3.0"
|
||||||
|
|
||||||
util-deprecate@^1.0.1:
|
util-deprecate@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||||
|
|
@ -3180,20 +3131,17 @@ webidl-conversions@^4.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||||
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
||||||
|
|
||||||
webpack-bundle-analyzer@4.3.0:
|
websocket@^1.0.34:
|
||||||
version "4.3.0"
|
version "1.0.34"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b"
|
resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111"
|
||||||
integrity sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA==
|
integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn "^8.0.4"
|
bufferutil "^4.0.1"
|
||||||
acorn-walk "^8.0.0"
|
debug "^2.2.0"
|
||||||
chalk "^4.1.0"
|
es5-ext "^0.10.50"
|
||||||
commander "^6.2.0"
|
typedarray-to-buffer "^3.1.5"
|
||||||
gzip-size "^6.0.0"
|
utf-8-validate "^5.0.2"
|
||||||
lodash "^4.17.20"
|
yaeti "^0.0.6"
|
||||||
opener "^1.5.2"
|
|
||||||
sirv "^1.0.7"
|
|
||||||
ws "^7.3.1"
|
|
||||||
|
|
||||||
whatwg-url@^7.0.0:
|
whatwg-url@^7.0.0:
|
||||||
version "7.1.0"
|
version "7.1.0"
|
||||||
|
|
@ -3227,28 +3175,16 @@ which-typed-array@^1.1.2:
|
||||||
has-tostringtag "^1.0.0"
|
has-tostringtag "^1.0.0"
|
||||||
is-typed-array "^1.1.7"
|
is-typed-array "^1.1.7"
|
||||||
|
|
||||||
which@^2.0.1:
|
|
||||||
version "2.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
|
||||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
|
||||||
dependencies:
|
|
||||||
isexe "^2.0.0"
|
|
||||||
|
|
||||||
ws@^7.3.1:
|
|
||||||
version "7.5.6"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b"
|
|
||||||
integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==
|
|
||||||
|
|
||||||
ws@^8.4.2:
|
|
||||||
version "8.4.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b"
|
|
||||||
integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==
|
|
||||||
|
|
||||||
xtend@^4.0.2:
|
xtend@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||||
|
|
||||||
|
yaeti@^0.0.6:
|
||||||
|
version "0.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
|
||||||
|
integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=
|
||||||
|
|
||||||
yallist@^4.0.0:
|
yallist@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue