diff --git a/Makefile b/Makefile index 7300af9..3ed659f 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ clean: run: clean @go run $(BUILD_FLAGS) main.go $(ARGS) -install: gen +install: @echo $(GOPATH) @echo "Commit Hash: `git rev-parse HEAD`" @echo "Old Hash: `shasum $(GOPATH)/bin/$(BINARY) 2>/dev/null | cut -c -32`" diff --git a/cmd/internal/serv/actions.go b/cmd/internal/serv/actions.go index 6fb5651..e04c845 100644 --- a/cmd/internal/serv/actions.go +++ b/cmd/internal/serv/actions.go @@ -3,13 +3,11 @@ package serv import ( "fmt" "net/http" - - "github.com/dosco/super-graph/config" ) type actionFn func(w http.ResponseWriter, r *http.Request) error -func newAction(a *config.Action) (http.Handler, error) { +func newAction(a *Action) (http.Handler, error) { var fn actionFn var err error @@ -32,7 +30,7 @@ func newAction(a *config.Action) (http.Handler, error) { return http.HandlerFunc(httpFn), nil } -func newSQLAction(a *config.Action) (actionFn, error) { +func newSQLAction(a *Action) (actionFn, error) { fn := func(w http.ResponseWriter, r *http.Request) error { _, err := db.ExecContext(r.Context(), a.SQL) return err diff --git a/cmd/internal/serv/api.go b/cmd/internal/serv/api.go new file mode 100644 index 0000000..1e2cf9c --- /dev/null +++ b/cmd/internal/serv/api.go @@ -0,0 +1,106 @@ +package serv + +import ( + "time" + + "github.com/dosco/super-graph/cmd/internal/serv/internal/auth" + "github.com/dosco/super-graph/core" + + "github.com/spf13/viper" +) + +const ( + LogLevelNone int = iota + LogLevelInfo + LogLevelWarn + LogLevelError + LogLevelDebug +) + +type Core = core.Config + +// Config struct holds the Super Graph config values +type Config struct { + Core `mapstructure:",squash"` + Serv `mapstructure:",squash"` + + cpath string + vi *viper.Viper +} + +// Serv struct contains config values used by the Super Graph service +type Serv struct { + AppName string `mapstructure:"app_name"` + Production bool + LogLevel string `mapstructure:"log_level"` + HostPort string `mapstructure:"host_port"` + Host string + Port string + HTTPGZip bool `mapstructure:"http_compress"` + WebUI bool `mapstructure:"web_ui"` + EnableTracing bool `mapstructure:"enable_tracing"` + WatchAndReload bool `mapstructure:"reload_on_config_change"` + AuthFailBlock bool `mapstructure:"auth_fail_block"` + SeedFile string `mapstructure:"seed_file"` + MigrationsPath string `mapstructure:"migrations_path"` + AllowedOrigins []string `mapstructure:"cors_allowed_origins"` + DebugCORS bool `mapstructure:"cors_debug"` + + Auth auth.Auth + Auths []auth.Auth + + DB struct { + Type string + Host string + Port uint16 + DBName string + User string + Password string + Schema string + PoolSize int32 `mapstructure:"pool_size"` + MaxRetries int `mapstructure:"max_retries"` + PingTimeout time.Duration `mapstructure:"ping_timeout"` + } `mapstructure:"database"` + + Actions []Action +} + +// Auth struct contains authentication related config values used by the Super Graph service +type Auth struct { + Name string + Type string + Cookie string + CredsInHeader bool `mapstructure:"creds_in_header"` + + Rails struct { + Version string + SecretKeyBase string `mapstructure:"secret_key_base"` + URL string + Password string + MaxIdle int `mapstructure:"max_idle"` + MaxActive int `mapstructure:"max_active"` + Salt string + SignSalt string `mapstructure:"sign_salt"` + AuthSalt string `mapstructure:"auth_salt"` + } + + JWT struct { + Provider string + Secret string + PubKeyFile string `mapstructure:"public_key_file"` + PubKeyType string `mapstructure:"public_key_type"` + } + + Header struct { + Name string + Value string + Exists bool + } +} + +// Action struct contains config values for a Super Graph service action +type Action struct { + Name string + SQL string + AuthName string `mapstructure:"auth_name"` +} diff --git a/cmd/internal/serv/cmd.go b/cmd/internal/serv/cmd.go index 4c45a13..0a14764 100644 --- a/cmd/internal/serv/cmd.go +++ b/cmd/internal/serv/cmd.go @@ -6,11 +6,8 @@ import ( _log "log" "os" "runtime" - "strings" - "github.com/dosco/super-graph/config" "github.com/spf13/cobra" - "github.com/spf13/viper" "go.uber.org/zap" ) @@ -29,12 +26,13 @@ var ( ) var ( - log *_log.Logger // logger - zlog *zap.Logger // fast logger - conf *config.Config // parsed config - confPath string // path to the config file - db *sql.DB // database connection pool - secretKey [32]byte // encryption key + log *_log.Logger // logger + zlog *zap.Logger // fast logger + logLevel int // log level + conf *Config // parsed config + confPath string // path to the config file + db *sql.DB // database connection pool + secretKey [32]byte // encryption key ) func Cmd() { @@ -132,12 +130,12 @@ e.g. db:migrate -+1 Run: cmdNew, }) - rootCmd.AddCommand(&cobra.Command{ - Use: fmt.Sprintf("conf:dump [%s]", strings.Join(viper.SupportedExts, "|")), - Short: "Dump config to file", - Long: "Dump current config to a file in the selected format", - Run: cmdConfDump, - }) + // rootCmd.AddCommand(&cobra.Command{ + // Use: fmt.Sprintf("conf:dump [%s]", strings.Join(viper.SupportedExts, "|")), + // Short: "Dump config to file", + // Long: "Dump current config to a file in the selected format", + // Run: cmdConfDump, + // }) rootCmd.AddCommand(&cobra.Command{ Use: "version", diff --git a/cmd/internal/serv/cmd_conf.go b/cmd/internal/serv/cmd_conf.go index 7e75aaa..3723812 100644 --- a/cmd/internal/serv/cmd_conf.go +++ b/cmd/internal/serv/cmd_conf.go @@ -1,29 +1,21 @@ package serv -import ( - "fmt" - "os" +// func cmdConfDump(cmd *cobra.Command, args []string) { +// if len(args) != 1 { +// cmd.Help() //nolint: errcheck +// os.Exit(1) +// } - "github.com/dosco/super-graph/config" - "github.com/spf13/cobra" -) +// fname := fmt.Sprintf("%s.%s", config.GetConfigName(), args[0]) -func cmdConfDump(cmd *cobra.Command, args []string) { - if len(args) != 1 { - cmd.Help() //nolint: errcheck - os.Exit(1) - } +// conf, err := initConf() +// if err != nil { +// log.Fatalf("ERR failed to read config: %s", err) +// } - fname := fmt.Sprintf("%s.%s", config.GetConfigName(), args[0]) +// if err := conf.WriteConfigAs(fname); err != nil { +// log.Fatalf("ERR failed to write config: %s", err) +// } - conf, err := initConf() - if err != nil { - log.Fatalf("ERR failed to read config: %s", err) - } - - if err := conf.WriteConfigAs(fname); err != nil { - log.Fatalf("ERR failed to write config: %s", err) - } - - log.Printf("INF config dumped to ./%s", fname) -} +// log.Printf("INF config dumped to ./%s", fname) +// } diff --git a/cmd/internal/serv/cmd_migrate.go b/cmd/internal/serv/cmd_migrate.go index eebac77..b133bd8 100644 --- a/cmd/internal/serv/cmd_migrate.go +++ b/cmd/internal/serv/cmd_migrate.go @@ -26,7 +26,7 @@ func cmdDBSetup(cmd *cobra.Command, args []string) { cmdDBCreate(cmd, []string{}) cmdDBMigrate(cmd, []string{"up"}) - sfile := path.Join(conf.ConfigPathUsed(), conf.SeedFile) + sfile := path.Join(conf.cpath, conf.SeedFile) _, err := os.Stat(sfile) if err == nil { @@ -144,7 +144,7 @@ func cmdDBMigrate(cmd *cobra.Command, args []string) { m.Data = getMigrationVars() - err = m.LoadMigrations(path.Join(conf.ConfigPathUsed(), conf.MigrationsPath)) + err = m.LoadMigrations(path.Join(conf.cpath, conf.MigrationsPath)) if err != nil { log.Fatalf("ERR failed to load migrations: %s", err) } diff --git a/cmd/internal/serv/cmd_seed.go b/cmd/internal/serv/cmd_seed.go index c2d160b..18ee186 100644 --- a/cmd/internal/serv/cmd_seed.go +++ b/cmd/internal/serv/cmd_seed.go @@ -33,14 +33,14 @@ func cmdDBSeed(cmd *cobra.Command, args []string) { log.Fatalf("ERR failed to connect to database: %s", err) } - sfile := path.Join(conf.ConfigPathUsed(), conf.SeedFile) + sfile := path.Join(conf.cpath, conf.SeedFile) b, err := ioutil.ReadFile(sfile) if err != nil { log.Fatalf("ERR failed to read seed file %s: %s", sfile, err) } - sg, err = core.NewSuperGraph(conf, db) + sg, err = core.NewSuperGraph(&conf.Core, db) if err != nil { log.Fatalf("ERR failed to initialize Super Graph: %s", err) } diff --git a/cmd/internal/serv/cmd_serv.go b/cmd/internal/serv/cmd_serv.go index 7c8a3b7..3a20f73 100644 --- a/cmd/internal/serv/cmd_serv.go +++ b/cmd/internal/serv/cmd_serv.go @@ -28,7 +28,7 @@ func cmdServ(cmd *cobra.Command, args []string) { // initResolvers() // } - sg, err = core.NewSuperGraph(conf, db) + sg, err = core.NewSuperGraph(&conf.Core, db) if err != nil { fatalInProd(err, "failed to initialize Super Graph") } diff --git a/cmd/internal/serv/config.go b/cmd/internal/serv/config.go new file mode 100644 index 0000000..1dd1206 --- /dev/null +++ b/cmd/internal/serv/config.go @@ -0,0 +1,115 @@ +package serv + +import ( + "fmt" + "os" + "path" + "strings" + + "github.com/spf13/viper" +) + +// ReadInConfig function reads in the config file for the environment specified in the GO_ENV +// environment variable. This is the best way to create a new Super Graph config. +func ReadInConfig(configFile string) (*Config, error) { + cpath := path.Dir(configFile) + cfile := path.Base(configFile) + vi := newViper(cpath, cfile) + + if err := vi.ReadInConfig(); err != nil { + return nil, err + } + + inherits := vi.GetString("inherits") + + if len(inherits) != 0 { + vi = newViper(cpath, inherits) + + if err := vi.ReadInConfig(); err != nil { + return nil, err + } + + if vi.IsSet("inherits") { + return nil, fmt.Errorf("inherited config (%s) cannot itself inherit (%s)", + inherits, + vi.GetString("inherits")) + } + + vi.SetConfigName(cfile) + + if err := vi.MergeInConfig(); err != nil { + return nil, err + } + } + + c := &Config{cpath: cpath, vi: vi} + + if err := vi.Unmarshal(&c); err != nil { + return nil, fmt.Errorf("failed to decode config, %v", err) + } + + if len(c.Core.AllowListFile) == 0 { + c.Core.AllowListFile = path.Join(cpath, "allow.list") + } + + return c, nil +} + +func newViper(configPath, configFile string) *viper.Viper { + vi := viper.New() + + vi.SetEnvPrefix("SG") + vi.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + vi.AutomaticEnv() + + vi.AddConfigPath(configPath) + vi.SetConfigName(configFile) + vi.AddConfigPath("./config") + + vi.SetDefault("host_port", "0.0.0.0:8080") + vi.SetDefault("web_ui", false) + vi.SetDefault("enable_tracing", false) + vi.SetDefault("auth_fail_block", "always") + vi.SetDefault("seed_file", "seed.js") + + vi.SetDefault("database.type", "postgres") + vi.SetDefault("database.host", "localhost") + vi.SetDefault("database.port", 5432) + vi.SetDefault("database.user", "postgres") + vi.SetDefault("database.schema", "public") + + vi.SetDefault("env", "development") + + vi.BindEnv("env", "GO_ENV") //nolint: errcheck + vi.BindEnv("host", "HOST") //nolint: errcheck + vi.BindEnv("port", "PORT") //nolint: errcheck + + vi.SetDefault("auth.rails.max_idle", 80) + vi.SetDefault("auth.rails.max_active", 12000) + + return vi +} + +func GetConfigName() string { + if len(os.Getenv("GO_ENV")) == 0 { + return "dev" + } + + ge := strings.ToLower(os.Getenv("GO_ENV")) + + switch { + case strings.HasPrefix(ge, "pro"): + return "prod" + + case strings.HasPrefix(ge, "sta"): + return "stage" + + case strings.HasPrefix(ge, "tes"): + return "test" + + case strings.HasPrefix(ge, "dev"): + return "dev" + } + + return ge +} diff --git a/cmd/internal/serv/http.go b/cmd/internal/serv/http.go index a964c34..af2d7a8 100644 --- a/cmd/internal/serv/http.go +++ b/cmd/internal/serv/http.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/dosco/super-graph/cmd/internal/serv/internal/auth" - "github.com/dosco/super-graph/config" "github.com/dosco/super-graph/core" "github.com/rs/cors" "go.uber.org/zap" @@ -83,7 +82,7 @@ func apiV1(w http.ResponseWriter, r *http.Request) { res, err := sg.GraphQL(ct, req.Query, req.Vars) - if conf.LogLevel() >= config.LogLevelDebug { + if logLevel >= LogLevelDebug { log.Printf("DBG query:\n%s\nsql:\n%s", req.Query, res.SQL()) } @@ -94,7 +93,7 @@ func apiV1(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(res) - if conf.LogLevel() >= config.LogLevelInfo { + if logLevel >= LogLevelInfo { zlog.Info("success", zap.String("op", res.Operation()), zap.String("name", res.QueryName()), @@ -111,7 +110,7 @@ func renderErr(w http.ResponseWriter, err error, res *core.Result) { json.NewEncoder(w).Encode(&errorResp{err}) - if conf.LogLevel() >= config.LogLevelError { + if logLevel >= LogLevelError { if res != nil { zlog.Error(err.Error(), zap.String("op", res.Operation()), diff --git a/cmd/internal/serv/init.go b/cmd/internal/serv/init.go index db1c75c..66f59ea 100644 --- a/cmd/internal/serv/init.go +++ b/cmd/internal/serv/init.go @@ -3,17 +3,82 @@ package serv import ( "database/sql" "fmt" + "path" "time" - "github.com/dosco/super-graph/config" _ "github.com/jackc/pgx/v4/stdlib" ) -func initConf() (*config.Config, error) { - return config.NewConfigWithLogger(confPath, log) +func initConf() (*Config, error) { + c, err := ReadInConfig(path.Join(confPath, GetConfigName())) + if err != nil { + return nil, err + } + + switch c.LogLevel { + case "debug": + logLevel = LogLevelDebug + case "error": + logLevel = LogLevelError + case "warn": + logLevel = LogLevelWarn + case "info": + logLevel = LogLevelInfo + default: + logLevel = LogLevelNone + } + + // Auths: validate and sanitize + am := make(map[string]struct{}) + + for i := 0; i < len(c.Auths); i++ { + a := &c.Auths[i] + a.Name = sanitize(a.Name) + + if _, ok := am[a.Name]; ok { + c.Auths = append(c.Auths[:i], c.Auths[i+1:]...) + log.Printf("WRN duplicate auth found: %s", a.Name) + } + am[a.Name] = struct{}{} + } + + // Actions: validate and sanitize + axm := make(map[string]struct{}) + + for i := 0; i < len(c.Actions); i++ { + a := &c.Actions[i] + a.Name = sanitize(a.Name) + a.AuthName = sanitize(a.AuthName) + + if _, ok := axm[a.Name]; ok { + c.Actions = append(c.Actions[:i], c.Actions[i+1:]...) + log.Printf("WRN duplicate action found: %s", a.Name) + } + + if _, ok := am[a.AuthName]; !ok { + c.Actions = append(c.Actions[:i], c.Actions[i+1:]...) + log.Printf("WRN invalid auth_name '%s' for auth: %s", a.AuthName, a.Name) + } + axm[a.Name] = struct{}{} + } + + var anonFound bool + + for _, r := range c.Roles { + if sanitize(r.Name) == "anon" { + anonFound = true + } + } + + if !anonFound { + log.Printf("WRN unauthenticated requests will be blocked. no role 'anon' defined") + c.AuthFailBlock = false + } + + return c, nil } -func initDB(c *config.Config) (*sql.DB, error) { +func initDB(c *Config) (*sql.DB, error) { var db *sql.DB var err error diff --git a/cmd/internal/serv/internal/auth/auth.go b/cmd/internal/serv/internal/auth/auth.go index 1529838..3dcbc26 100644 --- a/cmd/internal/serv/internal/auth/auth.go +++ b/cmd/internal/serv/internal/auth/auth.go @@ -5,11 +5,43 @@ import ( "fmt" "net/http" - "github.com/dosco/super-graph/config" "github.com/dosco/super-graph/core" ) -func SimpleHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +// Auth struct contains authentication related config values used by the Super Graph service +type Auth struct { + Name string + Type string + Cookie string + CredsInHeader bool `mapstructure:"creds_in_header"` + + Rails struct { + Version string + SecretKeyBase string `mapstructure:"secret_key_base"` + URL string + Password string + MaxIdle int `mapstructure:"max_idle"` + MaxActive int `mapstructure:"max_active"` + Salt string + SignSalt string `mapstructure:"sign_salt"` + AuthSalt string `mapstructure:"auth_salt"` + } + + JWT struct { + Provider string + Secret string + PubKeyFile string `mapstructure:"public_key_file"` + PubKeyType string `mapstructure:"public_key_type"` + } + + Header struct { + Name string + Value string + Exists bool + } +} + +func SimpleHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -32,7 +64,7 @@ func SimpleHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) }, nil } -func HeaderHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func HeaderHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { hdr := ac.Header if len(hdr.Name) == 0 { @@ -64,7 +96,7 @@ func HeaderHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) }, nil } -func WithAuth(next http.Handler, ac *config.Auth) (http.Handler, error) { +func WithAuth(next http.Handler, ac *Auth) (http.Handler, error) { var err error if ac.CredsInHeader { diff --git a/cmd/internal/serv/internal/auth/jwt.go b/cmd/internal/serv/internal/auth/jwt.go index 8a7b16d..b9df700 100644 --- a/cmd/internal/serv/internal/auth/jwt.go +++ b/cmd/internal/serv/internal/auth/jwt.go @@ -7,7 +7,6 @@ import ( "strings" jwt "github.com/dgrijalva/jwt-go" - "github.com/dosco/super-graph/config" "github.com/dosco/super-graph/core" ) @@ -16,7 +15,7 @@ const ( jwtAuth0 int = iota + 1 ) -func JwtHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func JwtHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { var key interface{} var jwtProvider int diff --git a/cmd/internal/serv/internal/auth/rails.go b/cmd/internal/serv/internal/auth/rails.go index 98d3008..f07a2d6 100644 --- a/cmd/internal/serv/internal/auth/rails.go +++ b/cmd/internal/serv/internal/auth/rails.go @@ -9,13 +9,12 @@ import ( "strings" "github.com/bradfitz/gomemcache/memcache" - "github.com/dosco/super-graph/config" - "github.com/dosco/super-graph/core" "github.com/dosco/super-graph/cmd/internal/serv/internal/rails" + "github.com/dosco/super-graph/core" "github.com/garyburd/redigo/redis" ) -func RailsHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func RailsHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { ru := ac.Rails.URL if strings.HasPrefix(ru, "memcache:") { @@ -29,7 +28,7 @@ func RailsHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) return RailsCookieHandler(ac, next) } -func RailsRedisHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func RailsRedisHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { cookie := ac.Cookie if len(cookie) == 0 { @@ -85,7 +84,7 @@ func RailsRedisHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, er }, nil } -func RailsMemcacheHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func RailsMemcacheHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { cookie := ac.Cookie if len(cookie) == 0 { @@ -128,7 +127,7 @@ func RailsMemcacheHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, }, nil } -func RailsCookieHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, error) { +func RailsCookieHandler(ac *Auth, next http.Handler) (http.HandlerFunc, error) { cookie := ac.Cookie if len(cookie) == 0 { return nil, fmt.Errorf("no auth.cookie defined") @@ -159,7 +158,7 @@ func RailsCookieHandler(ac *config.Auth, next http.Handler) (http.HandlerFunc, e }, nil } -func railsAuth(ac *config.Auth) (*rails.Auth, error) { +func railsAuth(ac *Auth) (*rails.Auth, error) { secret := ac.Rails.SecretKeyBase if len(secret) == 0 { return nil, errors.New("no auth.rails.secret_key_base defined") diff --git a/cmd/internal/serv/serv.go b/cmd/internal/serv/serv.go index bc4a5df..26b2e64 100644 --- a/cmd/internal/serv/serv.go +++ b/cmd/internal/serv/serv.go @@ -12,11 +12,10 @@ import ( rice "github.com/GeertJohan/go.rice" "github.com/NYTimes/gziphandler" "github.com/dosco/super-graph/cmd/internal/serv/internal/auth" - "github.com/dosco/super-graph/config" ) func initWatcher() { - cpath := conf.ConfigPathUsed() + cpath := conf.cpath if conf != nil && !conf.WatchAndReload { return } @@ -170,7 +169,7 @@ func setActionRoutes(routes map[string]http.Handler) error { return nil } -func findAuth(name string) *config.Auth { +func findAuth(name string) *auth.Auth { for _, a := range conf.Auths { if strings.EqualFold(a.Name, name) { return &a diff --git a/cmd/internal/serv/utils.go b/cmd/internal/serv/utils.go index ddc71f8..4a14e5e 100644 --- a/cmd/internal/serv/utils.go +++ b/cmd/internal/serv/utils.go @@ -113,12 +113,12 @@ func al(b byte) bool { func fatalInProd(err error, msg string) { var wg sync.WaitGroup - if !isDev() { + if isDev() { + log.Printf("ERR %s: %s", msg, err) + } else { log.Fatalf("ERR %s: %s", msg, err) } - log.Printf("ERR %s: %s", msg, err) - wg.Add(1) wg.Wait() } @@ -126,3 +126,7 @@ func fatalInProd(err error, msg string) { func isDev() bool { return strings.HasPrefix(os.Getenv("GO_ENV"), "dev") } + +func sanitize(value string) string { + return strings.ToLower(strings.TrimSpace(value)) +} diff --git a/cmd/internal/serv/web/.gitignore b/cmd/internal/serv/web/.gitignore index d4599dc..9ee9f1c 100755 --- a/cmd/internal/serv/web/.gitignore +++ b/cmd/internal/serv/web/.gitignore @@ -7,7 +7,7 @@ /coverage # production -/build +# /build # development /src/components/dataviz/core/*.js.map diff --git a/cmd/internal/serv/web/build/asset-manifest.json b/cmd/internal/serv/web/build/asset-manifest.json new file mode 100644 index 0000000..50d23de --- /dev/null +++ b/cmd/internal/serv/web/build/asset-manifest.json @@ -0,0 +1,30 @@ +{ + "files": { + "main.css": "/static/css/main.c6b5c55c.chunk.css", + "main.js": "/static/js/main.04d74040.chunk.js", + "main.js.map": "/static/js/main.04d74040.chunk.js.map", + "runtime-main.js": "/static/js/runtime-main.4aea9da3.js", + "runtime-main.js.map": "/static/js/runtime-main.4aea9da3.js.map", + "static/js/2.03370bd3.chunk.js": "/static/js/2.03370bd3.chunk.js", + "static/js/2.03370bd3.chunk.js.map": "/static/js/2.03370bd3.chunk.js.map", + "index.html": "/index.html", + "precache-manifest.e33bc3c7c6774d7032c490820c96901d.js": "/precache-manifest.e33bc3c7c6774d7032c490820c96901d.js", + "service-worker.js": "/service-worker.js", + "static/css/main.c6b5c55c.chunk.css.map": "/static/css/main.c6b5c55c.chunk.css.map", + "static/media/GraphQLLanguageService.js.flow": "/static/media/GraphQLLanguageService.js.5ab204b9.flow", + "static/media/autocompleteUtils.js.flow": "/static/media/autocompleteUtils.js.4ce7ba19.flow", + "static/media/getAutocompleteSuggestions.js.flow": "/static/media/getAutocompleteSuggestions.js.7f98f032.flow", + "static/media/getDefinition.js.flow": "/static/media/getDefinition.js.4dbec62f.flow", + "static/media/getDiagnostics.js.flow": "/static/media/getDiagnostics.js.65b0979a.flow", + "static/media/getHoverInformation.js.flow": "/static/media/getHoverInformation.js.d9411837.flow", + "static/media/getOutline.js.flow": "/static/media/getOutline.js.c04e3998.flow", + "static/media/index.js.flow": "/static/media/index.js.02c24280.flow", + "static/media/logo.png": "/static/media/logo.57ee3b60.png" + }, + "entrypoints": [ + "static/js/runtime-main.4aea9da3.js", + "static/js/2.03370bd3.chunk.js", + "static/css/main.c6b5c55c.chunk.css", + "static/js/main.04d74040.chunk.js" + ] +} \ No newline at end of file diff --git a/cmd/internal/serv/web/build/favicon.ico b/cmd/internal/serv/web/build/favicon.ico new file mode 100755 index 0000000..404dd13 Binary files /dev/null and b/cmd/internal/serv/web/build/favicon.ico differ diff --git a/cmd/internal/serv/web/build/index.html b/cmd/internal/serv/web/build/index.html new file mode 100644 index 0000000..7d9d6eb --- /dev/null +++ b/cmd/internal/serv/web/build/index.html @@ -0,0 +1 @@ +
f+p-3&&(a.scrollLeft=t.right+(d?0:10)-f),a}function Or(e,t){null!=t&&(Ir(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Fr(e){Ir(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Nr(e,t,n){null==t&&null==n||Ir(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Ir(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,jr(e,Jn(e,t.from),Jn(e,t.to),t.margin))}function jr(e,t,n,r){var i=_r(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Nr(e,i.scrollLeft,i.scrollTop)}function Mr(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||ui(e,{top:t}),Pr(e,t,!0),n&&ui(e),ri(e,100))}function Pr(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Lr(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,pi(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Rr(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+wn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+kn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}var Br=function(e,t,n){this.cm=n;var r=this.vert=_("div",[_("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=_("div",[_("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),fe(r,"scroll",(function(){r.clientHeight&&t(r.scrollTop,"vertical")})),fe(i,"scroll",(function(){i.clientWidth&&t(i.scrollLeft,"horizontal")})),this.checkedZeroWidth=!1,a&&s<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Br.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Br.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Br.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Br.prototype.zeroWidthHack=function(){var e=y&&!d?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new B,this.disableVert=new B},Br.prototype.enableZeroWidthBar=function(e,t,n){e.style.pointerEvents="auto",t.set(1e3,(function r(){var i=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,r)}))},Br.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Ur=function(){};function zr(e,t){t||(t=Rr(e));var n=e.display.barWidth,r=e.display.barHeight;Vr(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&kr(e),Vr(e,Rr(e)),n=e.display.barWidth,r=e.display.barHeight}function Vr(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}Ur.prototype.update=function(){return{bottom:0,right:0}},Ur.prototype.setScrollLeft=function(){},Ur.prototype.setScrollTop=function(){},Ur.prototype.clear=function(){};var qr={native:Br,null:Ur};function Hr(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&k(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new qr[e.options.scrollbarStyle]((function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),fe(t,"mousedown",(function(){e.state.focused&&setTimeout((function(){return e.display.input.focus()}),0)})),t.setAttribute("cm-not-content","true")}),(function(t,n){"horizontal"==n?Lr(e,t):Mr(e,t)}),e),e.display.scrollbars.addClass&&I(e.display.wrapper,e.display.scrollbars.addClass)}var Wr=0;function Gr(e){var t;e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:0,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Wr},t=e.curOp,an?an.ops.push(t):t.ownsGroup=an={ops:[t],delayedCallbacks:[]}}function Kr(e){var t=e.curOp;t&&function(e,t){var n=e.ownsGroup;if(n)try{!function(e){var t=e.delayedCallbacks,n=0;do{for(;n =Zt)return function(e,t,n,r,o){for(var a=0,s=new Array(i),u=0;0!==n;u++,n>>>=1)s[u]=1&n?t[a++]:void 0;return s[r]=o,new Lt(e,a+1,s)}(e,g,d,p,y);if(h&&!y&&2===g.length&&Jt(g[1^m]))return g[1^m];if(h&&y&&1===g.length&&Jt(y))return y;var b=e&&e===this.ownerID,E=h?y?d:d^f:d|f,x=h?y?Xt(g,m,y,b):function(e,t,n){var r=e.length-1;if(n&&t===r)return e.pop(),e;for(var i=new Array(r),o=0,a=0;a h?new an([],i):g;if(g&&m>h&&c a&&(f=f.removeBefore(i,p,c-d)),f&&ms)return{value:void 0,done:!0};var e=i.next();return r||t===P||e.done?e:V(t,u-1,t===M?void 0:e.value[1],e)}))},c}function Le(e,t,n,r){var i=Ke(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate((function(e,o,c){if(!s||!(s=t.call(n,e,o,c)))return u++,i(e,r?o:u-1,a)})),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(L,o),u=!0,c=0;return new z((function(){var e,o,l;do{if((e=s.next()).done)return r||i===P?e:V(i,c++,i===M?void 0:e.value[1],e);var p=e.value;o=p[0],l=p[1],u&&(u=t.call(n,l,o,a))}while(u);return i===L?e:V(i,o,l,e)}))},i}function Re(e,t){var n=E(e),r=[e].concat(t).map((function(e){return y(e)?n&&(e=S(e)):e=n?oe(e):ae(Array.isArray(e)?e:[e]),e})).filter((function(e){return 0!==e.size}));if(0===r.length)return e;if(1===r.length){var i=r[0];if(i===e||n&&E(i)||D(e)&&D(i))return i}var o=new ee(r);return n?o=o.toKeyedSeq():D(e)||(o=o.toSetSeq()),(o=o.flatten(!0)).size=r.reduce((function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}}),0),o}function Be(e,t,n){var r=Ke(e);return r.__iterateUncached=function(i,o){if(o)return this.cacheResult().__iterate(i,o);var a=0,s=!1;return function e(u,c){u.__iterate((function(o,u){return(!t||cr;b-=r){var E=h>>>b&o;y=y.array[E]=dn(y.array[E],i)}y.array[h>>>r&o]=g}if(l=m)c-=m,l-=m,p=r,f=null,v=v&&v.removeBefore(i,0,c);else if(c>a||m