mirror of
https://github.com/MizuchiLabs/mantrae.git
synced 2026-02-09 07:48:52 -06:00
fixed middlewares, better types
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// Package main is the entrypoint for the mantrae agent.
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package client provides the agent's main gRPC client logic.
|
||||
package client
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package collector provides functions for collecting data from the host system.
|
||||
package collector
|
||||
|
||||
import (
|
||||
|
||||
12
go.mod
12
go.mod
@@ -3,7 +3,7 @@ module github.com/mizuchilabs/mantrae
|
||||
go 1.24.4
|
||||
|
||||
require (
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1
|
||||
connectrpc.com/connect v1.18.1
|
||||
connectrpc.com/cors v0.1.0
|
||||
connectrpc.com/grpchealth v1.4.0
|
||||
@@ -12,7 +12,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
github.com/cloudflare/cloudflare-go v0.115.0
|
||||
github.com/coreos/go-oidc/v3 v3.14.1
|
||||
@@ -20,18 +20,19 @@ require (
|
||||
github.com/domodwyer/mailyak/v3 v3.6.2
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3
|
||||
github.com/joeig/go-powerdns/v3 v3.16.0
|
||||
github.com/pressly/goose/v3 v3.24.3
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/traefik/paerser v0.2.2
|
||||
github.com/traefik/traefik/v3 v3.4.1
|
||||
github.com/traefik/traefik/v3 v3.4.3
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/net v0.41.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
google.golang.org/protobuf v1.36.6
|
||||
modernc.org/sqlite v1.38.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -63,7 +64,7 @@ require (
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-acme/lego/v4 v4.23.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.1 // indirect
|
||||
github.com/go-kit/log v0.2.1 // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
@@ -108,6 +109,7 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
|
||||
27
go.sum
27
go.sum
@@ -1,5 +1,5 @@
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1 h1:AUL6VF5YWL01j/1H/DQbPUSDkEwYqwVCNw7yhbpOxSQ=
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250613105001-9f2d3c737feb.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U=
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1 h1:6tCo3lsKNLqUjRPhyc8JuYWYUiQkulufxSDOfG1zgWQ=
|
||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250625184727-c923a0c2a132.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U=
|
||||
buf.build/go/protovalidate v0.13.1 h1:6loHDTWdY/1qmqmt1MijBIKeN4T9Eajrqb9isT1W1s8=
|
||||
buf.build/go/protovalidate v0.13.1/go.mod h1:C/QcOn/CjXRn5udUwYBiLs8y1TGy7RS+GOSKqjS77aU=
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
@@ -48,8 +48,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzRE
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0 h1:1GmCadhKR3J2sMVKs2bAYq9VnwYeCqfRyZzD4RASGlA=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.81.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0 h1:JubM8CGDDFaAOmBrd8CRYNr49ZNgEAiLwGwgNMdS0nw=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
|
||||
@@ -93,8 +93,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV4=
|
||||
github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
|
||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
@@ -117,7 +117,6 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
|
||||
github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
|
||||
github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||
@@ -137,6 +136,8 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/http-wasm/http-wasm-host-go v0.7.0 h1:+1KrRyOO6tWiDB24QrtSYyDmzFLBBs3jioKaUT0mq1c=
|
||||
github.com/http-wasm/http-wasm-host-go v0.7.0/go.mod h1:adXKcLmL7yuavH/e0kBAp7b3TgAHTo/enCduyN5bXGM=
|
||||
github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3 h1:hql4suSs7RG3+t5UyjdPXIzBmXg6AyFoqRRF+TPR3yY=
|
||||
github.com/hypersequent/zen v0.0.0-20250317110808-f521ea1d4fc3/go.mod h1:uJ9mqUok1RHIAoVlkWxPHJqXNLwhLzh7jCUbp2V9Rws=
|
||||
github.com/jarcoal/httpmock v1.4.0 h1:BvhqnH0JAYbNudL2GMJKgOHe2CtKlzJ/5rWKyp+hc2k=
|
||||
github.com/jarcoal/httpmock v1.4.0/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0=
|
||||
github.com/joeig/go-powerdns/v3 v3.16.0 h1:d6k0dVlBYr+B9P5U+74rVY1VmQxUG6Qdtlb3F33cBLQ=
|
||||
@@ -210,8 +211,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/traefik/paerser v0.2.2 h1:cpzW/ZrQrBh3mdwD/jnp6aXASiUFKOVr6ldP+keJTcQ=
|
||||
github.com/traefik/paerser v0.2.2/go.mod h1:7BBDd4FANoVgaTZG+yh26jI6CA2nds7D/4VTEdIsh24=
|
||||
github.com/traefik/traefik/v3 v3.4.1 h1:QBO/C9ILViPVBhsmY8nEnoobTULxg6oW1jUTX8FFh8w=
|
||||
github.com/traefik/traefik/v3 v3.4.1/go.mod h1:8FHoFbX5P+zMQ3UUjjfrDH87BDSbHllcUQyiI2wCP3o=
|
||||
github.com/traefik/traefik/v3 v3.4.3 h1:4bFwOd+kd+c+XQevhHbZ4V4Ui5jMXI5aHh6YdHj0mqM=
|
||||
github.com/traefik/traefik/v3 v3.4.3/go.mod h1:uXB3uTO0wFWHFdliHvsHXvG52n3anUYHed89yRDcZmc=
|
||||
github.com/unrolled/render v1.7.0 h1:1yke01/tZiZpiXfUG+zqB+6fq3G4I+KDmnh0EhPq7So=
|
||||
github.com/unrolled/render v1.7.0/go.mod h1:LwQSeDhjml8NLjIO9GJO1/1qpFJxtfVIpzxXKjfVkoI=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -254,6 +255,10 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
|
||||
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
@@ -348,5 +353,5 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ=
|
||||
sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4=
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package handler provides HTTP handlers for the API.
|
||||
package handler
|
||||
|
||||
import (
|
||||
@@ -172,7 +173,7 @@ func OIDCCallback(a *config.App) http.HandlerFunc {
|
||||
|
||||
// Extract user info from verified token
|
||||
var userInfo OIDCUserInfo
|
||||
if err := verifiedToken.Claims(&userInfo); err != nil {
|
||||
if err = verifiedToken.Claims(&userInfo); err != nil {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("Failed to parse claims: %v", err),
|
||||
@@ -180,7 +181,7 @@ func OIDCCallback(a *config.App) http.HandlerFunc {
|
||||
)
|
||||
return
|
||||
}
|
||||
if err := userInfo.Validate(); err != nil {
|
||||
if err = userInfo.Validate(); err != nil {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("Invalid user info: %v", err),
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
@@ -27,7 +28,11 @@ func UploadAvatar(a *config.App) http.HandlerFunc {
|
||||
http.Error(w, "File too large or invalid form data", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.MultipartForm.RemoveAll()
|
||||
defer func() {
|
||||
if err := r.MultipartForm.RemoveAll(); err != nil {
|
||||
slog.Error("failed to close request body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
userID := r.URL.Query().Get("user_id")
|
||||
if userID == "" {
|
||||
@@ -40,7 +45,11 @@ func UploadAvatar(a *config.App) http.HandlerFunc {
|
||||
http.Error(w, "Failed to get uploaded file", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
if err = file.Close(); err != nil {
|
||||
slog.Error("failed to close uploaded file", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
extension := filepath.Ext(header.Filename)
|
||||
allowedExtensions := []string{".png", ".jpg", ".jpeg"}
|
||||
@@ -79,14 +88,22 @@ func UploadBackup(a *config.App) http.HandlerFunc {
|
||||
http.Error(w, "File too large or invalid form data", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.MultipartForm.RemoveAll()
|
||||
defer func() {
|
||||
if err := r.MultipartForm.RemoveAll(); err != nil {
|
||||
slog.Error("failed to close request body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
file, header, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to get uploaded file", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
if err = file.Close(); err != nil {
|
||||
slog.Error("failed to close uploaded file", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
extension := filepath.Ext(header.Filename)
|
||||
allowedExtensions := []string{".db", ".json", ".yaml", ".yml"}
|
||||
@@ -136,25 +153,22 @@ func UploadBackup(a *config.App) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if extension == ".yaml" || extension == ".yml" {
|
||||
if err = yaml.Unmarshal(content, &dynamic); err != nil {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("Failed to decode YAML file: %v", err),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
switch extension {
|
||||
case ".yaml", ".yml":
|
||||
if err = yaml.Unmarshal(content, dynamic); err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to decode YAML file: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else if extension == ".json" {
|
||||
if err = json.Unmarshal(content, &dynamic); err != nil {
|
||||
http.Error(
|
||||
w,
|
||||
fmt.Sprintf("Failed to decode JSON file: %v", err),
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
case ".json":
|
||||
if err = json.Unmarshal(content, dynamic); err != nil {
|
||||
http.Error(w, fmt.Sprintf("Failed to decode JSON file: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
default:
|
||||
http.Error(w, "Invalid file type", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err = convert.DynamicToDB(r.Context(), *a.Conn.GetQuery(), profileIDValue, dynamic); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package middlewares provides authentication and logging middleware.
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
|
||||
@@ -67,7 +67,11 @@ func NewServer(app *config.App) *Server {
|
||||
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
s.registerServices()
|
||||
defer s.app.Conn.Close()
|
||||
defer func() {
|
||||
if err := s.app.Conn.Close(); err != nil {
|
||||
slog.Error("failed to close database connection", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
server := &http.Server{
|
||||
Addr: s.Host + ":" + s.Port,
|
||||
@@ -83,12 +87,12 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
|
||||
// Start server in a goroutine
|
||||
go func() {
|
||||
serverUrl, _ := s.app.SM.Get("server_url")
|
||||
if serverUrl == "" {
|
||||
serverUrl = s.Host + ":" + s.Port
|
||||
serverURL, ok := s.app.SM.Get("server_url")
|
||||
if ok && serverURL == "" {
|
||||
serverURL = s.Host + ":" + s.Port
|
||||
}
|
||||
slog.Info("Server listening on", "address", "127.0.0.1:"+s.Port)
|
||||
slog.Info("Agents can connect to", "address", serverUrl)
|
||||
slog.Info("Agents can connect to", "address", serverURL)
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
serverErr <- err
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ func (s *AgentService) CreateAgent(
|
||||
return nil, connect.NewError(connect.CodeInternal, err)
|
||||
}
|
||||
|
||||
serverUrl, err := s.app.Conn.GetQuery().GetSetting(ctx, settings.KeyServerURL)
|
||||
serverURL, err := s.app.Conn.GetQuery().GetSetting(ctx, settings.KeyServerURL)
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, err)
|
||||
}
|
||||
if serverUrl.Value == "" {
|
||||
if serverURL.Value == "" {
|
||||
return nil, connect.NewError(
|
||||
connect.CodeInvalidArgument,
|
||||
errors.New("server url is required, check your settings"),
|
||||
@@ -157,7 +157,7 @@ func (s *AgentService) HealthCheck(
|
||||
}
|
||||
|
||||
// Rotate Token if it's close to expiring
|
||||
if _, err := s.updateToken(ctx, &agent); err != nil {
|
||||
if _, err = s.updateToken(ctx, &agent); err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, err)
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ func (s *AgentService) updateToken(ctx context.Context, agent *db.Agent) (*strin
|
||||
}
|
||||
|
||||
func (s *AgentService) createToken(agentID string, profileID int64) (*string, error) {
|
||||
serverUrl, ok := s.app.SM.Get(settings.KeyServerURL)
|
||||
serverURL, ok := s.app.SM.Get(settings.KeyServerURL)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to get server url setting")
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func (s *AgentService) createToken(agentID string, profileID int64) (*string, er
|
||||
token, err := meta.EncodeAgentToken(
|
||||
profileID,
|
||||
agentID,
|
||||
serverUrl,
|
||||
serverURL,
|
||||
s.app.Secret,
|
||||
time.Now().Add(settings.AsDuration(agentInterval)),
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"github.com/mizuchilabs/mantrae/internal/config"
|
||||
@@ -95,7 +96,11 @@ func (s *BackupService) DownloadBackup(
|
||||
if err != nil {
|
||||
return connect.NewError(connect.CodeInternal, err)
|
||||
}
|
||||
defer reader.Close()
|
||||
defer func() {
|
||||
if err = reader.Close(); err != nil {
|
||||
slog.Error("failed to close backup reader", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
buf := make([]byte, 32*1024)
|
||||
for {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
@@ -320,7 +321,11 @@ func (s *MiddlewareService) GetMiddlewarePlugins(
|
||||
if err != nil {
|
||||
return nil, connect.NewError(connect.CodeInternal, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var allPlugins []schema.Plugin
|
||||
if err := json.NewDecoder(resp.Body).Decode(&allPlugins); err != nil {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package service provides the gRPC service implementations.
|
||||
package service
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package backup provides functionality for creating and restoring backups.
|
||||
package backup
|
||||
|
||||
import (
|
||||
|
||||
@@ -15,6 +15,7 @@ type Flags struct {
|
||||
Version bool
|
||||
Update bool
|
||||
Squash bool
|
||||
Zod bool
|
||||
}
|
||||
|
||||
func ParseFlags() {
|
||||
@@ -22,6 +23,7 @@ func ParseFlags() {
|
||||
flag.BoolVar(&f.Version, "version", false, "Print version and exit")
|
||||
flag.BoolVar(&f.Update, "update", false, "Update the application")
|
||||
flag.BoolVar(&f.Squash, "squash", false, "Squash the database")
|
||||
flag.BoolVar(&f.Zod, "zod", false, "Generate zod schemas (only for dev)")
|
||||
|
||||
flag.Parse()
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
@@ -35,5 +37,10 @@ func ParseFlags() {
|
||||
store.Squash()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if f.Zod {
|
||||
StructToZodSchema()
|
||||
os.Exit(1)
|
||||
}
|
||||
build.Update(f.Update)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package config provides application configuration and setup.
|
||||
package config
|
||||
|
||||
import (
|
||||
|
||||
55
internal/config/zod.go
Normal file
55
internal/config/zod.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hypersequent/zen"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
)
|
||||
|
||||
// StructToZodSchema converts a struct to a zod schema (for use in the frontend)
|
||||
func StructToZodSchema() {
|
||||
types := map[string]any{
|
||||
// Routers
|
||||
"httpRouter": dynamic.Router{},
|
||||
"tcpRouter": dynamic.TCPRouter{},
|
||||
"udpRouter": dynamic.UDPRouter{},
|
||||
|
||||
// Services
|
||||
"httpService": dynamic.Service{},
|
||||
"tcpService": dynamic.TCPService{},
|
||||
"udpService": dynamic.UDPService{},
|
||||
|
||||
// HTTP Middlewares
|
||||
"httpMiddleware": dynamic.Middleware{},
|
||||
|
||||
// TCP Middlewares
|
||||
"tcpMiddleware": dynamic.TCPMiddleware{},
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
// Add a header
|
||||
builder.WriteString("// This file is auto-generated via `zen.StructToZodSchema`.\n")
|
||||
builder.WriteString("// Do not edit manually.\n\n")
|
||||
builder.WriteString("import { z } from 'zod';\n\n")
|
||||
|
||||
for _, strct := range types {
|
||||
schema := zen.StructToZodSchema(strct)
|
||||
builder.WriteString(fmt.Sprintf("%s\n", schema))
|
||||
}
|
||||
|
||||
out := "./web/src/lib/gen/zen/traefik-schemas.ts"
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(out), 0755); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := os.WriteFile(out, []byte(builder.String()), 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("✅ Zod schemas written to %s\n", out)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ func HTTPMiddlewareToProto(m *db.HttpMiddleware) *mantraev1.Middleware {
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
}
|
||||
@@ -36,6 +37,7 @@ func TCPMiddlewareToProto(m *db.TcpMiddleware) *mantraev1.Middleware {
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
}
|
||||
@@ -58,6 +60,7 @@ func TCPMiddlewaresToProto(middlewares []db.TcpMiddleware) []*mantraev1.Middlewa
|
||||
}
|
||||
|
||||
// Specialized batch conversion functions
|
||||
|
||||
func MiddlewaresByProfileToProto(
|
||||
middlewares []db.ListMiddlewaresByProfileRow,
|
||||
) []*mantraev1.Middleware {
|
||||
@@ -76,6 +79,7 @@ func MiddlewaresByProfileToProto(
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
})
|
||||
@@ -91,6 +95,7 @@ func MiddlewaresByProfileToProto(
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
})
|
||||
@@ -117,6 +122,7 @@ func MiddlewaresByAgentToProto(middlewares []db.ListMiddlewaresByAgentRow) []*ma
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_HTTP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
})
|
||||
@@ -132,6 +138,7 @@ func MiddlewaresByAgentToProto(middlewares []db.ListMiddlewaresByAgentRow) []*ma
|
||||
Name: m.Name,
|
||||
Config: config,
|
||||
Type: mantraev1.MiddlewareType_MIDDLEWARE_TYPE_TCP,
|
||||
Enabled: m.Enabled,
|
||||
CreatedAt: SafeTimestamp(m.CreatedAt),
|
||||
UpdatedAt: SafeTimestamp(m.UpdatedAt),
|
||||
})
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package dns provides functionality for managing DNS records.
|
||||
package dns
|
||||
|
||||
import (
|
||||
|
||||
@@ -147,7 +147,11 @@ func (t *TechnitiumProvider) DeleteRecord(subdomain string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
@@ -202,7 +206,11 @@ func (t *TechnitiumProvider) createRecord(subdomain, recordType string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
@@ -224,7 +232,11 @@ func (t *TechnitiumProvider) createRecord(subdomain, recordType string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
@@ -259,7 +271,11 @@ func (t *TechnitiumProvider) updateRecord(subdomain, recordType string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
@@ -290,7 +306,11 @@ func (t *TechnitiumProvider) ListRecords(subdomain string) ([]DNSRecord, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err = resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var tRecords struct {
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package mail provides functionality for sending emails.
|
||||
package mail
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package settings provides functionality for managing application settings.
|
||||
package settings
|
||||
|
||||
import (
|
||||
|
||||
149
internal/settings/settings_test.go
Normal file
149
internal/settings/settings_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mizuchilabs/mantrae/internal/store"
|
||||
"github.com/mizuchilabs/mantrae/internal/store/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func setupTest() (*SettingsManager, func()) {
|
||||
conn := store.NewConnection(":memory:")
|
||||
sm := NewManager(conn)
|
||||
|
||||
return sm, func() { conn.Close() }
|
||||
}
|
||||
|
||||
func TestNewManager(t *testing.T) {
|
||||
conn := store.NewConnection(":memory:")
|
||||
defer conn.Close()
|
||||
|
||||
sm := NewManager(conn)
|
||||
assert.NotNil(t, sm)
|
||||
assert.NotNil(t, sm.conn)
|
||||
assert.NotNil(t, sm.cache)
|
||||
}
|
||||
|
||||
func TestGetAndSet(t *testing.T) {
|
||||
sm, teardown := setupTest()
|
||||
defer teardown()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Test setting and getting a value
|
||||
err := sm.Set(ctx, KeyServerURL, "http://localhost:8080")
|
||||
assert.NoError(t, err)
|
||||
|
||||
val, ok := sm.Get(KeyServerURL)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "http://localhost:8080", val)
|
||||
|
||||
// Test setting an invalid key
|
||||
err = sm.Set(ctx, "invalid_key", "some_value")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGetAll(t *testing.T) {
|
||||
sm, teardown := setupTest()
|
||||
defer teardown()
|
||||
|
||||
ctx := context.Background()
|
||||
sm.Start(ctx)
|
||||
|
||||
// Test getting all values
|
||||
allSettings := sm.GetAll()
|
||||
assert.NotEmpty(t, allSettings)
|
||||
assert.Equal(t, "local", allSettings[KeyStorage])
|
||||
}
|
||||
|
||||
func TestGetMany(t *testing.T) {
|
||||
sm, teardown := setupTest()
|
||||
defer teardown()
|
||||
|
||||
ctx := context.Background()
|
||||
sm.Start(ctx)
|
||||
|
||||
// Test getting many values
|
||||
keys := []string{KeyServerURL, KeyStorage}
|
||||
manySettings := sm.GetMany(keys)
|
||||
assert.Len(t, manySettings, 2)
|
||||
assert.Equal(t, "", manySettings[KeyServerURL])
|
||||
assert.Equal(t, "local", manySettings[KeyStorage])
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
sm, teardown := setupTest()
|
||||
defer teardown()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Set an environment variable
|
||||
os.Setenv("SERVER_URL", "http://env.test")
|
||||
defer os.Unsetenv("SERVER_URL")
|
||||
|
||||
// Add a value to the database
|
||||
err := sm.conn.GetQuery().UpsertSetting(ctx, db.UpsertSettingParams{
|
||||
Key: KeyStorage,
|
||||
Value: "db_value",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
sm.Start(ctx)
|
||||
|
||||
// Check that the environment variable is used
|
||||
val, ok := sm.Get(KeyServerURL)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "http://env.test", val)
|
||||
|
||||
// Check that the database value is used
|
||||
val, ok = sm.Get(KeyStorage)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "db_value", val)
|
||||
|
||||
// Check that the default value is used
|
||||
val, ok = sm.Get(KeyBackupEnabled)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "true", val)
|
||||
}
|
||||
|
||||
func TestValidation(t *testing.T) {
|
||||
sm, teardown := setupTest()
|
||||
defer teardown()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Test validation for server url
|
||||
err := sm.Set(ctx, KeyServerURL, " ")
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test validation for email port
|
||||
err = sm.Set(ctx, KeyEmailPort, "abc")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = sm.Set(ctx, KeyEmailPort, "70000")
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test validation for backup keep
|
||||
err = sm.Set(ctx, KeyBackupKeep, "0")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAsHelpers(t *testing.T) {
|
||||
testString := "test"
|
||||
testStringEmpty := ""
|
||||
assert.Equal(t, "test", AsString(&testString))
|
||||
assert.Equal(t, "", AsString(&testStringEmpty))
|
||||
assert.True(t, AsBool("true"))
|
||||
assert.False(t, AsBool("false"))
|
||||
assert.False(t, AsBool("invalid"))
|
||||
assert.Equal(t, 123, AsInt("123"))
|
||||
assert.Equal(t, 0, AsInt("invalid"))
|
||||
assert.Equal(t, 123.45, AsFloat64("123.45"))
|
||||
assert.Equal(t, 0.0, AsFloat64("invalid"))
|
||||
assert.Equal(t, time.Hour, AsDuration("1h"))
|
||||
assert.Equal(t, time.Duration(0), AsDuration("invalid"))
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package storage provides a generic interface for storage backends.
|
||||
package storage
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package store provides functionality for interacting with the database.
|
||||
package store
|
||||
|
||||
import (
|
||||
|
||||
@@ -64,20 +64,11 @@ INSERT INTO
|
||||
agent_id,
|
||||
name,
|
||||
config,
|
||||
enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at
|
||||
(?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateHttpMiddlewareParams struct {
|
||||
@@ -85,7 +76,6 @@ type CreateHttpMiddlewareParams struct {
|
||||
AgentID *string `json:"agentId"`
|
||||
Name string `json:"name"`
|
||||
Config *schema.Middleware `json:"config"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateHttpMiddleware(ctx context.Context, arg CreateHttpMiddlewareParams) (HttpMiddleware, error) {
|
||||
@@ -94,7 +84,6 @@ func (q *Queries) CreateHttpMiddleware(ctx context.Context, arg CreateHttpMiddle
|
||||
arg.AgentID,
|
||||
arg.Name,
|
||||
arg.Config,
|
||||
arg.Enabled,
|
||||
)
|
||||
var i HttpMiddleware
|
||||
err := row.Scan(
|
||||
|
||||
@@ -64,20 +64,11 @@ INSERT INTO
|
||||
agent_id,
|
||||
name,
|
||||
config,
|
||||
enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at
|
||||
(?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING id, profile_id, agent_id, name, config, enabled, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateTcpMiddlewareParams struct {
|
||||
@@ -85,7 +76,6 @@ type CreateTcpMiddlewareParams struct {
|
||||
AgentID *string `json:"agentId"`
|
||||
Name string `json:"name"`
|
||||
Config *schema.TCPMiddleware `json:"config"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateTcpMiddleware(ctx context.Context, arg CreateTcpMiddlewareParams) (TcpMiddleware, error) {
|
||||
@@ -94,7 +84,6 @@ func (q *Queries) CreateTcpMiddleware(ctx context.Context, arg CreateTcpMiddlewa
|
||||
arg.AgentID,
|
||||
arg.Name,
|
||||
arg.Config,
|
||||
arg.Enabled,
|
||||
)
|
||||
var i TcpMiddleware
|
||||
err := row.Scan(
|
||||
|
||||
@@ -5,20 +5,11 @@ INSERT INTO
|
||||
agent_id,
|
||||
name,
|
||||
config,
|
||||
enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
) RETURNING *;
|
||||
(?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *;
|
||||
|
||||
-- name: GetHttpMiddleware :one
|
||||
SELECT
|
||||
|
||||
@@ -5,20 +5,11 @@ INSERT INTO
|
||||
agent_id,
|
||||
name,
|
||||
config,
|
||||
enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
) RETURNING *;
|
||||
(?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) RETURNING *;
|
||||
|
||||
-- name: GetTcpMiddleware :one
|
||||
SELECT
|
||||
|
||||
@@ -11,7 +11,11 @@ func Squash() {
|
||||
conn.Migrate()
|
||||
|
||||
db := conn.db
|
||||
defer db.Close()
|
||||
defer func() {
|
||||
if err := db.Close(); err != nil {
|
||||
slog.Error("failed to close database", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var currentVersion int64
|
||||
err := db.QueryRow("SELECT version_id FROM goose_db_version ORDER BY id DESC LIMIT 1").
|
||||
@@ -31,7 +35,11 @@ func Squash() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err = rows.Close(); err != nil {
|
||||
slog.Error("failed to close rows", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create new base migration
|
||||
baseFile := "-- +goose Up\n"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package traefik provides functionality for interacting with the Traefik API.
|
||||
package traefik
|
||||
|
||||
import (
|
||||
@@ -7,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -32,7 +34,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch %s: %w", instance.Url+RawAPI, err)
|
||||
}
|
||||
defer rawResp.Close()
|
||||
defer func() {
|
||||
if err = rawResp.Close(); err != nil {
|
||||
slog.Error("failed to close raw response", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var config schema.Configuration
|
||||
if err = json.NewDecoder(rawResp).Decode(&config); err != nil {
|
||||
@@ -43,7 +49,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch %s: %w", instance.Url+EntrypointsAPI, err)
|
||||
}
|
||||
defer entrypointsResp.Close()
|
||||
defer func() {
|
||||
if err = entrypointsResp.Close(); err != nil {
|
||||
slog.Error("failed to close entrypoints response", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var entrypoints schema.EntryPoints
|
||||
if err = json.NewDecoder(entrypointsResp).Decode(&entrypoints); err != nil {
|
||||
@@ -54,7 +64,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch %s: %w", instance.Url+OverviewAPI, err)
|
||||
}
|
||||
defer overviewResp.Close()
|
||||
defer func() {
|
||||
if err = overviewResp.Close(); err != nil {
|
||||
slog.Error("failed to close overview response", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var overview schema.Overview
|
||||
if err = json.NewDecoder(overviewResp).Decode(&overview); err != nil {
|
||||
@@ -65,7 +79,11 @@ func UpdateTraefikAPI(DB *sql.DB, instanceID int64) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch %s: %w", instance.Url+VersionAPI, err)
|
||||
}
|
||||
defer versionResp.Close()
|
||||
defer func() {
|
||||
if err = versionResp.Close(); err != nil {
|
||||
slog.Error("failed to close version response", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var version schema.Version
|
||||
if err := json.NewDecoder(versionResp).Decode(&version); err != nil {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package build provides build information.
|
||||
package build
|
||||
|
||||
var (
|
||||
|
||||
@@ -107,7 +107,11 @@ func fetchLatestRelease() (*release, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
defer func() {
|
||||
if err = res.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("(%d) failed to send latest release request", res.StatusCode)
|
||||
@@ -139,7 +143,11 @@ func downloadFile(url string, dest string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
defer func() {
|
||||
if err = res.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("(%d) failed to send download file request", res.StatusCode)
|
||||
@@ -149,7 +157,11 @@ func downloadFile(url string, dest string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
defer func() {
|
||||
if err = out.Close(); err != nil {
|
||||
slog.Error("failed to close output file", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := io.Copy(out, res.Body); err != nil {
|
||||
return err
|
||||
@@ -207,12 +219,9 @@ func compareVersions(a, b string) int {
|
||||
bSplit := strings.Split(b, ".")
|
||||
bTotal := len(bSplit)
|
||||
|
||||
limit := aTotal
|
||||
if bTotal > aTotal {
|
||||
limit = bTotal
|
||||
}
|
||||
limit := max(aTotal, bTotal)
|
||||
|
||||
for i := 0; i < limit; i++ {
|
||||
for i := range limit {
|
||||
var x, y int
|
||||
|
||||
if i < aTotal {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package logger provides logging setup and configuration for the application.
|
||||
package logger
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package meta provides functionality for handling JWT claims.
|
||||
package meta
|
||||
|
||||
import (
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -123,7 +124,11 @@ func getIP(services []string, validationFunc func(string) bool) (string, error)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
slog.Error("failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
continue
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Package util provides utility functions.
|
||||
package util
|
||||
|
||||
import (
|
||||
|
||||
@@ -80,9 +80,10 @@ type Middleware struct {
|
||||
AgentId string `protobuf:"bytes,3,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
||||
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Config *structpb.Struct `protobuf:"bytes,5,opt,name=config,proto3" json:"config,omitempty"`
|
||||
Type MiddlewareType `protobuf:"varint,6,opt,name=type,proto3,enum=mantrae.v1.MiddlewareType" json:"type,omitempty"`
|
||||
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
|
||||
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||
Enabled bool `protobuf:"varint,6,opt,name=enabled,proto3" json:"enabled,omitempty"`
|
||||
Type MiddlewareType `protobuf:"varint,7,opt,name=type,proto3,enum=mantrae.v1.MiddlewareType" json:"type,omitempty"`
|
||||
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
|
||||
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -152,6 +153,13 @@ func (x *Middleware) GetConfig() *structpb.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Middleware) GetEnabled() bool {
|
||||
if x != nil {
|
||||
return x.Enabled
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Middleware) GetType() MiddlewareType {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
@@ -1032,7 +1040,7 @@ var file_mantrae_v1_middleware_proto_rawDesc = string([]byte{
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc1, 0x02, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdb, 0x02, 0x0a, 0x0a, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||
@@ -1042,202 +1050,204 @@ var file_mantrae_v1_middleware_proto_rawDesc = string([]byte{
|
||||
0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61,
|
||||
0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39,
|
||||
0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0xac, 0x03, 0x0a, 0x06, 0x50, 0x6c,
|
||||
0x75, 0x67, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70,
|
||||
0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||
0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61,
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74,
|
||||
0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f,
|
||||
0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f,
|
||||
0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x75,
|
||||
0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72,
|
||||
0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73,
|
||||
0x74, 0x61, 0x72, 0x73, 0x12, 0x33, 0x0a, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x18,
|
||||
0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74,
|
||||
0x52, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67,
|
||||
0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x38, 0x73,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x38, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x79,
|
||||
0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x12,
|
||||
0x12, 0x0a, 0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
|
||||
0x6f, 0x6d, 0x6c, 0x22, 0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22,
|
||||
0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x22, 0x4f, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a,
|
||||
0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0xed, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20,
|
||||
0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10,
|
||||
0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70,
|
||||
0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x52, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x17, 0x55, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65,
|
||||
0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2e, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a,
|
||||
0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x64, 0x41, 0x74, 0x22, 0xac, 0x03, 0x0a, 0x06, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61,
|
||||
0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6d,
|
||||
0x6d, 0x61, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d,
|
||||
0x61, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18,
|
||||
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72,
|
||||
0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c,
|
||||
0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72,
|
||||
0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x73, 0x12, 0x33,
|
||||
0x0a, 0x07, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75,
|
||||
0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x52, 0x07, 0x73, 0x6e, 0x69, 0x70,
|
||||
0x70, 0x65, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61,
|
||||
0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
||||
0x41, 0x74, 0x22, 0x49, 0x0a, 0x0d, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x6e, 0x69, 0x70,
|
||||
0x70, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x38, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 0x38, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x6f, 0x6d,
|
||||
0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x6f, 0x6d, 0x6c, 0x22, 0x6f, 0x0a,
|
||||
0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69,
|
||||
0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
|
||||
0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08,
|
||||
0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4f,
|
||||
0x0a, 0x15, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22,
|
||||
0xed, 0x01, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70,
|
||||
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42,
|
||||
0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49,
|
||||
0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42,
|
||||
0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32,
|
||||
0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08,
|
||||
0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f,
|
||||
0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
|
||||
0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x52, 0x0a, 0x18, 0x55, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0x72, 0x0a,
|
||||
0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x3b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b,
|
||||
0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x22, 0x1a, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xef, 0x02,
|
||||
0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48,
|
||||
0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00,
|
||||
0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x04,
|
||||
0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e,
|
||||
0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
|
||||
0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xba, 0x48, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01,
|
||||
0x48, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x71, 0x0a, 0x05, 0x6c,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x42, 0x56, 0xba, 0x48, 0x53, 0xba,
|
||||
0x01, 0x50, 0x0a, 0x0b, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12,
|
||||
0x29, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65,
|
||||
0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x2d, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x30, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73,
|
||||
0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e,
|
||||
0x20, 0x30, 0x48, 0x02, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24,
|
||||
0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07,
|
||||
0xba, 0x48, 0x04, 0x22, 0x02, 0x28, 0x00, 0x48, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65,
|
||||
0x74, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c,
|
||||
0x69, 0x6d, 0x69, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22,
|
||||
0x74, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x6d, 0x69,
|
||||
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||
0x52, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0a, 0x6d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c,
|
||||
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64,
|
||||
0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69,
|
||||
0x6e, 0x73, 0x2a, 0x64, 0x0a, 0x0e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
|
||||
0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41,
|
||||
0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46,
|
||||
0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57,
|
||||
0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12,
|
||||
0x17, 0x0a, 0x13, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x54, 0x43, 0x50, 0x10, 0x02, 0x32, 0xdc, 0x04, 0x0a, 0x11, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59,
|
||||
0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12,
|
||||
0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47,
|
||||
0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x5d, 0x0a, 0x10, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e,
|
||||
0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69,
|
||||
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07,
|
||||
0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01,
|
||||
0x01, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x04, 0x74,
|
||||
0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01, 0x82, 0x01, 0x02,
|
||||
0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63,
|
||||
0x74, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x22, 0x52, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x36, 0x0a, 0x0a, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x0a, 0x6d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x22, 0x72, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d,
|
||||
0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69,
|
||||
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
|
||||
0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x12, 0x6e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69,
|
||||
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12,
|
||||
0x27, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72,
|
||||
0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x03, 0x90, 0x02, 0x01, 0x42, 0xa9, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4d, 0x69, 0x64, 0x64,
|
||||
0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x7a, 0x75, 0x63, 0x68,
|
||||
0x69, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f,
|
||||
0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d,
|
||||
0x58, 0x58, 0xaa, 0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x56, 0x31, 0xca,
|
||||
0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x4d,
|
||||
0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74,
|
||||
0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0b, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x3a,
|
||||
0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x73, 0x74, 0x12, 0x1a, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a,
|
||||
0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02, 0x20, 0x00, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3b,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d,
|
||||
0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x0b, 0xba, 0x48, 0x08, 0xc8, 0x01, 0x01,
|
||||
0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xef, 0x02, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x0a, 0xba, 0x48, 0x07, 0xc8, 0x01, 0x01, 0x22, 0x02,
|
||||
0x20, 0x00, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x27, 0x0a,
|
||||
0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
|
||||
0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x48, 0x00, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e,
|
||||
0x74, 0x49, 0x64, 0x88, 0x01, 0x01, 0x12, 0x3d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65,
|
||||
0x42, 0x08, 0xba, 0x48, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x48, 0x01, 0x52, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x88, 0x01, 0x01, 0x12, 0x71, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x03, 0x42, 0x56, 0xba, 0x48, 0x53, 0xba, 0x01, 0x50, 0x0a, 0x0b, 0x6c, 0x69,
|
||||
0x6d, 0x69, 0x74, 0x2e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x29, 0x6c, 0x69, 0x6d, 0x69, 0x74,
|
||||
0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20,
|
||||
0x2d, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68,
|
||||
0x61, 0x6e, 0x20, 0x30, 0x1a, 0x16, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31,
|
||||
0x20, 0x7c, 0x7c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x3e, 0x20, 0x30, 0x48, 0x02, 0x52, 0x05,
|
||||
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73,
|
||||
0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x42, 0x07, 0xba, 0x48, 0x04, 0x22, 0x02, 0x28,
|
||||
0x00, 0x48, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0b,
|
||||
0x0a, 0x09, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f,
|
||||
0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x09,
|
||||
0x0a, 0x07, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x74, 0x0a, 0x17, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
|
||||
0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x52, 0x0b, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73, 0x12, 0x1f,
|
||||
0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22,
|
||||
0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
|
||||
0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4c,
|
||||
0x0a, 0x1c, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50,
|
||||
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c,
|
||||
0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x75,
|
||||
0x67, 0x69, 0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2a, 0x64, 0x0a, 0x0e,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f,
|
||||
0x0a, 0x1b, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50,
|
||||
0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,
|
||||
0x18, 0x0a, 0x14, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x48, 0x54, 0x54, 0x50, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x49, 0x44,
|
||||
0x44, 0x4c, 0x45, 0x57, 0x41, 0x52, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x43, 0x50,
|
||||
0x10, 0x02, 0x32, 0xdc, 0x04, 0x0a, 0x11, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72,
|
||||
0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64,
|
||||
0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03,
|
||||
0x90, 0x02, 0x01, 0x12, 0x5d, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64,
|
||||
0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d,
|
||||
0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64,
|
||||
0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d,
|
||||
0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x5d, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c,
|
||||
0x65, 0x77, 0x61, 0x72, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e,
|
||||
0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4d, 0x69,
|
||||
0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x5f, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
|
||||
0x72, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
|
||||
0x61, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02,
|
||||
0x01, 0x12, 0x6e, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61,
|
||||
0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x27, 0x2e, 0x6d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65,
|
||||
0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x28, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x47, 0x65, 0x74, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65, 0x50, 0x6c, 0x75,
|
||||
0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x90, 0x02,
|
||||
0x01, 0x42, 0xa9, 0x01, 0x0a, 0x0e, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61,
|
||||
0x65, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77, 0x61, 0x72, 0x65,
|
||||
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x7a, 0x75, 0x63, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2f,
|
||||
0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65,
|
||||
0x6e, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x6e,
|
||||
0x74, 0x72, 0x61, 0x65, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x58, 0x58, 0xaa, 0x02, 0x0a, 0x4d,
|
||||
0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0a, 0x4d, 0x61, 0x6e, 0x74,
|
||||
0x72, 0x61, 0x65, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x16, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65,
|
||||
0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea,
|
||||
0x02, 0x0b, 0x4d, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x65, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
})
|
||||
|
||||
var (
|
||||
|
||||
@@ -1219,6 +1219,9 @@ components:
|
||||
config:
|
||||
title: config
|
||||
$ref: '#/components/schemas/google.protobuf.Struct'
|
||||
enabled:
|
||||
type: boolean
|
||||
title: enabled
|
||||
type:
|
||||
title: type
|
||||
$ref: '#/components/schemas/mantrae.v1.MiddlewareType'
|
||||
|
||||
@@ -33,9 +33,10 @@ message Middleware {
|
||||
string agent_id = 3;
|
||||
string name = 4;
|
||||
google.protobuf.Struct config = 5;
|
||||
MiddlewareType type = 6;
|
||||
google.protobuf.Timestamp created_at = 7;
|
||||
google.protobuf.Timestamp updated_at = 8;
|
||||
bool enabled = 6;
|
||||
MiddlewareType type = 7;
|
||||
google.protobuf.Timestamp created_at = 8;
|
||||
google.protobuf.Timestamp updated_at = 9;
|
||||
}
|
||||
|
||||
message Plugin {
|
||||
|
||||
11
tygo.yaml
11
tygo.yaml
@@ -1,11 +0,0 @@
|
||||
packages:
|
||||
- path: "github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
output_path: "web/src/lib/gen/tygo/dynamic"
|
||||
type_mappings:
|
||||
ptypes.Duration: string
|
||||
|
||||
- path: "github.com/traefik/traefik/v3/pkg/tls"
|
||||
output_path: "web/src/lib/gen/tygo/tls"
|
||||
|
||||
- path: "github.com/traefik/traefik/v3/pkg/types"
|
||||
output_path: "web/src/lib/gen/tygo/types"
|
||||
@@ -2,12 +2,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="%sveltekit.assets%/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/ico" href="%sveltekit.assets%/favicon.ico" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="%sveltekit.assets%/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="%sveltekit.assets%/favicon-16x16.png" />
|
||||
<link rel="manifest" href="%sveltekit.assets%/site.webmanifest" />
|
||||
<link rel="mask-icon" href="%sveltekit.assets%/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/ico" href="/favicon.ico" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
|
||||
@@ -1,69 +1,244 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button/index';
|
||||
import { cleanupFormData, safeClone } from '$lib/utils';
|
||||
import FormField from './FormField.svelte';
|
||||
import type { FieldMetadata } from '$lib/types/middlewares';
|
||||
import Separator from '../ui/separator/separator.svelte';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Textarea } from '$lib/components/ui/textarea';
|
||||
import { extractSchemaFields, type FormField } from '$lib/formGenerator';
|
||||
import type { ZodSchema } from 'zod';
|
||||
import DynamicForm from './DynamicForm.svelte';
|
||||
import YAML from 'yaml';
|
||||
|
||||
interface Props {
|
||||
schema: ZodSchema;
|
||||
data: Record<string, unknown>;
|
||||
metadata?: Record<string, FieldMetadata>;
|
||||
onSubmit: (data: Record<string, unknown>) => void;
|
||||
disabled?: boolean;
|
||||
onUpdate: (data: Record<string, unknown>) => void;
|
||||
}
|
||||
|
||||
let { data = $bindable(), metadata = {}, onSubmit, disabled }: Props = $props();
|
||||
let { schema, data, onUpdate }: Props = $props();
|
||||
|
||||
// Form state
|
||||
let formData = $derived(safeClone(data));
|
||||
let fields = $derived(extractSchemaFields(schema));
|
||||
|
||||
// Handle form submission
|
||||
function handleSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
const clonedData = safeClone(formData);
|
||||
const cleanedData = (cleanupFormData(clonedData) as Record<string, unknown>) || {};
|
||||
onSubmit(cleanedData);
|
||||
// Make data reactive
|
||||
let formData = $derived(data);
|
||||
|
||||
function updateField(key: string, value: unknown) {
|
||||
formData[key] = value;
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
type FormFieldType = {
|
||||
key: string;
|
||||
path: string;
|
||||
value: unknown;
|
||||
metadata: FieldMetadata;
|
||||
type: string;
|
||||
};
|
||||
function addArrayItem(key: string) {
|
||||
if (!formData[key]) formData[key] = [];
|
||||
(formData[key] as unknown[]).push(getDefaultValue(fields[key].arrayItemType!));
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
// Process object fields
|
||||
const fields = $derived(processFields(formData));
|
||||
function processFields(obj: Record<string, unknown>, parentKey = ''): FormFieldType[] {
|
||||
return Object.entries(obj).flatMap(([key, value]) => {
|
||||
const currentPath = parentKey ? `${parentKey}.${key}` : key;
|
||||
const fieldMetadata = metadata[currentPath] || {};
|
||||
function removeArrayItem(key: string, index: number) {
|
||||
(formData[key] as unknown[]).splice(index, 1);
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
||||
return processFields(value as Record<string, unknown>, currentPath);
|
||||
function addRecordItem(key: string) {
|
||||
if (!formData[key]) formData[key] = {};
|
||||
const newKey = `key${Object.keys(formData[key] as object).length + 1}`;
|
||||
(formData[key] as Record<string, unknown>)[newKey] = getDefaultValue(
|
||||
fields[key].recordValueType!
|
||||
);
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
function removeRecordItem(key: string, recordKey: string) {
|
||||
delete (formData[key] as Record<string, unknown>)[recordKey];
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
function updateRecordKey(key: string, oldKey: string, newKey: string) {
|
||||
const record = formData[key] as Record<string, unknown>;
|
||||
if (oldKey !== newKey && !record[newKey]) {
|
||||
record[newKey] = record[oldKey];
|
||||
delete record[oldKey];
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
}
|
||||
|
||||
function updateRecordValue(key: string, recordKey: string, value: unknown) {
|
||||
(formData[key] as Record<string, unknown>)[recordKey] = value;
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
|
||||
let yamlError = $state<string | null>(null);
|
||||
function handlePluginChange(value: string) {
|
||||
try {
|
||||
const parsed = YAML.parse(value);
|
||||
if (parsed) {
|
||||
yamlError = null;
|
||||
formData = parsed;
|
||||
onUpdate({ ...formData });
|
||||
}
|
||||
} catch (e) {
|
||||
yamlError = e instanceof Error ? e.message : 'Invalid YAML';
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
key,
|
||||
path: currentPath,
|
||||
value,
|
||||
metadata: fieldMetadata,
|
||||
type: Array.isArray(value) ? 'array' : typeof value
|
||||
}
|
||||
];
|
||||
});
|
||||
function getPluginValue(): string {
|
||||
const value = formData;
|
||||
if (typeof value === 'string') return value;
|
||||
if (typeof value === 'object') return YAML.stringify(value, { indent: 2 });
|
||||
return '';
|
||||
}
|
||||
|
||||
function getDefaultValue(field: FormField): unknown {
|
||||
switch (field.type) {
|
||||
case 'string':
|
||||
return '';
|
||||
case 'number':
|
||||
return 0;
|
||||
case 'boolean':
|
||||
return false;
|
||||
case 'array':
|
||||
return [];
|
||||
case 'object':
|
||||
return {};
|
||||
case 'record':
|
||||
return {};
|
||||
case 'plugin':
|
||||
return {};
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form onsubmit={handleSubmit}>
|
||||
<div class="grid gap-4">
|
||||
{#each fields as field (field.key)}
|
||||
<FormField {...field} {disabled} bind:data={formData} />
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each Object.entries(fields) as [key, field] (key)}
|
||||
<div class="flex flex-col gap-2">
|
||||
<Label class="text-sm font-medium">
|
||||
{field.label}
|
||||
{#if !field.optional}
|
||||
<span class="text-red-500">*</span>
|
||||
{/if}
|
||||
</Label>
|
||||
|
||||
<Separator class="my-4" />
|
||||
<Button type="submit" class="w-full">Save</Button>
|
||||
</form>
|
||||
{#if field.type === 'string'}
|
||||
<Input
|
||||
bind:value={data[key]}
|
||||
placeholder={field.description}
|
||||
oninput={() => updateField(key, data[key])}
|
||||
/>
|
||||
{:else if field.type === 'number'}
|
||||
<Input
|
||||
type="number"
|
||||
bind:value={data[key]}
|
||||
placeholder={field.description}
|
||||
oninput={() => updateField(key, data[key])}
|
||||
/>
|
||||
{:else if field.type === 'boolean'}
|
||||
<Checkbox
|
||||
checked={data[key] as boolean}
|
||||
onCheckedChange={(checked) => updateField(key, checked)}
|
||||
/>
|
||||
{:else if field.type === 'plugin'}
|
||||
<div class="flex flex-col gap-2">
|
||||
<Textarea
|
||||
value={getPluginValue()}
|
||||
placeholder="Edit plugin configuration as YAML"
|
||||
class="min-h-[100px] font-mono text-sm"
|
||||
oninput={(e) => handlePluginChange(e.currentTarget.value)}
|
||||
/>
|
||||
{#if yamlError}
|
||||
<p class="text-xs text-red-400 dark:text-red-700">{yamlError}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if field.type === 'array'}
|
||||
<div class="flex flex-col gap-2 rounded-md border p-3">
|
||||
{#if data[key] && Array.isArray(data[key])}
|
||||
{#each data[key] as item, index (index)}
|
||||
<div class="flex items-center gap-2">
|
||||
{#if field.arrayItemType?.type === 'string'}
|
||||
<Input
|
||||
bind:value={data[key][index]}
|
||||
oninput={() => updateField(key, data[key])}
|
||||
/>
|
||||
{:else if field.arrayItemType?.type === 'number'}
|
||||
<Input
|
||||
type="number"
|
||||
bind:value={data[key][index]}
|
||||
oninput={() => updateField(key, data[key])}
|
||||
/>
|
||||
{:else if field.arrayItemType?.type === 'object' && field.arrayItemType.nestedSchema}
|
||||
<div class="flex-1 rounded border p-2">
|
||||
<DynamicForm
|
||||
schema={field.arrayItemType.nestedSchema}
|
||||
data={(data[key][index] as Record<string, unknown>) || {}}
|
||||
onUpdate={(nestedData) => {
|
||||
(data[key] as unknown[])[index] = nestedData;
|
||||
updateField(key, data[key]);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<Button variant="outline" size="sm" onclick={() => removeArrayItem(key, index)}>
|
||||
Remove
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
<Button variant="outline" size="sm" onclick={() => addArrayItem(key)}>
|
||||
Add {field.label}
|
||||
</Button>
|
||||
</div>
|
||||
{:else if field.type === 'record'}
|
||||
<div class="flex flex-col gap-2 rounded-md border p-3">
|
||||
{#if formData[key] && typeof formData[key] === 'object'}
|
||||
{#each Object.entries(formData[key] as Record<string, unknown>) as [recordKey, recordValue], index (recordKey)}
|
||||
<div class="flex items-center gap-2">
|
||||
<Input
|
||||
value={recordKey}
|
||||
placeholder="Key"
|
||||
oninput={(e) => updateRecordKey(key, recordKey, e.currentTarget.value)}
|
||||
/>
|
||||
{#if field.recordValueType?.type === 'string'}
|
||||
<Input
|
||||
value={recordValue as string}
|
||||
placeholder="Value"
|
||||
oninput={(e) => updateRecordValue(key, recordKey, e.currentTarget.value)}
|
||||
/>
|
||||
{:else if field.recordValueType?.type === 'number'}
|
||||
<Input
|
||||
type="number"
|
||||
value={recordValue as number}
|
||||
placeholder="Value"
|
||||
oninput={(e) =>
|
||||
updateRecordValue(key, recordKey, parseFloat(e.currentTarget.value) || 0)}
|
||||
/>
|
||||
{/if}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={() => removeRecordItem(key, recordKey)}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
<Button variant="outline" size="sm" onclick={() => addRecordItem(key)}>
|
||||
Add {field.label} Entry
|
||||
</Button>
|
||||
</div>
|
||||
{:else if field.type === 'object' && field.nestedSchema}
|
||||
<div class="rounded-md border p-3">
|
||||
<DynamicForm
|
||||
schema={field.nestedSchema}
|
||||
data={(formData[key] as Record<string, unknown>) || {}}
|
||||
onUpdate={(nestedData) => updateField(key, nestedData)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if field.description}
|
||||
<p class="text-muted-foreground text-xs">{field.description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
<script lang="ts">
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import { Plus, Trash } from '@lucide/svelte';
|
||||
import { mwNames } from '$lib/api';
|
||||
import type { FieldMetadata } from '$lib/types/middlewares';
|
||||
import Separator from '../ui/separator/separator.svelte';
|
||||
|
||||
interface Props {
|
||||
key: string;
|
||||
path: string;
|
||||
type: string;
|
||||
data: Record<string, unknown>;
|
||||
metadata?: FieldMetadata;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
let { key, path, type, data = $bindable(), metadata = {}, disabled }: Props = $props();
|
||||
|
||||
type FormValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| string[]
|
||||
| Record<string, unknown>
|
||||
| Record<string, unknown>[];
|
||||
|
||||
function getNestedValue(obj: Record<string, unknown>, path: string): FormValue {
|
||||
return path.split('.').reduce<unknown>((acc, part) => {
|
||||
if (acc && typeof acc === 'object') {
|
||||
return (acc as Record<string, unknown>)[part];
|
||||
}
|
||||
return undefined;
|
||||
}, obj) as FormValue;
|
||||
}
|
||||
|
||||
function setNestedValue(obj: Record<string, unknown>, path: string, value: FormValue) {
|
||||
const parts = path.split('.');
|
||||
const last = parts.pop()!;
|
||||
const target = parts.reduce((acc, part) => {
|
||||
if (!acc[part] || typeof acc[part] !== 'object') {
|
||||
acc[part] = {};
|
||||
}
|
||||
return acc[part] as Record<string, unknown>;
|
||||
}, obj);
|
||||
target[last] = value;
|
||||
}
|
||||
|
||||
function handleChange(e: Event) {
|
||||
const target = e.target as HTMLInputElement;
|
||||
const newValue = type === 'number' ? Number(target.value) : target.value;
|
||||
setNestedValue(data, path, newValue);
|
||||
}
|
||||
|
||||
function handleSwitchChange(checked: boolean) {
|
||||
setNestedValue(data, path, checked);
|
||||
}
|
||||
|
||||
function handleArrayChange(index: number, value: string) {
|
||||
const array = (getNestedValue(data, path) as string[]) || [];
|
||||
array[index] = value;
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
function addArrayItem() {
|
||||
const array = (getNestedValue(data, path) as string[]) || [];
|
||||
array.push('');
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
function removeArrayItem(index: number) {
|
||||
const array = (getNestedValue(data, path) as string[]) || [];
|
||||
array.splice(index, 1);
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
const fieldValue = $derived(getNestedValue(data, path));
|
||||
|
||||
function formatLabel(str: string): string {
|
||||
return str
|
||||
.split(/(?=[A-Z])/)
|
||||
.join(' ')
|
||||
.replace(/^\w/, (c) => c.toUpperCase());
|
||||
}
|
||||
|
||||
// Extra special cases
|
||||
const isChainMiddleware = $derived(path === 'middlewares');
|
||||
function handleMiddlewareChange(values: string[]) {
|
||||
setNestedValue(data, path, values);
|
||||
}
|
||||
|
||||
function handleObjectArrayChange(index: number, field: string, value: string) {
|
||||
const array = (getNestedValue(data, path) as Record<string, unknown>[]) || [];
|
||||
if (!isObjectArray(array)) return;
|
||||
if (!array[index]) {
|
||||
array[index] = {};
|
||||
}
|
||||
array[index] = { ...array[index], [field]: value };
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
function removeObjectArrayItem(index: number) {
|
||||
if (index < 1) return;
|
||||
const array = (getNestedValue(data, path) as string[]) || [];
|
||||
array.splice(index, 1);
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
function addObjectArrayItem() {
|
||||
const array = (getNestedValue(data, path) as Record<string, unknown>[]) || [];
|
||||
// Use the first item as a template, creating an object with the same keys but empty values
|
||||
const template = array[0] || {};
|
||||
const newItem = Object.keys(template).reduce(
|
||||
(obj, key) => {
|
||||
obj[key] = '';
|
||||
return obj;
|
||||
},
|
||||
{} as Record<string, unknown>
|
||||
);
|
||||
array.push(newItem);
|
||||
setNestedValue(data, path, array);
|
||||
}
|
||||
|
||||
// Helper to detect if array contains objects
|
||||
function isObjectArray(value: unknown[]): value is Record<string, unknown>[] {
|
||||
return (
|
||||
Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && value[0] !== null
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for={path} class="flex flex-row items-center justify-between">
|
||||
{formatLabel(key)}
|
||||
{#if metadata.description}
|
||||
<span class="text-muted-foreground ml-1 text-sm">
|
||||
{metadata.description}
|
||||
</span>
|
||||
{/if}
|
||||
</Label>
|
||||
|
||||
{#if isChainMiddleware}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#if Array.isArray(fieldValue) && fieldValue.length > 0 && disabled}
|
||||
{#each fieldValue as middleware (middleware)}
|
||||
<div class="flex items-center gap-2">
|
||||
<Input type="text" value={middleware} readonly {disabled} />
|
||||
{#if !disabled}
|
||||
<Button variant="destructive" size="icon" type="button">
|
||||
<Trash class="h-4 w-4" />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{#if !disabled}
|
||||
<Select.Root
|
||||
type="multiple"
|
||||
value={fieldValue as string[]}
|
||||
onValueChange={handleMiddlewareChange}
|
||||
{disabled}
|
||||
>
|
||||
<Select.Trigger>
|
||||
{Array.isArray(fieldValue) && fieldValue.length > 0
|
||||
? fieldValue.join(', ')
|
||||
: 'Select Middlewares'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each $mwNames as name (name)}
|
||||
<Select.Item value={name}>{name}</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if type === 'boolean'}
|
||||
<Switch
|
||||
id={path}
|
||||
checked={fieldValue as boolean}
|
||||
onCheckedChange={handleSwitchChange}
|
||||
{disabled}
|
||||
/>
|
||||
{:else if type === 'array'}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#if Array.isArray(fieldValue) && isObjectArray(fieldValue)}
|
||||
<div class="ml-4 flex flex-col gap-2 rounded border-l p-4">
|
||||
{#each fieldValue as item, i (i)}
|
||||
<div class="flex flex-col gap-2 rounded">
|
||||
{#each Object.entries(item) as [field, value] (field)}
|
||||
<div class="grid grid-cols-4 items-center gap-2">
|
||||
<Label class="col-span-1">{formatLabel(field)}</Label>
|
||||
<Input
|
||||
type="text"
|
||||
value={value as string}
|
||||
class="col-span-3"
|
||||
onchange={(e) =>
|
||||
handleObjectArrayChange(i, field, (e.target as HTMLInputElement).value)}
|
||||
placeholder={metadata.placeholder}
|
||||
{disabled}
|
||||
/>
|
||||
</div>
|
||||
{/each}
|
||||
<Separator class="my-2" />
|
||||
{#if !disabled}
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
type="button"
|
||||
class="w-full text-red-500"
|
||||
onclick={() => removeObjectArrayItem(i)}
|
||||
>
|
||||
<Trash />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
{#each (fieldValue as string[]) || [] as value, i (i)}
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
type="text"
|
||||
{value}
|
||||
onchange={(e) => handleArrayChange(i, (e.target as HTMLInputElement).value)}
|
||||
placeholder={metadata.placeholder}
|
||||
{disabled}
|
||||
/>
|
||||
{#if !disabled}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
type="button"
|
||||
class="text-red-500"
|
||||
onclick={() => removeArrayItem(i)}
|
||||
>
|
||||
<Trash />
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
{#if !disabled}
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onclick={Array.isArray(fieldValue) && isObjectArray(fieldValue)
|
||||
? addObjectArrayItem
|
||||
: addArrayItem}
|
||||
class="w-full"
|
||||
>
|
||||
<Plus />
|
||||
Add {key.charAt(0).toUpperCase() + key.slice(1)}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if type === 'number'}
|
||||
<Input
|
||||
type="number"
|
||||
id={path}
|
||||
value={fieldValue !== undefined ? (fieldValue as number) : ''}
|
||||
onchange={handleChange}
|
||||
placeholder={metadata.placeholder}
|
||||
{disabled}
|
||||
/>
|
||||
{#if metadata.examples?.length}
|
||||
<div class="text-muted-foreground text-sm">
|
||||
Examples: {metadata.examples.join(', ')}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<Input
|
||||
type="text"
|
||||
id={path}
|
||||
value={fieldValue as string}
|
||||
placeholder={metadata.placeholder}
|
||||
onchange={handleChange}
|
||||
{disabled}
|
||||
/>
|
||||
{#if metadata.examples?.length}
|
||||
<div class="text-muted-foreground text-sm">
|
||||
Examples: {metadata.examples.join(', ')}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -1,127 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button/index';
|
||||
import { Textarea } from '$lib/components/ui/textarea/index.js';
|
||||
|
||||
import Separator from '../ui/separator/separator.svelte';
|
||||
import { loading } from '$lib/api';
|
||||
import YAML from 'yaml';
|
||||
|
||||
interface Props {
|
||||
data: Record<string, unknown>;
|
||||
onSubmit: (data: Record<string, unknown>) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
let { data = $bindable(), onSubmit, disabled }: Props = $props();
|
||||
|
||||
// Form state
|
||||
let formData = $derived(YAML.stringify(data, { indent: 2 }));
|
||||
let errorMessage = $state<string | null>(null);
|
||||
let isValid = $state(true);
|
||||
|
||||
// Validate YAML and return boolean
|
||||
function validateYAML(input: string): boolean {
|
||||
try {
|
||||
YAML.parse(input);
|
||||
errorMessage = null;
|
||||
return true;
|
||||
} catch (e) {
|
||||
errorMessage = e instanceof Error ? e.message : 'Invalid YAML';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Format YAML with proper indentation
|
||||
function formatYAML(input: string): string {
|
||||
try {
|
||||
const parsed = YAML.parse(input);
|
||||
return YAML.stringify(parsed, { indent: 2 });
|
||||
} catch {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle input changes
|
||||
function handleInput(e: Event) {
|
||||
const input = (e.target as HTMLTextAreaElement).value;
|
||||
formData = input;
|
||||
isValid = validateYAML(input);
|
||||
}
|
||||
|
||||
// Format on blur
|
||||
function handleBlur() {
|
||||
if (isValid) {
|
||||
formData = formatYAML(formData);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle tab key
|
||||
function handleKeydown(e: KeyboardEvent & { currentTarget: HTMLTextAreaElement }) {
|
||||
if (e.key === 'Tab') {
|
||||
e.preventDefault();
|
||||
const target = e.currentTarget;
|
||||
const start = target.selectionStart;
|
||||
const end = target.selectionEnd;
|
||||
const newPosition = start + 2;
|
||||
|
||||
// Handle selected text
|
||||
if (start !== end) {
|
||||
const lines = formData.split('\n');
|
||||
let startLine = formData.substring(0, start).split('\n').length - 1;
|
||||
let endLine = formData.substring(0, end).split('\n').length - 1;
|
||||
|
||||
// Indent or unindent selected lines
|
||||
const newLines = lines.map((line, i) => {
|
||||
if (i >= startLine && i <= endLine) {
|
||||
return e.shiftKey ? line.replace(/^ {2}/, '') : ' ' + line;
|
||||
}
|
||||
return line;
|
||||
});
|
||||
|
||||
formData = newLines.join('\n');
|
||||
requestAnimationFrame(() => {
|
||||
target.setSelectionRange(newPosition, newPosition);
|
||||
});
|
||||
} else {
|
||||
// Insert tab at cursor position
|
||||
formData = formData.substring(0, start) + ' ' + formData.substring(end);
|
||||
requestAnimationFrame(() => {
|
||||
target.setSelectionRange(newPosition, newPosition);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
function handleSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
if (!isValid) return;
|
||||
|
||||
try {
|
||||
const parsed = YAML.parse(formData);
|
||||
onSubmit(parsed);
|
||||
} catch (e) {
|
||||
errorMessage = e instanceof Error ? e.message : 'Failed to parse YAML';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form onsubmit={handleSubmit}>
|
||||
<div class="grid gap-4">
|
||||
<Textarea
|
||||
value={formData}
|
||||
rows={formData.split('\n').length}
|
||||
class={!isValid ? 'border-red-500 font-mono' : 'font-mono'}
|
||||
oninput={handleInput}
|
||||
onblur={handleBlur}
|
||||
onkeydown={handleKeydown}
|
||||
{disabled}
|
||||
/>
|
||||
{#if errorMessage}
|
||||
<p class="text-sm text-red-500">{errorMessage}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Separator class="my-4" />
|
||||
<Button type="submit" class="w-full" disabled={$loading || !isValid || disabled}>Save</Button>
|
||||
</form>
|
||||
@@ -1,27 +1,27 @@
|
||||
<script lang="ts">
|
||||
import * as Select from '$lib/components/ui/select/index.js';
|
||||
import { Badge } from '$lib/components/ui/badge/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import type { Middleware as HttpMiddleware } from '$lib/gen/tygo/dynamic';
|
||||
import { type Middleware } from '$lib/gen/mantrae/v1/middleware_pb';
|
||||
import { unmarshalConfig, marshalConfig, HTTPMiddlewareKeys } from '$lib/types';
|
||||
import { unmarshalConfig, marshalConfig } from '$lib/types';
|
||||
import {
|
||||
MiddlewareSchema,
|
||||
type Middleware as HTTPMiddleware
|
||||
} from '$lib/gen/zen/traefik-schemas';
|
||||
import DynamicForm from './DynamicForm.svelte';
|
||||
|
||||
let { middleware = $bindable() }: { middleware: Middleware } = $props();
|
||||
|
||||
let config = $state(unmarshalConfig(middleware.config) as HttpMiddleware);
|
||||
let selectedType = $state(config ? Object.keys(config)[0] : '');
|
||||
let config = $state(unmarshalConfig(middleware.config) as HTTPMiddleware);
|
||||
let selectedType = $derived(config ? Object.keys(config)[0] : '');
|
||||
|
||||
$effect(() => {
|
||||
if (config) middleware.config = marshalConfig(config);
|
||||
// if (selectedType) {
|
||||
// config = {
|
||||
// ...config,
|
||||
// [selectedType]: {}
|
||||
// };
|
||||
// // middleware.config = marshalConfig(config);
|
||||
// }
|
||||
});
|
||||
|
||||
const middlewareTypes = Object.keys(MiddlewareSchema.shape).map((key) => ({
|
||||
value: key,
|
||||
label: key.replace(/([A-Z])/g, ' $1').replace(/^./, (s) => s.toUpperCase()) // dumb prettifier
|
||||
}));
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
@@ -31,11 +31,11 @@
|
||||
<Select.Root type="single" bind:value={selectedType}>
|
||||
<Select.Trigger class="w-full">
|
||||
{selectedType
|
||||
? HTTPMiddlewareKeys.find((t) => t.value === selectedType)?.label
|
||||
? middlewareTypes.find((t) => t.value === selectedType)?.label
|
||||
: 'Select type'}
|
||||
</Select.Trigger>
|
||||
<Select.Content class="no-scrollbar max-h-[300px] overflow-y-auto">
|
||||
{#each HTTPMiddlewareKeys as t (t.value)}
|
||||
{#each middlewareTypes as t (t.value)}
|
||||
<Select.Item value={t.value}>{t.label}</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
@@ -43,6 +43,12 @@
|
||||
</div>
|
||||
|
||||
{#if selectedType}
|
||||
<!-- dynamic form -->
|
||||
<DynamicForm
|
||||
schema={MiddlewareSchema.shape[selectedType as keyof typeof MiddlewareSchema.shape]}
|
||||
data={(config[selectedType as keyof HTTPMiddleware] as Record<string, unknown>) || {}}
|
||||
onUpdate={(updatedData) => {
|
||||
config = { [selectedType]: updatedData } as HTTPMiddleware;
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { RouterType, type Router } from '$lib/gen/mantrae/v1/router_pb';
|
||||
import type { Router as HttpRouter, RouterTLSConfig } from '$lib/gen/tygo/dynamic';
|
||||
import type { Router as HTTPRouter, RouterTLSConfig } from '$lib/gen/zen/traefik-schemas';
|
||||
import { Star } from '@lucide/svelte';
|
||||
import { entryPointClient, middlewareClient, routerClient } from '$lib/api';
|
||||
import { MiddlewareType } from '$lib/gen/mantrae/v1/middleware_pb';
|
||||
@@ -16,7 +16,7 @@
|
||||
let { router = $bindable() }: { router: Router } = $props();
|
||||
|
||||
let certResolvers: string[] = $state([]);
|
||||
let config = $state(unmarshalConfig(router.config) as HttpRouter);
|
||||
let config = $state(unmarshalConfig(router.config) as HTTPRouter);
|
||||
|
||||
$effect(() => {
|
||||
if (config) router.config = marshalConfig(config);
|
||||
@@ -33,12 +33,12 @@
|
||||
const resolverSet = new Set(
|
||||
response.routers
|
||||
.filter((r) => {
|
||||
let tmp = unmarshalConfig(r.config) as HttpRouter;
|
||||
let tmp = unmarshalConfig(r.config) as HTTPRouter;
|
||||
if (!tmp?.tls?.certResolver) return false;
|
||||
return true;
|
||||
})
|
||||
.map((r) => {
|
||||
let tmp = unmarshalConfig(r.config) as HttpRouter;
|
||||
let tmp = unmarshalConfig(r.config) as HTTPRouter;
|
||||
return tmp.tls?.certResolver ?? '';
|
||||
})
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { Switch } from '$lib/components/ui/switch/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { ServiceType, type Service } from '$lib/gen/mantrae/v1/service_pb';
|
||||
import type { Service as HTTPService } from '$lib/gen/tygo/dynamic';
|
||||
import type { Service as HTTPService } from '$lib/gen/zen/traefik-schemas';
|
||||
import { Plus, Trash } from '@lucide/svelte';
|
||||
import { marshalConfig } from '$lib/types';
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
if (service.config) {
|
||||
config = service.config as HTTPService;
|
||||
}
|
||||
if (!config.loadBalancer) config.loadBalancer = {};
|
||||
if (!config.loadBalancer) config.loadBalancer = { passHostHeader: true };
|
||||
if (!config.loadBalancer.servers) config.loadBalancer.servers = [];
|
||||
if (config.loadBalancer.servers.length === 0) {
|
||||
config.loadBalancer.servers = [{ url: '' }];
|
||||
@@ -35,7 +35,7 @@
|
||||
class="col-span-3"
|
||||
checked={config.loadBalancer?.passHostHeader ?? true}
|
||||
onCheckedChange={(value) => {
|
||||
if (!config.loadBalancer) config.loadBalancer = {};
|
||||
if (!config.loadBalancer) config.loadBalancer = { passHostHeader: true };
|
||||
config.loadBalancer.passHostHeader = value;
|
||||
service.config = marshalConfig(config);
|
||||
}}
|
||||
@@ -65,7 +65,7 @@
|
||||
class="text-red-500"
|
||||
onclick={() => {
|
||||
if (i === 0) return;
|
||||
if (!config.loadBalancer) config.loadBalancer = {};
|
||||
if (!config.loadBalancer) config.loadBalancer = { passHostHeader: true };
|
||||
if (!config.loadBalancer.servers) config.loadBalancer.servers = [];
|
||||
config.loadBalancer.servers = config.loadBalancer.servers.filter((_, j) => j !== i);
|
||||
service.config = marshalConfig(config);
|
||||
@@ -81,7 +81,7 @@
|
||||
variant="outline"
|
||||
class="w-full"
|
||||
onclick={() => {
|
||||
if (!config.loadBalancer) config.loadBalancer = {};
|
||||
if (!config.loadBalancer) config.loadBalancer = { passHostHeader: true };
|
||||
if (!config.loadBalancer.servers) config.loadBalancer.servers = [];
|
||||
config.loadBalancer.servers = [...config.loadBalancer.servers, { url: '' }];
|
||||
service.config = marshalConfig(config);
|
||||
|
||||
51
web/src/lib/components/forms/tcpMiddleware.svelte
Normal file
51
web/src/lib/components/forms/tcpMiddleware.svelte
Normal file
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import * as Select from '$lib/components/ui/select/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { type Middleware } from '$lib/gen/mantrae/v1/middleware_pb';
|
||||
import { unmarshalConfig, marshalConfig } from '$lib/types';
|
||||
import { TCPMiddlewareSchema, type TCPMiddleware } from '$lib/gen/zen/traefik-schemas';
|
||||
import DynamicForm from './DynamicForm.svelte';
|
||||
|
||||
let { middleware = $bindable() }: { middleware: Middleware } = $props();
|
||||
|
||||
let config = $state(unmarshalConfig(middleware.config) as TCPMiddleware);
|
||||
let selectedType = $derived(config ? Object.keys(config)[0] : '');
|
||||
|
||||
$effect(() => {
|
||||
if (config) middleware.config = marshalConfig(config);
|
||||
});
|
||||
|
||||
const middlewareTypes = Object.keys(TCPMiddlewareSchema.shape).map((key) => ({
|
||||
value: key,
|
||||
label: key.replace(/([A-Z])/g, ' $1').replace(/^./, (s) => s.toUpperCase()) // dumb prettifier
|
||||
}));
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
<!-- Middleware Type -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<Label class="mr-2">Type</Label>
|
||||
<Select.Root type="single" bind:value={selectedType}>
|
||||
<Select.Trigger class="w-full">
|
||||
{selectedType
|
||||
? middlewareTypes.find((t) => t.value === selectedType)?.label
|
||||
: 'Select type'}
|
||||
</Select.Trigger>
|
||||
<Select.Content class="no-scrollbar max-h-[300px] overflow-y-auto">
|
||||
{#each middlewareTypes as t (t.value)}
|
||||
<Select.Item value={t.value}>{t.label}</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
{#if selectedType}
|
||||
<DynamicForm
|
||||
schema={TCPMiddlewareSchema.shape[selectedType as keyof typeof TCPMiddlewareSchema.shape]}
|
||||
data={(config[selectedType as keyof TCPMiddleware] as Record<string, unknown>) || {}}
|
||||
onUpdate={(updatedData) => {
|
||||
config = { [selectedType]: updatedData } as TCPMiddleware;
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -5,7 +5,7 @@
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { RouterType, type Router } from '$lib/gen/mantrae/v1/router_pb';
|
||||
import type { RouterTCPTLSConfig, TCPRouter } from '$lib/gen/tygo/dynamic';
|
||||
import type { RouterTCPTLSConfig, TCPRouter } from '$lib/gen/zen/traefik-schemas';
|
||||
import { Star } from '@lucide/svelte';
|
||||
import { entryPointClient, middlewareClient, routerClient } from '$lib/api';
|
||||
import { MiddlewareType } from '$lib/gen/mantrae/v1/middleware_pb';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { ServiceType, type Service } from '$lib/gen/mantrae/v1/service_pb';
|
||||
import { Plus, Trash } from '@lucide/svelte';
|
||||
import { marshalConfig } from '$lib/types';
|
||||
import type { TCPService } from '$lib/gen/tygo/dynamic';
|
||||
import type { TCPService } from '$lib/gen/zen/traefik-schemas';
|
||||
|
||||
interface Props {
|
||||
service: Service;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import * as Select from '$lib/components/ui/select/index.js';
|
||||
import { Label } from '$lib/components/ui/label/index.js';
|
||||
import { type Router } from '$lib/gen/mantrae/v1/router_pb';
|
||||
import type { UDPRouter } from '$lib/gen/tygo/dynamic';
|
||||
import type { UDPRouter } from '$lib/gen/zen/traefik-schemas';
|
||||
import { Star } from '@lucide/svelte';
|
||||
import { entryPointClient } from '$lib/api';
|
||||
import { unmarshalConfig, marshalConfig } from '$lib/types';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { ServiceType, type Service } from '$lib/gen/mantrae/v1/service_pb';
|
||||
import { Plus, Trash } from '@lucide/svelte';
|
||||
import { marshalConfig } from '$lib/types';
|
||||
import type { UDPService } from '$lib/gen/tygo/dynamic';
|
||||
import type { UDPService } from '$lib/gen/zen/traefik-schemas';
|
||||
|
||||
interface Props {
|
||||
service: Service;
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
import { ConnectError } from '@connectrpc/connect';
|
||||
import { profile } from '$lib/stores/profile';
|
||||
import { pageIndex, pageSize } from '$lib/stores/common';
|
||||
import HttpMiddleware from '../forms/httpMiddleware.svelte';
|
||||
import HTTPMiddlewareForm from '../forms/httpMiddleware.svelte';
|
||||
import TCPMiddlewareForm from '../forms/tcpMiddleware.svelte';
|
||||
|
||||
interface Props {
|
||||
data: Middleware[];
|
||||
@@ -28,7 +29,8 @@
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
config: item.config,
|
||||
type: item.type
|
||||
type: item.type,
|
||||
enabled: item.enabled
|
||||
});
|
||||
toast.success('Middleware updated successfully');
|
||||
} else {
|
||||
@@ -84,7 +86,7 @@
|
||||
<Dialog.Description>Configure your Traefik middleware</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<form onsubmit={handleSubmit} class="flex flex-col gap-4">
|
||||
<form class="flex flex-col gap-4">
|
||||
<div class="grid w-full grid-cols-3 gap-2">
|
||||
<div class="col-span-2 flex flex-col gap-2">
|
||||
<Label for="name">Name</Label>
|
||||
@@ -117,7 +119,10 @@
|
||||
</div>
|
||||
|
||||
{#if item.type === MiddlewareType.HTTP}
|
||||
<HttpMiddleware bind:middleware={item} />
|
||||
<HTTPMiddlewareForm bind:middleware={item} />
|
||||
{/if}
|
||||
{#if item.type === MiddlewareType.TCP}
|
||||
<TCPMiddlewareForm bind:middleware={item} />
|
||||
{/if}
|
||||
|
||||
<Separator />
|
||||
|
||||
@@ -185,48 +185,50 @@
|
||||
|
||||
<!-- DNS Providers -->
|
||||
{#await dnsClient.listDnsProviders({ limit: -1n, offset: 0n }) then value}
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<div bind:this={dnsAnchor}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="flex items-center gap-2"
|
||||
onclick={() => (selectDNSOpen = true)}
|
||||
>
|
||||
<Globe size={16} />
|
||||
<Badge>
|
||||
{item.dnsProviders.length > 0
|
||||
? item.dnsProviders.map((p) => p.name).join(', ')
|
||||
: 'None'}
|
||||
</Badge>
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content side="left" align="center">
|
||||
<p>Select DNS Provider</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
{#if value.dnsProviders.length > 0}
|
||||
<Tooltip.Provider>
|
||||
<Tooltip.Root>
|
||||
<Tooltip.Trigger>
|
||||
<div bind:this={dnsAnchor}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="flex items-center gap-2"
|
||||
onclick={() => (selectDNSOpen = true)}
|
||||
>
|
||||
<Globe size={16} />
|
||||
<Badge>
|
||||
{item.dnsProviders?.length > 0
|
||||
? item.dnsProviders?.map((p) => p.name).join(', ')
|
||||
: 'None'}
|
||||
</Badge>
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Content side="left" align="center">
|
||||
<p>Select DNS Provider</p>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Root>
|
||||
</Tooltip.Provider>
|
||||
|
||||
<Select.Root
|
||||
type="multiple"
|
||||
value={item.dnsProviders.map((item) => item.id.toString())}
|
||||
onValueChange={handleDNSProviderChange}
|
||||
bind:open={selectDNSOpen}
|
||||
>
|
||||
<Select.Content customAnchor={dnsAnchor} align="end">
|
||||
{#each value.dnsProviders as dns (dns.id)}
|
||||
<Select.Item value={dns.id.toString()} class="flex items-center gap-2">
|
||||
{dns.name}
|
||||
{#if dns.isActive}
|
||||
<CircleCheck size="1rem" class="text-green-400" />
|
||||
{/if}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
<Select.Root
|
||||
type="multiple"
|
||||
value={item.dnsProviders?.map((item) => item.id.toString())}
|
||||
onValueChange={handleDNSProviderChange}
|
||||
bind:open={selectDNSOpen}
|
||||
>
|
||||
<Select.Content customAnchor={dnsAnchor} align="end">
|
||||
{#each value.dnsProviders as dns (dns.id)}
|
||||
<Select.Item value={dns.id.toString()} class="flex items-center gap-2">
|
||||
{dns.name}
|
||||
{#if dns.isActive}
|
||||
<CircleCheck size="1rem" class="text-green-400" />
|
||||
{/if}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
{/if}
|
||||
{/await}
|
||||
</Card.Header>
|
||||
<Card.Content class="flex flex-col gap-3">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { AlertTriangle, Eye, Globe, Key, type IconProps } from '@lucide/svelte';
|
||||
import { type Component } from 'svelte';
|
||||
import type { Column } from '@tanstack/table-core';
|
||||
import type { RouterTCPTLSConfig } from '$lib/gen/tygo/dynamic';
|
||||
import type { RouterTCPTLSConfig } from '$lib/gen/zen/traefik-schemas';
|
||||
|
||||
type IconComponent = Component<IconProps, Record<string, never>, ''>;
|
||||
type Props = ComponentProps<typeof Badge> & {
|
||||
|
||||
149
web/src/lib/formGenerator.ts
Normal file
149
web/src/lib/formGenerator.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import type { ZodSchema, ZodTypeAny } from "zod";
|
||||
|
||||
export interface FormField {
|
||||
type:
|
||||
| "string"
|
||||
| "number"
|
||||
| "boolean"
|
||||
| "array"
|
||||
| "object"
|
||||
| "record"
|
||||
| "plugin";
|
||||
label: string;
|
||||
optional: boolean;
|
||||
description?: string;
|
||||
arrayItemType?: FormField;
|
||||
nestedSchema?: ZodSchema;
|
||||
recordValueType?: FormField;
|
||||
}
|
||||
|
||||
export function extractSchemaFields(
|
||||
schema: ZodSchema,
|
||||
): Record<string, FormField> {
|
||||
let actualSchema = schema;
|
||||
|
||||
// Unwrap ZodOptional if present
|
||||
if ((schema as any)._def.typeName === "ZodOptional") {
|
||||
actualSchema = (schema as any)._def.innerType;
|
||||
}
|
||||
|
||||
// Handle the case where the entire schema is a ZodRecord (like for plugins)
|
||||
const schemaType = (actualSchema as any)._def.typeName;
|
||||
|
||||
if (schemaType === "ZodRecord") {
|
||||
// For ZodRecord schemas, create a single plugin field
|
||||
return {
|
||||
plugin: {
|
||||
type: "plugin",
|
||||
label: "Plugin Configuration",
|
||||
optional: false,
|
||||
description: "YAML configuration for plugins",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Check if it's a ZodObject
|
||||
if ((actualSchema as any)._def.typeName !== "ZodObject") {
|
||||
console.error(
|
||||
"Expected ZodObject, got:",
|
||||
(actualSchema as any)._def.typeName,
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
const shape = (actualSchema as any)._def.shape();
|
||||
const fields: Record<string, FormField> = {};
|
||||
|
||||
for (const [key, zodType] of Object.entries(shape)) {
|
||||
fields[key] = parseZodType(zodType as ZodTypeAny, key);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
function parseZodType(zodType: ZodTypeAny, key: string): FormField {
|
||||
const def = zodType._def;
|
||||
let type = def.typeName;
|
||||
let optional = false;
|
||||
let currentType = zodType;
|
||||
|
||||
// Handle optional fields
|
||||
if (type === "ZodOptional") {
|
||||
optional = true;
|
||||
currentType = def.innerType;
|
||||
type = currentType._def.typeName;
|
||||
}
|
||||
|
||||
// Special handling for plugin field - handle it as plugin type regardless of Zod type
|
||||
if (key === "plugin") {
|
||||
return {
|
||||
type: "plugin",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: "YAML or JSON configuration for plugins",
|
||||
};
|
||||
}
|
||||
|
||||
// Map Zod types to form field types
|
||||
switch (type) {
|
||||
case "ZodString":
|
||||
return {
|
||||
type: "string",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
};
|
||||
case "ZodNumber":
|
||||
return {
|
||||
type: "number",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
};
|
||||
case "ZodBoolean":
|
||||
return {
|
||||
type: "boolean",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
};
|
||||
case "ZodArray":
|
||||
return {
|
||||
type: "array",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
arrayItemType: parseZodType(currentType._def.type, `${key}Item`),
|
||||
};
|
||||
case "ZodObject":
|
||||
return {
|
||||
type: "object",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
nestedSchema: currentType,
|
||||
};
|
||||
case "ZodRecord":
|
||||
return {
|
||||
type: "record",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
recordValueType: parseZodType(
|
||||
currentType._def.valueType,
|
||||
`${key}Value`,
|
||||
),
|
||||
};
|
||||
default:
|
||||
return {
|
||||
type: "string",
|
||||
label: formatLabel(key),
|
||||
optional,
|
||||
description: def.description,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function formatLabel(key: string): string {
|
||||
return key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase());
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import type { JsonObject, Message } from "@bufbuild/protobuf";
|
||||
* Describes the file mantrae/v1/middleware.proto.
|
||||
*/
|
||||
export const file_mantrae_v1_middleware: GenFile = /*@__PURE__*/
|
||||
fileDesc("ChttYW50cmFlL3YxL21pZGRsZXdhcmUucHJvdG8SCm1hbnRyYWUudjEi/wEKCk1pZGRsZXdhcmUSCgoCaWQYASABKAMSEgoKcHJvZmlsZV9pZBgCIAEoAxIQCghhZ2VudF9pZBgDIAEoCRIMCgRuYW1lGAQgASgJEicKBmNvbmZpZxgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSKAoEdHlwZRgGIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGUSLgoKY3JlYXRlZF9hdBgHIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASLgoKdXBkYXRlZF9hdBgIIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAipgIKBlBsdWdpbhIKCgJpZBgBIAEoCRIMCgRuYW1lGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIOCgZhdXRob3IYBCABKAkSDAoEdHlwZRgFIAEoCRIOCgZpbXBvcnQYBiABKAkSDwoHc3VtbWFyeRgHIAEoCRIQCghpY29uX3VybBgIIAEoCRISCgpiYW5uZXJfdXJsGAkgASgJEg4KBnJlYWRtZRgKIAEoCRIWCg5sYXRlc3RfdmVyc2lvbhgLIAEoCRIQCgh2ZXJzaW9ucxgMIAMoCRINCgVzdGFycxgNIAEoAxIqCgdzbmlwcGV0GA4gASgLMhkubWFudHJhZS52MS5QbHVnaW5TbmlwcGV0EhIKCmNyZWF0ZWRfYXQYDyABKAkiOAoNUGx1Z2luU25pcHBldBILCgNrOHMYASABKAkSDAoEeWFtbBgCIAEoCRIMCgR0b21sGAMgASgJImUKFEdldE1pZGRsZXdhcmVSZXF1ZXN0EhYKAmlkGAEgASgDQgq6SAfIAQEiAiAAEjUKBHR5cGUYAiABKA4yGi5tYW50cmFlLnYxLk1pZGRsZXdhcmVUeXBlQgu6SAjIAQGCAQIQASJDChVHZXRNaWRkbGV3YXJlUmVzcG9uc2USKgoKbWlkZGxld2FyZRgBIAEoCzIWLm1hbnRyYWUudjEuTWlkZGxld2FyZSLFAQoXQ3JlYXRlTWlkZGxld2FyZVJlcXVlc3QSHgoKcHJvZmlsZV9pZBgBIAEoA0IKukgHyAEBIgIgABIQCghhZ2VudF9pZBgCIAEoCRIYCgRuYW1lGAMgASgJQgq6SAfIAQFyAhABEjUKBHR5cGUYBCABKA4yGi5tYW50cmFlLnYxLk1pZGRsZXdhcmVUeXBlQgu6SAjIAQGCAQIQARInCgZjb25maWcYBSABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0IkYKGENyZWF0ZU1pZGRsZXdhcmVSZXNwb25zZRIqCgptaWRkbGV3YXJlGAEgASgLMhYubWFudHJhZS52MS5NaWRkbGV3YXJlIrwBChdVcGRhdGVNaWRkbGV3YXJlUmVxdWVzdBIWCgJpZBgBIAEoA0IKukgHyAEBIgIgABIYCgRuYW1lGAIgASgJQgq6SAfIAQFyAhABEjUKBHR5cGUYAyABKA4yGi5tYW50cmFlLnYxLk1pZGRsZXdhcmVUeXBlQgu6SAjIAQGCAQIQARInCgZjb25maWcYBCABKAsyFy5nb29nbGUucHJvdG9idWYuU3RydWN0Eg8KB2VuYWJsZWQYBSABKAgiRgoYVXBkYXRlTWlkZGxld2FyZVJlc3BvbnNlEioKCm1pZGRsZXdhcmUYASABKAsyFi5tYW50cmFlLnYxLk1pZGRsZXdhcmUiaAoXRGVsZXRlTWlkZGxld2FyZVJlcXVlc3QSFgoCaWQYASABKANCCrpIB8gBASICIAASNQoEdHlwZRgCIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGVCC7pICMgBAYIBAhABIhoKGERlbGV0ZU1pZGRsZXdhcmVSZXNwb25zZSLGAgoWTGlzdE1pZGRsZXdhcmVzUmVxdWVzdBIeCgpwcm9maWxlX2lkGAEgASgDQgq6SAfIAQEiAiAAEh4KCGFnZW50X2lkGAIgASgJQge6SARyAhABSACIAQESNwoEdHlwZRgDIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGVCCLpIBYIBAhABSAGIAQESagoFbGltaXQYBCABKANCVrpIU7oBUAoLbGltaXQudmFsaWQSKWxpbWl0IG11c3QgYmUgZWl0aGVyIC0xIG9yIGdyZWF0ZXIgdGhhbiAwGhZ0aGlzID09IC0xIHx8IHRoaXMgPiAwSAKIAQESHAoGb2Zmc2V0GAUgASgDQge6SAQiAigASAOIAQFCCwoJX2FnZW50X2lkQgcKBV90eXBlQggKBl9saW1pdEIJCgdfb2Zmc2V0IlsKF0xpc3RNaWRkbGV3YXJlc1Jlc3BvbnNlEisKC21pZGRsZXdhcmVzGAEgAygLMhYubWFudHJhZS52MS5NaWRkbGV3YXJlEhMKC3RvdGFsX2NvdW50GAIgASgDIh0KG0dldE1pZGRsZXdhcmVQbHVnaW5zUmVxdWVzdCJDChxHZXRNaWRkbGV3YXJlUGx1Z2luc1Jlc3BvbnNlEiMKB3BsdWdpbnMYASADKAsyEi5tYW50cmFlLnYxLlBsdWdpbipkCg5NaWRkbGV3YXJlVHlwZRIfChtNSURETEVXQVJFX1RZUEVfVU5TUEVDSUZJRUQQABIYChRNSURETEVXQVJFX1RZUEVfSFRUUBABEhcKE01JRERMRVdBUkVfVFlQRV9UQ1AQAjLcBAoRTWlkZGxld2FyZVNlcnZpY2USWQoNR2V0TWlkZGxld2FyZRIgLm1hbnRyYWUudjEuR2V0TWlkZGxld2FyZVJlcXVlc3QaIS5tYW50cmFlLnYxLkdldE1pZGRsZXdhcmVSZXNwb25zZSIDkAIBEl0KEENyZWF0ZU1pZGRsZXdhcmUSIy5tYW50cmFlLnYxLkNyZWF0ZU1pZGRsZXdhcmVSZXF1ZXN0GiQubWFudHJhZS52MS5DcmVhdGVNaWRkbGV3YXJlUmVzcG9uc2USXQoQVXBkYXRlTWlkZGxld2FyZRIjLm1hbnRyYWUudjEuVXBkYXRlTWlkZGxld2FyZVJlcXVlc3QaJC5tYW50cmFlLnYxLlVwZGF0ZU1pZGRsZXdhcmVSZXNwb25zZRJdChBEZWxldGVNaWRkbGV3YXJlEiMubWFudHJhZS52MS5EZWxldGVNaWRkbGV3YXJlUmVxdWVzdBokLm1hbnRyYWUudjEuRGVsZXRlTWlkZGxld2FyZVJlc3BvbnNlEl8KD0xpc3RNaWRkbGV3YXJlcxIiLm1hbnRyYWUudjEuTGlzdE1pZGRsZXdhcmVzUmVxdWVzdBojLm1hbnRyYWUudjEuTGlzdE1pZGRsZXdhcmVzUmVzcG9uc2UiA5ACARJuChRHZXRNaWRkbGV3YXJlUGx1Z2lucxInLm1hbnRyYWUudjEuR2V0TWlkZGxld2FyZVBsdWdpbnNSZXF1ZXN0GigubWFudHJhZS52MS5HZXRNaWRkbGV3YXJlUGx1Z2luc1Jlc3BvbnNlIgOQAgFCqQEKDmNvbS5tYW50cmFlLnYxQg9NaWRkbGV3YXJlUHJvdG9QAVo9Z2l0aHViLmNvbS9taXp1Y2hpbGFicy9tYW50cmFlL3Byb3RvL2dlbi9tYW50cmFlL3YxO21hbnRyYWV2MaICA01YWKoCCk1hbnRyYWUuVjHKAgpNYW50cmFlXFYx4gIWTWFudHJhZVxWMVxHUEJNZXRhZGF0YeoCC01hbnRyYWU6OlYxYgZwcm90bzM", [file_buf_validate_validate, file_google_protobuf_struct, file_google_protobuf_timestamp]);
|
||||
fileDesc("ChttYW50cmFlL3YxL21pZGRsZXdhcmUucHJvdG8SCm1hbnRyYWUudjEikAIKCk1pZGRsZXdhcmUSCgoCaWQYASABKAMSEgoKcHJvZmlsZV9pZBgCIAEoAxIQCghhZ2VudF9pZBgDIAEoCRIMCgRuYW1lGAQgASgJEicKBmNvbmZpZxgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSDwoHZW5hYmxlZBgGIAEoCBIoCgR0eXBlGAcgASgOMhoubWFudHJhZS52MS5NaWRkbGV3YXJlVHlwZRIuCgpjcmVhdGVkX2F0GAggASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgp1cGRhdGVkX2F0GAkgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcCKmAgoGUGx1Z2luEgoKAmlkGAEgASgJEgwKBG5hbWUYAiABKAkSFAoMZGlzcGxheV9uYW1lGAMgASgJEg4KBmF1dGhvchgEIAEoCRIMCgR0eXBlGAUgASgJEg4KBmltcG9ydBgGIAEoCRIPCgdzdW1tYXJ5GAcgASgJEhAKCGljb25fdXJsGAggASgJEhIKCmJhbm5lcl91cmwYCSABKAkSDgoGcmVhZG1lGAogASgJEhYKDmxhdGVzdF92ZXJzaW9uGAsgASgJEhAKCHZlcnNpb25zGAwgAygJEg0KBXN0YXJzGA0gASgDEioKB3NuaXBwZXQYDiABKAsyGS5tYW50cmFlLnYxLlBsdWdpblNuaXBwZXQSEgoKY3JlYXRlZF9hdBgPIAEoCSI4Cg1QbHVnaW5TbmlwcGV0EgsKA2s4cxgBIAEoCRIMCgR5YW1sGAIgASgJEgwKBHRvbWwYAyABKAkiZQoUR2V0TWlkZGxld2FyZVJlcXVlc3QSFgoCaWQYASABKANCCrpIB8gBASICIAASNQoEdHlwZRgCIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGVCC7pICMgBAYIBAhABIkMKFUdldE1pZGRsZXdhcmVSZXNwb25zZRIqCgptaWRkbGV3YXJlGAEgASgLMhYubWFudHJhZS52MS5NaWRkbGV3YXJlIsUBChdDcmVhdGVNaWRkbGV3YXJlUmVxdWVzdBIeCgpwcm9maWxlX2lkGAEgASgDQgq6SAfIAQEiAiAAEhAKCGFnZW50X2lkGAIgASgJEhgKBG5hbWUYAyABKAlCCrpIB8gBAXICEAESNQoEdHlwZRgEIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGVCC7pICMgBAYIBAhABEicKBmNvbmZpZxgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QiRgoYQ3JlYXRlTWlkZGxld2FyZVJlc3BvbnNlEioKCm1pZGRsZXdhcmUYASABKAsyFi5tYW50cmFlLnYxLk1pZGRsZXdhcmUivAEKF1VwZGF0ZU1pZGRsZXdhcmVSZXF1ZXN0EhYKAmlkGAEgASgDQgq6SAfIAQEiAiAAEhgKBG5hbWUYAiABKAlCCrpIB8gBAXICEAESNQoEdHlwZRgDIAEoDjIaLm1hbnRyYWUudjEuTWlkZGxld2FyZVR5cGVCC7pICMgBAYIBAhABEicKBmNvbmZpZxgEIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3QSDwoHZW5hYmxlZBgFIAEoCCJGChhVcGRhdGVNaWRkbGV3YXJlUmVzcG9uc2USKgoKbWlkZGxld2FyZRgBIAEoCzIWLm1hbnRyYWUudjEuTWlkZGxld2FyZSJoChdEZWxldGVNaWRkbGV3YXJlUmVxdWVzdBIWCgJpZBgBIAEoA0IKukgHyAEBIgIgABI1CgR0eXBlGAIgASgOMhoubWFudHJhZS52MS5NaWRkbGV3YXJlVHlwZUILukgIyAEBggECEAEiGgoYRGVsZXRlTWlkZGxld2FyZVJlc3BvbnNlIsYCChZMaXN0TWlkZGxld2FyZXNSZXF1ZXN0Eh4KCnByb2ZpbGVfaWQYASABKANCCrpIB8gBASICIAASHgoIYWdlbnRfaWQYAiABKAlCB7pIBHICEAFIAIgBARI3CgR0eXBlGAMgASgOMhoubWFudHJhZS52MS5NaWRkbGV3YXJlVHlwZUIIukgFggECEAFIAYgBARJqCgVsaW1pdBgEIAEoA0JWukhTugFQCgtsaW1pdC52YWxpZBIpbGltaXQgbXVzdCBiZSBlaXRoZXIgLTEgb3IgZ3JlYXRlciB0aGFuIDAaFnRoaXMgPT0gLTEgfHwgdGhpcyA+IDBIAogBARIcCgZvZmZzZXQYBSABKANCB7pIBCICKABIA4gBAUILCglfYWdlbnRfaWRCBwoFX3R5cGVCCAoGX2xpbWl0QgkKB19vZmZzZXQiWwoXTGlzdE1pZGRsZXdhcmVzUmVzcG9uc2USKwoLbWlkZGxld2FyZXMYASADKAsyFi5tYW50cmFlLnYxLk1pZGRsZXdhcmUSEwoLdG90YWxfY291bnQYAiABKAMiHQobR2V0TWlkZGxld2FyZVBsdWdpbnNSZXF1ZXN0IkMKHEdldE1pZGRsZXdhcmVQbHVnaW5zUmVzcG9uc2USIwoHcGx1Z2lucxgBIAMoCzISLm1hbnRyYWUudjEuUGx1Z2luKmQKDk1pZGRsZXdhcmVUeXBlEh8KG01JRERMRVdBUkVfVFlQRV9VTlNQRUNJRklFRBAAEhgKFE1JRERMRVdBUkVfVFlQRV9IVFRQEAESFwoTTUlERExFV0FSRV9UWVBFX1RDUBACMtwEChFNaWRkbGV3YXJlU2VydmljZRJZCg1HZXRNaWRkbGV3YXJlEiAubWFudHJhZS52MS5HZXRNaWRkbGV3YXJlUmVxdWVzdBohLm1hbnRyYWUudjEuR2V0TWlkZGxld2FyZVJlc3BvbnNlIgOQAgESXQoQQ3JlYXRlTWlkZGxld2FyZRIjLm1hbnRyYWUudjEuQ3JlYXRlTWlkZGxld2FyZVJlcXVlc3QaJC5tYW50cmFlLnYxLkNyZWF0ZU1pZGRsZXdhcmVSZXNwb25zZRJdChBVcGRhdGVNaWRkbGV3YXJlEiMubWFudHJhZS52MS5VcGRhdGVNaWRkbGV3YXJlUmVxdWVzdBokLm1hbnRyYWUudjEuVXBkYXRlTWlkZGxld2FyZVJlc3BvbnNlEl0KEERlbGV0ZU1pZGRsZXdhcmUSIy5tYW50cmFlLnYxLkRlbGV0ZU1pZGRsZXdhcmVSZXF1ZXN0GiQubWFudHJhZS52MS5EZWxldGVNaWRkbGV3YXJlUmVzcG9uc2USXwoPTGlzdE1pZGRsZXdhcmVzEiIubWFudHJhZS52MS5MaXN0TWlkZGxld2FyZXNSZXF1ZXN0GiMubWFudHJhZS52MS5MaXN0TWlkZGxld2FyZXNSZXNwb25zZSIDkAIBEm4KFEdldE1pZGRsZXdhcmVQbHVnaW5zEicubWFudHJhZS52MS5HZXRNaWRkbGV3YXJlUGx1Z2luc1JlcXVlc3QaKC5tYW50cmFlLnYxLkdldE1pZGRsZXdhcmVQbHVnaW5zUmVzcG9uc2UiA5ACAUKpAQoOY29tLm1hbnRyYWUudjFCD01pZGRsZXdhcmVQcm90b1ABWj1naXRodWIuY29tL21penVjaGlsYWJzL21hbnRyYWUvcHJvdG8vZ2VuL21hbnRyYWUvdjE7bWFudHJhZXYxogIDTVhYqgIKTWFudHJhZS5WMcoCCk1hbnRyYWVcVjHiAhZNYW50cmFlXFYxXEdQQk1ldGFkYXRh6gILTWFudHJhZTo6VjFiBnByb3RvMw", [file_buf_validate_validate, file_google_protobuf_struct, file_google_protobuf_timestamp]);
|
||||
|
||||
/**
|
||||
* @generated from message mantrae.v1.Middleware
|
||||
@@ -45,17 +45,22 @@ export type Middleware = Message<"mantrae.v1.Middleware"> & {
|
||||
config?: JsonObject;
|
||||
|
||||
/**
|
||||
* @generated from field: mantrae.v1.MiddlewareType type = 6;
|
||||
* @generated from field: bool enabled = 6;
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* @generated from field: mantrae.v1.MiddlewareType type = 7;
|
||||
*/
|
||||
type: MiddlewareType;
|
||||
|
||||
/**
|
||||
* @generated from field: google.protobuf.Timestamp created_at = 7;
|
||||
* @generated from field: google.protobuf.Timestamp created_at = 8;
|
||||
*/
|
||||
createdAt?: Timestamp;
|
||||
|
||||
/**
|
||||
* @generated from field: google.protobuf.Timestamp updated_at = 8;
|
||||
* @generated from field: google.protobuf.Timestamp updated_at = 9;
|
||||
*/
|
||||
updatedAt?: Timestamp;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
// Code generated by tygo. DO NOT EDIT.
|
||||
|
||||
import type { Domain } from '../types';
|
||||
|
||||
//////////
|
||||
// source: certificate.go
|
||||
|
||||
/**
|
||||
* Certificates defines traefik certificates type
|
||||
* Certs and Keys could be either a file path, or the file content itself.
|
||||
*/
|
||||
export type Certificates = Certificate[];
|
||||
/**
|
||||
* Certificate holds a SSL cert/key pair
|
||||
* Certs and Key could be either a file path, or the file content itself.
|
||||
*/
|
||||
export interface Certificate {
|
||||
certFile?: any /* types.FileOrContent */;
|
||||
keyFile?: any /* types.FileOrContent */;
|
||||
}
|
||||
/**
|
||||
* FileOrContent hold a file path or content.
|
||||
*/
|
||||
export type FileOrContent = string;
|
||||
|
||||
//////////
|
||||
// source: certificate_store.go
|
||||
|
||||
/**
|
||||
* CertificateStore store for dynamic certificates.
|
||||
*/
|
||||
export interface CertificateStore {
|
||||
DynamicCerts?: any /* safe.Safe */;
|
||||
DefaultCertificate?: any /* tls.Certificate */;
|
||||
CertCache?: any /* cache.Cache */;
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: tls.go
|
||||
|
||||
/**
|
||||
* ClientAuth defines the parameters of the client authentication part of the TLS connection, if any.
|
||||
*/
|
||||
export interface ClientAuth {
|
||||
caFiles?: any /* types.FileOrContent */[];
|
||||
/**
|
||||
* ClientAuthType defines the client authentication type to apply.
|
||||
* The available values are: "NoClientCert", "RequestClientCert", "VerifyClientCertIfGiven" and "RequireAndVerifyClientCert".
|
||||
*/
|
||||
clientAuthType?: string;
|
||||
}
|
||||
/**
|
||||
* Options configures TLS for an entry point.
|
||||
*/
|
||||
export interface Options {
|
||||
minVersion?: string;
|
||||
maxVersion?: string;
|
||||
cipherSuites?: string[];
|
||||
curvePreferences?: string[];
|
||||
clientAuth?: ClientAuth;
|
||||
sniStrict?: boolean;
|
||||
alpnProtocols?: string[];
|
||||
disableSessionTickets?: boolean;
|
||||
/**
|
||||
* Deprecated: https://github.com/golang/go/issues/45430
|
||||
*/
|
||||
preferServerCipherSuites?: boolean;
|
||||
}
|
||||
/**
|
||||
* Store holds the options for a given Store.
|
||||
*/
|
||||
export interface Store {
|
||||
defaultCertificate?: Certificate;
|
||||
defaultGeneratedCert?: GeneratedCert;
|
||||
}
|
||||
/**
|
||||
* GeneratedCert defines the default generated certificate configuration.
|
||||
*/
|
||||
export interface GeneratedCert {
|
||||
/**
|
||||
* Resolver is the name of the resolver that will be used to issue the DefaultCertificate.
|
||||
*/
|
||||
resolver?: string;
|
||||
/**
|
||||
* Domain is the domain definition for the DefaultCertificate.
|
||||
*/
|
||||
domain?: Domain;
|
||||
}
|
||||
/**
|
||||
* CertAndStores allows mapping a TLS certificate to a list of entry points.
|
||||
*/
|
||||
export interface CertAndStores {
|
||||
Certificate: Certificate;
|
||||
stores?: string[];
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: tlsmanager.go
|
||||
|
||||
/**
|
||||
* DefaultTLSConfigName is the name of the default set of options for configuring TLS.
|
||||
*/
|
||||
export const DefaultTLSConfigName = 'default';
|
||||
/**
|
||||
* DefaultTLSStoreName is the name of the default store of TLS certificates.
|
||||
* Note that it actually is the only usable one for now.
|
||||
*/
|
||||
export const DefaultTLSStoreName = 'default';
|
||||
/**
|
||||
* Manager is the TLS option/store/configuration factory.
|
||||
*/
|
||||
export interface Manager {}
|
||||
@@ -1,264 +0,0 @@
|
||||
// Code generated by tygo. DO NOT EDIT.
|
||||
|
||||
//////////
|
||||
// source: domains.go
|
||||
|
||||
/**
|
||||
* Domain holds a domain name with SANs.
|
||||
*/
|
||||
export interface Domain {
|
||||
/**
|
||||
* Main defines the main domain name.
|
||||
*/
|
||||
main?: string;
|
||||
/**
|
||||
* SANs defines the subject alternative domain names.
|
||||
*/
|
||||
sans?: string[];
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: file_or_content.go
|
||||
|
||||
/**
|
||||
* FileOrContent holds a file path or content.
|
||||
*/
|
||||
export type FileOrContent = string;
|
||||
|
||||
//////////
|
||||
// source: host_resolver.go
|
||||
|
||||
/**
|
||||
* HostResolverConfig contain configuration for CNAME Flattening.
|
||||
*/
|
||||
export interface HostResolverConfig {
|
||||
cnameFlattening?: boolean;
|
||||
resolvConfig?: string;
|
||||
resolvDepth?: number /* int */;
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: http_code_range.go
|
||||
|
||||
/**
|
||||
* HTTPCodeRanges holds HTTP code ranges.
|
||||
*/
|
||||
export type HTTPCodeRanges = number /* int */[][];
|
||||
|
||||
//////////
|
||||
// source: logs.go
|
||||
|
||||
/**
|
||||
* AccessLogKeep is the keep string value.
|
||||
*/
|
||||
export const AccessLogKeep = "keep";
|
||||
/**
|
||||
* AccessLogDrop is the drop string value.
|
||||
*/
|
||||
export const AccessLogDrop = "drop";
|
||||
/**
|
||||
* AccessLogRedact is the redact string value.
|
||||
*/
|
||||
export const AccessLogRedact = "redact";
|
||||
/**
|
||||
* CommonFormat is the common logging format (CLF).
|
||||
*/
|
||||
export const CommonFormat: string = "common";
|
||||
export const OTelTraefikServiceName = "traefik";
|
||||
/**
|
||||
* TraefikLog holds the configuration settings for the traefik logger.
|
||||
*/
|
||||
export interface TraefikLog {
|
||||
level?: string;
|
||||
format?: string;
|
||||
noColor?: boolean;
|
||||
filePath?: string;
|
||||
maxSize?: number /* int */;
|
||||
maxAge?: number /* int */;
|
||||
maxBackups?: number /* int */;
|
||||
compress?: boolean;
|
||||
otlp?: OTelLog;
|
||||
}
|
||||
/**
|
||||
* AccessLog holds the configuration settings for the access logger (middlewares/accesslog).
|
||||
*/
|
||||
export interface AccessLog {
|
||||
filePath?: string;
|
||||
format?: string;
|
||||
filters?: AccessLogFilters;
|
||||
fields?: AccessLogFields;
|
||||
bufferingSize?: number /* int64 */;
|
||||
addInternals?: boolean;
|
||||
otlp?: OTelLog;
|
||||
}
|
||||
/**
|
||||
* AccessLogFilters holds filters configuration.
|
||||
*/
|
||||
export interface AccessLogFilters {
|
||||
statusCodes?: string[];
|
||||
retryAttempts?: boolean;
|
||||
minDuration?: any /* types.Duration */;
|
||||
}
|
||||
/**
|
||||
* FieldHeaders holds configuration for access log headers.
|
||||
*/
|
||||
export interface FieldHeaders {
|
||||
defaultMode?: string;
|
||||
names?: { [key: string]: string};
|
||||
}
|
||||
/**
|
||||
* AccessLogFields holds configuration for access log fields.
|
||||
*/
|
||||
export interface AccessLogFields {
|
||||
defaultMode?: string;
|
||||
names?: { [key: string]: string};
|
||||
headers?: FieldHeaders;
|
||||
}
|
||||
/**
|
||||
* OTelLog provides configuration settings for the open-telemetry logger.
|
||||
*/
|
||||
export interface OTelLog {
|
||||
serviceName?: string;
|
||||
resourceAttributes?: { [key: string]: string};
|
||||
grpc?: OTelGRPC;
|
||||
http?: OTelHTTP;
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: metrics.go
|
||||
|
||||
/**
|
||||
* Metrics provides options to expose and send Traefik metrics to different third party monitoring systems.
|
||||
*/
|
||||
export interface Metrics {
|
||||
addInternals?: boolean;
|
||||
prometheus?: Prometheus;
|
||||
datadog?: Datadog;
|
||||
statsD?: Statsd;
|
||||
influxDB2?: InfluxDB2;
|
||||
otlp?: OTLP;
|
||||
}
|
||||
/**
|
||||
* Prometheus can contain specific configuration used by the Prometheus Metrics exporter.
|
||||
*/
|
||||
export interface Prometheus {
|
||||
buckets?: number /* float64 */[];
|
||||
addEntryPointsLabels?: boolean;
|
||||
addRoutersLabels?: boolean;
|
||||
addServicesLabels?: boolean;
|
||||
entryPoint?: string;
|
||||
manualRouting?: boolean;
|
||||
headerLabels?: { [key: string]: string};
|
||||
}
|
||||
/**
|
||||
* Datadog contains address and metrics pushing interval configuration.
|
||||
*/
|
||||
export interface Datadog {
|
||||
address?: string;
|
||||
pushInterval?: any /* types.Duration */;
|
||||
addEntryPointsLabels?: boolean;
|
||||
addRoutersLabels?: boolean;
|
||||
addServicesLabels?: boolean;
|
||||
prefix?: string;
|
||||
}
|
||||
/**
|
||||
* Statsd contains address and metrics pushing interval configuration.
|
||||
*/
|
||||
export interface Statsd {
|
||||
address?: string;
|
||||
pushInterval?: any /* types.Duration */;
|
||||
addEntryPointsLabels?: boolean;
|
||||
addRoutersLabels?: boolean;
|
||||
addServicesLabels?: boolean;
|
||||
prefix?: string;
|
||||
}
|
||||
/**
|
||||
* InfluxDB2 contains address, token and metrics pushing interval configuration.
|
||||
*/
|
||||
export interface InfluxDB2 {
|
||||
address?: string;
|
||||
token?: string;
|
||||
pushInterval?: any /* types.Duration */;
|
||||
org?: string;
|
||||
bucket?: string;
|
||||
addEntryPointsLabels?: boolean;
|
||||
addRoutersLabels?: boolean;
|
||||
addServicesLabels?: boolean;
|
||||
additionalLabels?: { [key: string]: string};
|
||||
}
|
||||
/**
|
||||
* OTLP contains specific configuration used by the OpenTelemetry Metrics exporter.
|
||||
*/
|
||||
export interface OTLP {
|
||||
grpc?: OTelGRPC;
|
||||
http?: OTelHTTP;
|
||||
addEntryPointsLabels?: boolean;
|
||||
addRoutersLabels?: boolean;
|
||||
addServicesLabels?: boolean;
|
||||
explicitBoundaries?: number /* float64 */[];
|
||||
pushInterval?: any /* types.Duration */;
|
||||
serviceName?: string;
|
||||
}
|
||||
/**
|
||||
* Statistics provides options for monitoring request and response stats.
|
||||
*/
|
||||
export interface Statistics {
|
||||
recentErrors?: number /* int */;
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: otel.go
|
||||
|
||||
/**
|
||||
* OTelGRPC provides configuration settings for the gRPC open-telemetry.
|
||||
*/
|
||||
export interface OTelGRPC {
|
||||
endpoint?: string;
|
||||
insecure?: boolean;
|
||||
tls?: ClientTLS;
|
||||
headers?: { [key: string]: string};
|
||||
}
|
||||
/**
|
||||
* OTelHTTP provides configuration settings for the HTTP open-telemetry.
|
||||
*/
|
||||
export interface OTelHTTP {
|
||||
endpoint?: string;
|
||||
tls?: ClientTLS;
|
||||
headers?: { [key: string]: string};
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: route_appender.go
|
||||
|
||||
/**
|
||||
* RouteAppender appends routes on a router (/api, /ping ...).
|
||||
*/
|
||||
export type RouteAppender = any;
|
||||
|
||||
//////////
|
||||
// source: tls.go
|
||||
|
||||
/**
|
||||
* ClientTLS holds TLS specific configurations as client
|
||||
* CA, Cert and Key can be either path or file contents.
|
||||
*/
|
||||
export interface ClientTLS {
|
||||
ca?: string;
|
||||
cert?: string;
|
||||
key?: string;
|
||||
insecureSkipVerify?: boolean;
|
||||
}
|
||||
|
||||
//////////
|
||||
// source: tracing.go
|
||||
|
||||
/**
|
||||
* OTelTracing provides configuration settings for the open-telemetry tracer.
|
||||
*/
|
||||
export interface OTelTracing {
|
||||
grpc?: OTelGRPC;
|
||||
http?: OTelHTTP;
|
||||
}
|
||||
/**
|
||||
* tpCloser converts a TraceProvider into an io.Closer.
|
||||
*/
|
||||
588
web/src/lib/gen/zen/traefik-schemas.ts
Normal file
588
web/src/lib/gen/zen/traefik-schemas.ts
Normal file
@@ -0,0 +1,588 @@
|
||||
// This file is auto-generated via `zen.StructToZodSchema`.
|
||||
// Do not edit manually.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
export const CookieSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
secure: z.boolean().optional(),
|
||||
httpOnly: z.boolean().optional(),
|
||||
sameSite: z.string().optional(),
|
||||
maxAge: z.number().optional(),
|
||||
path: z.string().optional(),
|
||||
domain: z.string().optional(),
|
||||
});
|
||||
export type Cookie = z.infer<typeof CookieSchema>;
|
||||
|
||||
export const StickySchema = z.object({
|
||||
cookie: CookieSchema.optional(),
|
||||
});
|
||||
export type Sticky = z.infer<typeof StickySchema>;
|
||||
|
||||
export const ServerSchema = z.object({
|
||||
url: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
preservePath: z.boolean().optional(),
|
||||
fenced: z.boolean().optional(),
|
||||
});
|
||||
export type Server = z.infer<typeof ServerSchema>;
|
||||
|
||||
export const ServerHealthCheckSchema = z.object({
|
||||
scheme: z.string().optional(),
|
||||
mode: z.string().optional(),
|
||||
path: z.string().optional(),
|
||||
method: z.string().optional(),
|
||||
status: z.number().optional(),
|
||||
port: z.number().optional(),
|
||||
interval: z.number().optional(),
|
||||
timeout: z.number().optional(),
|
||||
hostname: z.string().optional(),
|
||||
followRedirects: z.boolean().optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
});
|
||||
export type ServerHealthCheck = z.infer<typeof ServerHealthCheckSchema>;
|
||||
|
||||
export const ResponseForwardingSchema = z.object({
|
||||
flushInterval: z.number().optional(),
|
||||
});
|
||||
export type ResponseForwarding = z.infer<typeof ResponseForwardingSchema>;
|
||||
|
||||
export const ServersLoadBalancerSchema = z.object({
|
||||
sticky: StickySchema.optional(),
|
||||
servers: ServerSchema.array().optional(),
|
||||
strategy: z.string().optional(),
|
||||
healthCheck: ServerHealthCheckSchema.optional(),
|
||||
passHostHeader: z.boolean().nullable(),
|
||||
responseForwarding: ResponseForwardingSchema.optional(),
|
||||
serversTransport: z.string().optional(),
|
||||
});
|
||||
export type ServersLoadBalancer = z.infer<typeof ServersLoadBalancerSchema>;
|
||||
|
||||
export const WRRServiceSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
});
|
||||
export type WRRService = z.infer<typeof WRRServiceSchema>;
|
||||
|
||||
export const HealthCheckSchema = z.object({});
|
||||
export type HealthCheck = z.infer<typeof HealthCheckSchema>;
|
||||
|
||||
export const WeightedRoundRobinSchema = z.object({
|
||||
services: WRRServiceSchema.array().optional(),
|
||||
sticky: StickySchema.optional(),
|
||||
healthCheck: HealthCheckSchema.optional(),
|
||||
});
|
||||
export type WeightedRoundRobin = z.infer<typeof WeightedRoundRobinSchema>;
|
||||
|
||||
export const MirrorServiceSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
percent: z.number().optional(),
|
||||
});
|
||||
export type MirrorService = z.infer<typeof MirrorServiceSchema>;
|
||||
|
||||
export const MirroringSchema = z.object({
|
||||
service: z.string().optional(),
|
||||
mirrorBody: z.boolean().optional(),
|
||||
maxBodySize: z.number().optional(),
|
||||
mirrors: MirrorServiceSchema.array().optional(),
|
||||
healthCheck: HealthCheckSchema.optional(),
|
||||
});
|
||||
export type Mirroring = z.infer<typeof MirroringSchema>;
|
||||
|
||||
export const FailoverSchema = z.object({
|
||||
service: z.string().optional(),
|
||||
fallback: z.string().optional(),
|
||||
healthCheck: HealthCheckSchema.optional(),
|
||||
});
|
||||
export type Failover = z.infer<typeof FailoverSchema>;
|
||||
|
||||
export const ServiceSchema = z.object({
|
||||
loadBalancer: ServersLoadBalancerSchema.optional(),
|
||||
weighted: WeightedRoundRobinSchema.optional(),
|
||||
mirroring: MirroringSchema.optional(),
|
||||
failover: FailoverSchema.optional(),
|
||||
});
|
||||
export type Service = z.infer<typeof ServiceSchema>;
|
||||
|
||||
export const ProxyProtocolSchema = z.object({
|
||||
version: z.number().optional(),
|
||||
});
|
||||
export type ProxyProtocol = z.infer<typeof ProxyProtocolSchema>;
|
||||
|
||||
export const TCPServerSchema = z.object({
|
||||
address: z.string().optional(),
|
||||
tls: z.boolean().optional(),
|
||||
});
|
||||
export type TCPServer = z.infer<typeof TCPServerSchema>;
|
||||
|
||||
export const TCPServersLoadBalancerSchema = z.object({
|
||||
proxyProtocol: ProxyProtocolSchema.optional(),
|
||||
servers: TCPServerSchema.array().optional(),
|
||||
serversTransport: z.string().optional(),
|
||||
terminationDelay: z.number().optional(),
|
||||
});
|
||||
export type TCPServersLoadBalancer = z.infer<
|
||||
typeof TCPServersLoadBalancerSchema
|
||||
>;
|
||||
|
||||
export const TCPWRRServiceSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
});
|
||||
export type TCPWRRService = z.infer<typeof TCPWRRServiceSchema>;
|
||||
|
||||
export const TCPWeightedRoundRobinSchema = z.object({
|
||||
services: TCPWRRServiceSchema.array().optional(),
|
||||
});
|
||||
export type TCPWeightedRoundRobin = z.infer<typeof TCPWeightedRoundRobinSchema>;
|
||||
|
||||
export const TCPServiceSchema = z.object({
|
||||
loadBalancer: TCPServersLoadBalancerSchema.optional(),
|
||||
weighted: TCPWeightedRoundRobinSchema.optional(),
|
||||
});
|
||||
export type TCPService = z.infer<typeof TCPServiceSchema>;
|
||||
|
||||
export const UDPServerSchema = z.object({
|
||||
address: z.string().optional(),
|
||||
});
|
||||
export type UDPServer = z.infer<typeof UDPServerSchema>;
|
||||
|
||||
export const UDPServersLoadBalancerSchema = z.object({
|
||||
servers: UDPServerSchema.array().optional(),
|
||||
});
|
||||
export type UDPServersLoadBalancer = z.infer<
|
||||
typeof UDPServersLoadBalancerSchema
|
||||
>;
|
||||
|
||||
export const UDPWRRServiceSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
weight: z.number().optional(),
|
||||
});
|
||||
export type UDPWRRService = z.infer<typeof UDPWRRServiceSchema>;
|
||||
|
||||
export const UDPWeightedRoundRobinSchema = z.object({
|
||||
services: UDPWRRServiceSchema.array().optional(),
|
||||
});
|
||||
export type UDPWeightedRoundRobin = z.infer<typeof UDPWeightedRoundRobinSchema>;
|
||||
|
||||
export const UDPServiceSchema = z.object({
|
||||
loadBalancer: UDPServersLoadBalancerSchema.optional(),
|
||||
weighted: UDPWeightedRoundRobinSchema.optional(),
|
||||
});
|
||||
export type UDPService = z.infer<typeof UDPServiceSchema>;
|
||||
|
||||
export const AddPrefixSchema = z.object({
|
||||
prefix: z.string().optional(),
|
||||
});
|
||||
export type AddPrefix = z.infer<typeof AddPrefixSchema>;
|
||||
|
||||
export const StripPrefixSchema = z.object({
|
||||
prefixes: z.string().array().optional(),
|
||||
forceSlash: z.boolean().optional(),
|
||||
});
|
||||
export type StripPrefix = z.infer<typeof StripPrefixSchema>;
|
||||
|
||||
export const StripPrefixRegexSchema = z.object({
|
||||
regex: z.string().array().optional(),
|
||||
});
|
||||
export type StripPrefixRegex = z.infer<typeof StripPrefixRegexSchema>;
|
||||
|
||||
export const ReplacePathSchema = z.object({
|
||||
path: z.string().optional(),
|
||||
});
|
||||
export type ReplacePath = z.infer<typeof ReplacePathSchema>;
|
||||
|
||||
export const ReplacePathRegexSchema = z.object({
|
||||
regex: z.string().optional(),
|
||||
replacement: z.string().optional(),
|
||||
});
|
||||
export type ReplacePathRegex = z.infer<typeof ReplacePathRegexSchema>;
|
||||
|
||||
export const ChainSchema = z.object({
|
||||
middlewares: z.string().array().optional(),
|
||||
});
|
||||
export type Chain = z.infer<typeof ChainSchema>;
|
||||
|
||||
export const IPStrategySchema = z.object({
|
||||
depth: z.number().optional(),
|
||||
excludedIPs: z.string().array().optional(),
|
||||
ipv6Subnet: z.number().optional(),
|
||||
});
|
||||
export type IPStrategy = z.infer<typeof IPStrategySchema>;
|
||||
|
||||
export const IPWhiteListSchema = z.object({
|
||||
sourceRange: z.string().array().optional(),
|
||||
ipStrategy: IPStrategySchema.optional(),
|
||||
});
|
||||
export type IPWhiteList = z.infer<typeof IPWhiteListSchema>;
|
||||
|
||||
export const IPAllowListSchema = z.object({
|
||||
sourceRange: z.string().array().optional(),
|
||||
ipStrategy: IPStrategySchema.optional(),
|
||||
rejectStatusCode: z.number().optional(),
|
||||
});
|
||||
export type IPAllowList = z.infer<typeof IPAllowListSchema>;
|
||||
|
||||
export const HeadersSchema = z.object({
|
||||
customRequestHeaders: z.record(z.string(), z.string()).optional(),
|
||||
customResponseHeaders: z.record(z.string(), z.string()).optional(),
|
||||
accessControlAllowCredentials: z.boolean().optional(),
|
||||
accessControlAllowHeaders: z.string().array().optional(),
|
||||
accessControlAllowMethods: z.string().array().optional(),
|
||||
accessControlAllowOriginList: z.string().array().optional(),
|
||||
accessControlAllowOriginListRegex: z.string().array().optional(),
|
||||
accessControlExposeHeaders: z.string().array().optional(),
|
||||
accessControlMaxAge: z.number().optional(),
|
||||
addVaryHeader: z.boolean().optional(),
|
||||
allowedHosts: z.string().array().optional(),
|
||||
hostsProxyHeaders: z.string().array().optional(),
|
||||
sslProxyHeaders: z.record(z.string(), z.string()).optional(),
|
||||
stsSeconds: z.number().optional(),
|
||||
stsIncludeSubdomains: z.boolean().optional(),
|
||||
stsPreload: z.boolean().optional(),
|
||||
forceSTSHeader: z.boolean().optional(),
|
||||
frameDeny: z.boolean().optional(),
|
||||
customFrameOptionsValue: z.string().optional(),
|
||||
contentTypeNosniff: z.boolean().optional(),
|
||||
browserXssFilter: z.boolean().optional(),
|
||||
customBrowserXSSValue: z.string().optional(),
|
||||
contentSecurityPolicy: z.string().optional(),
|
||||
contentSecurityPolicyReportOnly: z.string().optional(),
|
||||
publicKey: z.string().optional(),
|
||||
referrerPolicy: z.string().optional(),
|
||||
permissionsPolicy: z.string().optional(),
|
||||
isDevelopment: z.boolean().optional(),
|
||||
featurePolicy: z.string().optional(),
|
||||
sslRedirect: z.boolean().optional(),
|
||||
sslTemporaryRedirect: z.boolean().optional(),
|
||||
sslHost: z.string().optional(),
|
||||
sslForceHost: z.boolean().optional(),
|
||||
});
|
||||
export type Headers = z.infer<typeof HeadersSchema>;
|
||||
|
||||
export const ErrorPageSchema = z.object({
|
||||
status: z.string().array().optional(),
|
||||
statusRewrites: z.record(z.string(), z.number()).optional(),
|
||||
service: z.string().optional(),
|
||||
query: z.string().optional(),
|
||||
});
|
||||
export type ErrorPage = z.infer<typeof ErrorPageSchema>;
|
||||
|
||||
export const SourceCriterionSchema = z.object({
|
||||
ipStrategy: IPStrategySchema.optional(),
|
||||
requestHeaderName: z.string().optional(),
|
||||
requestHost: z.boolean().optional(),
|
||||
});
|
||||
export type SourceCriterion = z.infer<typeof SourceCriterionSchema>;
|
||||
|
||||
export const ClientTLSSchema = z.object({
|
||||
ca: z.string().optional(),
|
||||
cert: z.string().optional(),
|
||||
key: z.string().optional(),
|
||||
insecureSkipVerify: z.boolean().optional(),
|
||||
});
|
||||
export type ClientTLS = z.infer<typeof ClientTLSSchema>;
|
||||
|
||||
export const RedisSchema = z.object({
|
||||
endpoints: z.string().array().optional(),
|
||||
tls: ClientTLSSchema.optional(),
|
||||
username: z.string().optional(),
|
||||
password: z.string().optional(),
|
||||
db: z.number().optional(),
|
||||
poolSize: z.number().optional(),
|
||||
minIdleConns: z.number().optional(),
|
||||
maxActiveConns: z.number().optional(),
|
||||
readTimeout: z.number().optional(),
|
||||
writeTimeout: z.number().optional(),
|
||||
dialTimeout: z.number().optional(),
|
||||
});
|
||||
export type Redis = z.infer<typeof RedisSchema>;
|
||||
|
||||
export const RateLimitSchema = z.object({
|
||||
average: z.number().optional(),
|
||||
period: z.number().optional(),
|
||||
burst: z.number().optional(),
|
||||
sourceCriterion: SourceCriterionSchema.optional(),
|
||||
redis: RedisSchema.optional(),
|
||||
});
|
||||
export type RateLimit = z.infer<typeof RateLimitSchema>;
|
||||
|
||||
export const RedirectRegexSchema = z.object({
|
||||
regex: z.string().optional(),
|
||||
replacement: z.string().optional(),
|
||||
permanent: z.boolean().optional(),
|
||||
});
|
||||
export type RedirectRegex = z.infer<typeof RedirectRegexSchema>;
|
||||
|
||||
export const RedirectSchemeSchema = z.object({
|
||||
scheme: z.string().optional(),
|
||||
port: z.string().optional(),
|
||||
permanent: z.boolean().optional(),
|
||||
});
|
||||
export type RedirectScheme = z.infer<typeof RedirectSchemeSchema>;
|
||||
|
||||
export const BasicAuthSchema = z.object({
|
||||
users: z.string().array().optional(),
|
||||
usersFile: z.string().optional(),
|
||||
realm: z.string().optional(),
|
||||
removeHeader: z.boolean().optional(),
|
||||
headerField: z.string().optional(),
|
||||
});
|
||||
export type BasicAuth = z.infer<typeof BasicAuthSchema>;
|
||||
|
||||
export const DigestAuthSchema = z.object({
|
||||
users: z.string().array().optional(),
|
||||
usersFile: z.string().optional(),
|
||||
removeHeader: z.boolean().optional(),
|
||||
realm: z.string().optional(),
|
||||
headerField: z.string().optional(),
|
||||
});
|
||||
export type DigestAuth = z.infer<typeof DigestAuthSchema>;
|
||||
|
||||
export const ForwardAuthSchema = z.object({
|
||||
address: z.string().optional(),
|
||||
tls: ClientTLSSchema.optional(),
|
||||
trustForwardHeader: z.boolean().optional(),
|
||||
authResponseHeaders: z.string().array().optional(),
|
||||
authResponseHeadersRegex: z.string().optional(),
|
||||
authRequestHeaders: z.string().array().optional(),
|
||||
addAuthCookiesToResponse: z.string().array().optional(),
|
||||
headerField: z.string().optional(),
|
||||
forwardBody: z.boolean().optional(),
|
||||
maxBodySize: z.number().optional(),
|
||||
preserveLocationHeader: z.boolean().optional(),
|
||||
preserveRequestMethod: z.boolean().optional(),
|
||||
});
|
||||
export type ForwardAuth = z.infer<typeof ForwardAuthSchema>;
|
||||
|
||||
export const InFlightReqSchema = z.object({
|
||||
amount: z.number().optional(),
|
||||
sourceCriterion: SourceCriterionSchema.optional(),
|
||||
});
|
||||
export type InFlightReq = z.infer<typeof InFlightReqSchema>;
|
||||
|
||||
export const BufferingSchema = z.object({
|
||||
maxRequestBodyBytes: z.number().optional(),
|
||||
memRequestBodyBytes: z.number().optional(),
|
||||
maxResponseBodyBytes: z.number().optional(),
|
||||
memResponseBodyBytes: z.number().optional(),
|
||||
retryExpression: z.string().optional(),
|
||||
});
|
||||
export type Buffering = z.infer<typeof BufferingSchema>;
|
||||
|
||||
export const CircuitBreakerSchema = z.object({
|
||||
expression: z.string().optional(),
|
||||
checkPeriod: z.number().optional(),
|
||||
fallbackDuration: z.number().optional(),
|
||||
recoveryDuration: z.number().optional(),
|
||||
responseCode: z.number().optional(),
|
||||
});
|
||||
export type CircuitBreaker = z.infer<typeof CircuitBreakerSchema>;
|
||||
|
||||
export const CompressSchema = z.object({
|
||||
excludedContentTypes: z.string().array().optional(),
|
||||
includedContentTypes: z.string().array().optional(),
|
||||
minResponseBodyBytes: z.number().optional(),
|
||||
encodings: z.string().array().optional(),
|
||||
defaultEncoding: z.string().optional(),
|
||||
});
|
||||
export type Compress = z.infer<typeof CompressSchema>;
|
||||
|
||||
export const TLSClientCertificateSubjectDNInfoSchema = z.object({
|
||||
country: z.boolean().optional(),
|
||||
province: z.boolean().optional(),
|
||||
locality: z.boolean().optional(),
|
||||
organization: z.boolean().optional(),
|
||||
organizationalUnit: z.boolean().optional(),
|
||||
commonName: z.boolean().optional(),
|
||||
serialNumber: z.boolean().optional(),
|
||||
domainComponent: z.boolean().optional(),
|
||||
});
|
||||
export type TLSClientCertificateSubjectDNInfo = z.infer<
|
||||
typeof TLSClientCertificateSubjectDNInfoSchema
|
||||
>;
|
||||
|
||||
export const TLSClientCertificateIssuerDNInfoSchema = z.object({
|
||||
country: z.boolean().optional(),
|
||||
province: z.boolean().optional(),
|
||||
locality: z.boolean().optional(),
|
||||
organization: z.boolean().optional(),
|
||||
commonName: z.boolean().optional(),
|
||||
serialNumber: z.boolean().optional(),
|
||||
domainComponent: z.boolean().optional(),
|
||||
});
|
||||
export type TLSClientCertificateIssuerDNInfo = z.infer<
|
||||
typeof TLSClientCertificateIssuerDNInfoSchema
|
||||
>;
|
||||
|
||||
export const TLSClientCertificateInfoSchema = z.object({
|
||||
notAfter: z.boolean().optional(),
|
||||
notBefore: z.boolean().optional(),
|
||||
sans: z.boolean().optional(),
|
||||
serialNumber: z.boolean().optional(),
|
||||
subject: TLSClientCertificateSubjectDNInfoSchema.optional(),
|
||||
issuer: TLSClientCertificateIssuerDNInfoSchema.optional(),
|
||||
});
|
||||
export type TLSClientCertificateInfo = z.infer<
|
||||
typeof TLSClientCertificateInfoSchema
|
||||
>;
|
||||
|
||||
export const PassTLSClientCertSchema = z.object({
|
||||
pem: z.boolean().optional(),
|
||||
info: TLSClientCertificateInfoSchema.optional(),
|
||||
});
|
||||
export type PassTLSClientCert = z.infer<typeof PassTLSClientCertSchema>;
|
||||
|
||||
export const RetrySchema = z.object({
|
||||
attempts: z.number().optional(),
|
||||
initialInterval: z.number().optional(),
|
||||
});
|
||||
export type Retry = z.infer<typeof RetrySchema>;
|
||||
|
||||
export const ContentTypeSchema = z.object({
|
||||
autoDetect: z.boolean().optional(),
|
||||
});
|
||||
export type ContentType = z.infer<typeof ContentTypeSchema>;
|
||||
|
||||
export const GrpcWebSchema = z.object({
|
||||
allowOrigins: z.string().array().optional(),
|
||||
});
|
||||
export type GrpcWeb = z.infer<typeof GrpcWebSchema>;
|
||||
|
||||
export const HeaderModifierSchema = z.object({
|
||||
set: z.record(z.string(), z.string()).optional(),
|
||||
add: z.record(z.string(), z.string()).optional(),
|
||||
remove: z.string().array().optional(),
|
||||
});
|
||||
export type HeaderModifier = z.infer<typeof HeaderModifierSchema>;
|
||||
|
||||
export const RequestRedirectSchema = z.object({
|
||||
scheme: z.string().optional(),
|
||||
hostname: z.string().optional(),
|
||||
port: z.string().optional(),
|
||||
path: z.string().optional(),
|
||||
pathPrefix: z.string().optional(),
|
||||
statusCode: z.number().optional(),
|
||||
});
|
||||
export type RequestRedirect = z.infer<typeof RequestRedirectSchema>;
|
||||
|
||||
export const URLRewriteSchema = z.object({
|
||||
hostname: z.string().optional(),
|
||||
path: z.string().optional(),
|
||||
pathPrefix: z.string().optional(),
|
||||
});
|
||||
export type URLRewrite = z.infer<typeof URLRewriteSchema>;
|
||||
|
||||
export const MiddlewareSchema = z.object({
|
||||
addPrefix: AddPrefixSchema.optional(),
|
||||
stripPrefix: StripPrefixSchema.optional(),
|
||||
stripPrefixRegex: StripPrefixRegexSchema.optional(),
|
||||
replacePath: ReplacePathSchema.optional(),
|
||||
replacePathRegex: ReplacePathRegexSchema.optional(),
|
||||
chain: ChainSchema.optional(),
|
||||
ipWhiteList: IPWhiteListSchema.optional(),
|
||||
ipAllowList: IPAllowListSchema.optional(),
|
||||
headers: HeadersSchema.optional(),
|
||||
errors: ErrorPageSchema.optional(),
|
||||
rateLimit: RateLimitSchema.optional(),
|
||||
redirectRegex: RedirectRegexSchema.optional(),
|
||||
redirectScheme: RedirectSchemeSchema.optional(),
|
||||
basicAuth: BasicAuthSchema.optional(),
|
||||
digestAuth: DigestAuthSchema.optional(),
|
||||
forwardAuth: ForwardAuthSchema.optional(),
|
||||
inFlightReq: InFlightReqSchema.optional(),
|
||||
buffering: BufferingSchema.optional(),
|
||||
circuitBreaker: CircuitBreakerSchema.optional(),
|
||||
compress: CompressSchema.optional(),
|
||||
passTLSClientCert: PassTLSClientCertSchema.optional(),
|
||||
retry: RetrySchema.optional(),
|
||||
contentType: ContentTypeSchema.optional(),
|
||||
grpcWeb: GrpcWebSchema.optional(),
|
||||
plugin: z.record(z.string(), z.record(z.string(), z.any())).optional(),
|
||||
requestHeaderModifier: HeaderModifierSchema.optional(),
|
||||
responseHeaderModifier: HeaderModifierSchema.optional(),
|
||||
requestRedirect: RequestRedirectSchema.optional(),
|
||||
URLRewrite: URLRewriteSchema.optional(),
|
||||
});
|
||||
export type Middleware = z.infer<typeof MiddlewareSchema>;
|
||||
|
||||
export const TCPInFlightConnSchema = z.object({
|
||||
amount: z.number().optional(),
|
||||
});
|
||||
export type TCPInFlightConn = z.infer<typeof TCPInFlightConnSchema>;
|
||||
|
||||
export const TCPIPWhiteListSchema = z.object({
|
||||
sourceRange: z.string().array().optional(),
|
||||
});
|
||||
export type TCPIPWhiteList = z.infer<typeof TCPIPWhiteListSchema>;
|
||||
|
||||
export const TCPIPAllowListSchema = z.object({
|
||||
sourceRange: z.string().array().optional(),
|
||||
});
|
||||
export type TCPIPAllowList = z.infer<typeof TCPIPAllowListSchema>;
|
||||
|
||||
export const TCPMiddlewareSchema = z.object({
|
||||
inFlightConn: TCPInFlightConnSchema.optional(),
|
||||
ipWhiteList: TCPIPWhiteListSchema.optional(),
|
||||
ipAllowList: TCPIPAllowListSchema.optional(),
|
||||
});
|
||||
export type TCPMiddleware = z.infer<typeof TCPMiddlewareSchema>;
|
||||
|
||||
export const DomainSchema = z.object({
|
||||
main: z.string().optional(),
|
||||
sans: z.string().array().optional(),
|
||||
});
|
||||
export type Domain = z.infer<typeof DomainSchema>;
|
||||
|
||||
export const RouterTLSConfigSchema = z.object({
|
||||
options: z.string().optional(),
|
||||
certResolver: z.string().optional(),
|
||||
domains: DomainSchema.array().optional(),
|
||||
});
|
||||
export type RouterTLSConfig = z.infer<typeof RouterTLSConfigSchema>;
|
||||
|
||||
export const RouterObservabilityConfigSchema = z.object({
|
||||
accessLogs: z.boolean().optional(),
|
||||
tracing: z.boolean().optional(),
|
||||
metrics: z.boolean().optional(),
|
||||
});
|
||||
export type RouterObservabilityConfig = z.infer<
|
||||
typeof RouterObservabilityConfigSchema
|
||||
>;
|
||||
|
||||
export const RouterSchema = z.object({
|
||||
entryPoints: z.string().array().optional(),
|
||||
middlewares: z.string().array().optional(),
|
||||
service: z.string().optional(),
|
||||
rule: z.string().optional(),
|
||||
ruleSyntax: z.string().optional(),
|
||||
priority: z.number().optional(),
|
||||
tls: RouterTLSConfigSchema.optional(),
|
||||
observability: RouterObservabilityConfigSchema.optional(),
|
||||
});
|
||||
export type Router = z.infer<typeof RouterSchema>;
|
||||
|
||||
export const RouterTCPTLSConfigSchema = z.object({
|
||||
passthrough: z.boolean(),
|
||||
options: z.string().optional(),
|
||||
certResolver: z.string().optional(),
|
||||
domains: DomainSchema.array().optional(),
|
||||
});
|
||||
export type RouterTCPTLSConfig = z.infer<typeof RouterTCPTLSConfigSchema>;
|
||||
|
||||
export const TCPRouterSchema = z.object({
|
||||
entryPoints: z.string().array().optional(),
|
||||
middlewares: z.string().array().optional(),
|
||||
service: z.string().optional(),
|
||||
rule: z.string().optional(),
|
||||
ruleSyntax: z.string().optional(),
|
||||
priority: z.number().optional(),
|
||||
tls: RouterTCPTLSConfigSchema.optional(),
|
||||
});
|
||||
export type TCPRouter = z.infer<typeof TCPRouterSchema>;
|
||||
|
||||
export const UDPRouterSchema = z.object({
|
||||
entryPoints: z.string().array().optional(),
|
||||
service: z.string().optional(),
|
||||
});
|
||||
export type UDPRouter = z.infer<typeof UDPRouterSchema>;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DnsProviderType } from './gen/mantrae/v1/dns_provider_pb';
|
||||
import { MiddlewareType } from './gen/mantrae/v1/middleware_pb';
|
||||
import { RouterType } from './gen/mantrae/v1/router_pb';
|
||||
import { ServiceType } from './gen/mantrae/v1/service_pb';
|
||||
import type { JsonObject } from '@bufbuild/protobuf';
|
||||
import { DnsProviderType } from "./gen/mantrae/v1/dns_provider_pb";
|
||||
import { MiddlewareType } from "./gen/mantrae/v1/middleware_pb";
|
||||
import { RouterType } from "./gen/mantrae/v1/router_pb";
|
||||
import { ServiceType } from "./gen/mantrae/v1/service_pb";
|
||||
import type { JsonObject } from "@bufbuild/protobuf";
|
||||
|
||||
// Parse protobuf config
|
||||
export function unmarshalConfig<T>(json: JsonObject | undefined): T {
|
||||
@@ -17,62 +17,62 @@ export function marshalConfig<T>(config: T): JsonObject {
|
||||
|
||||
// Convert enum to select options
|
||||
export const routerTypes = Object.keys(RouterType)
|
||||
.filter((key) => isNaN(Number(key)) && key !== 'UNSPECIFIED')
|
||||
.filter((key) => isNaN(Number(key)) && key !== "UNSPECIFIED")
|
||||
.map((key) => ({
|
||||
label: key.toUpperCase(),
|
||||
value: RouterType[key as keyof typeof RouterType]
|
||||
value: RouterType[key as keyof typeof RouterType],
|
||||
}));
|
||||
|
||||
export const serviceTypes = Object.keys(ServiceType)
|
||||
.filter((key) => isNaN(Number(key)) && key !== 'UNSPECIFIED')
|
||||
.filter((key) => isNaN(Number(key)) && key !== "UNSPECIFIED")
|
||||
.map((key) => ({
|
||||
label: key.toUpperCase(),
|
||||
value: ServiceType[key as keyof typeof ServiceType]
|
||||
value: ServiceType[key as keyof typeof ServiceType],
|
||||
}));
|
||||
|
||||
export const middlewareTypes = Object.keys(MiddlewareType)
|
||||
.filter((key) => isNaN(Number(key)) && key !== 'UNSPECIFIED')
|
||||
.filter((key) => isNaN(Number(key)) && key !== "UNSPECIFIED")
|
||||
.map((key) => ({
|
||||
label: key.toUpperCase(),
|
||||
value: MiddlewareType[key as keyof typeof MiddlewareType]
|
||||
value: MiddlewareType[key as keyof typeof MiddlewareType],
|
||||
}));
|
||||
|
||||
export const dnsProviderTypes = Object.keys(DnsProviderType)
|
||||
.filter((key) => isNaN(Number(key)) && key !== 'UNSPECIFIED')
|
||||
.filter((key) => isNaN(Number(key)) && key !== "UNSPECIFIED")
|
||||
.map((key) => ({
|
||||
label: key
|
||||
.replace('DNS_PROVIDER_TYPE_', '')
|
||||
.replace("DNS_PROVIDER_TYPE_", "")
|
||||
.toLowerCase()
|
||||
.replace(/^\w/, (c) => c.toUpperCase()),
|
||||
value: DnsProviderType[key as keyof typeof DnsProviderType]
|
||||
value: DnsProviderType[key as keyof typeof DnsProviderType],
|
||||
}));
|
||||
|
||||
export const HTTPMiddlewareKeys = [
|
||||
{ value: 'addPrefix', label: 'Add Prefix' },
|
||||
{ value: 'basicAuth', label: 'Basic Auth' },
|
||||
{ value: 'digestAuth', label: 'Digest Auth' },
|
||||
{ value: 'buffering', label: 'Buffering' },
|
||||
{ value: 'chain', label: 'Chain' },
|
||||
{ value: 'circuitBreaker', label: 'Circuit Breaker' },
|
||||
{ value: 'compress', label: 'Compress' },
|
||||
{ value: 'errorPage', label: 'Error Page' },
|
||||
{ value: 'forwardAuth', label: 'Forward Auth' },
|
||||
{ value: 'headers', label: 'Headers' },
|
||||
{ value: 'ipAllowList', label: 'IP Allow List' },
|
||||
{ value: 'inFlightReq', label: 'In-Flight Request' },
|
||||
{ value: 'passTLSClientCert', label: 'Pass TLS Client Cert' },
|
||||
{ value: 'rateLimit', label: 'Rate Limit' },
|
||||
{ value: 'redirectRegex', label: 'Redirect Regex' },
|
||||
{ value: 'redirectScheme', label: 'Redirect Scheme' },
|
||||
{ value: 'replacePath', label: 'Replace Path' },
|
||||
{ value: 'replacePathRegex', label: 'Replace Path Regex' },
|
||||
{ value: 'retry', label: 'Retry' },
|
||||
{ value: 'stripPrefix', label: 'Strip Prefix' },
|
||||
{ value: 'stripPrefixRegex', label: 'Strip Prefix Regex' },
|
||||
{ value: 'plugin', label: 'Plugin' }
|
||||
{ value: "addPrefix", label: "Add Prefix" },
|
||||
{ value: "basicAuth", label: "Basic Auth" },
|
||||
{ value: "digestAuth", label: "Digest Auth" },
|
||||
{ value: "buffering", label: "Buffering" },
|
||||
{ value: "chain", label: "Chain" },
|
||||
{ value: "circuitBreaker", label: "Circuit Breaker" },
|
||||
{ value: "compress", label: "Compress" },
|
||||
{ value: "errorPage", label: "Error Page" },
|
||||
{ value: "forwardAuth", label: "Forward Auth" },
|
||||
{ value: "headers", label: "Headers" },
|
||||
{ value: "ipAllowList", label: "IP Allow List" },
|
||||
{ value: "inFlightReq", label: "In-Flight Request" },
|
||||
{ value: "passTLSClientCert", label: "Pass TLS Client Cert" },
|
||||
{ value: "rateLimit", label: "Rate Limit" },
|
||||
{ value: "redirectRegex", label: "Redirect Regex" },
|
||||
{ value: "redirectScheme", label: "Redirect Scheme" },
|
||||
{ value: "replacePath", label: "Replace Path" },
|
||||
{ value: "replacePathRegex", label: "Replace Path Regex" },
|
||||
{ value: "retry", label: "Retry" },
|
||||
{ value: "stripPrefix", label: "Strip Prefix" },
|
||||
{ value: "stripPrefixRegex", label: "Strip Prefix Regex" },
|
||||
{ value: "plugin", label: "Plugin" },
|
||||
];
|
||||
|
||||
export const TCPMiddlewareKeys = [
|
||||
{ value: 'ipAllowList', label: 'IP Allow List' },
|
||||
{ value: 'inFlightConn', label: 'In-Flight Connection' }
|
||||
{ value: "ipAllowList", label: "IP Allow List" },
|
||||
{ value: "inFlightConn", label: "In-Flight Connection" },
|
||||
];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import ColumnBadge from '$lib/components/tables/ColumnBadge.svelte';
|
||||
import DataTable from '$lib/components/tables/DataTable.svelte';
|
||||
import ColumnCheck from '$lib/components/tables/ColumnCheck.svelte';
|
||||
import MiddlewareModal from '$lib/components/modals/middleware.svelte';
|
||||
import TableActions from '$lib/components/tables/TableActions.svelte';
|
||||
import type { ColumnDef, PaginationState } from '@tanstack/table-core';
|
||||
@@ -68,6 +69,15 @@
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
header: 'Enabled',
|
||||
accessorKey: 'enabled',
|
||||
enableSorting: true,
|
||||
cell: ({ row }) => {
|
||||
let checked = row.getValue('enabled') as boolean;
|
||||
return renderComponent(ColumnCheck, { checked: checked });
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
enableHiding: false,
|
||||
@@ -117,13 +127,15 @@
|
||||
toast.success('Router deleted');
|
||||
} catch (err) {
|
||||
const e = ConnectError.from(err);
|
||||
toast.error('Failed to delete router', { description: e.message });
|
||||
toast.error('Failed to delete middleware', { description: e.message });
|
||||
}
|
||||
};
|
||||
|
||||
async function bulkDelete(selectedRows: Middleware[]) {
|
||||
try {
|
||||
const confirmed = confirm(`Are you sure you want to delete ${selectedRows.length} routers?`);
|
||||
const confirmed = confirm(
|
||||
`Are you sure you want to delete ${selectedRows.length} middlewares?`
|
||||
);
|
||||
if (!confirmed) return;
|
||||
|
||||
const rows = selectedRows.map((row) => ({ id: row.id, type: row.type }));
|
||||
@@ -131,10 +143,10 @@
|
||||
await middlewareClient.deleteMiddleware({ id: row.id, type: row.type });
|
||||
}
|
||||
await refreshData(pageSize.value ?? 10, 0);
|
||||
toast.success(`Successfully deleted ${selectedRows.length} routers`);
|
||||
toast.success(`Successfully deleted ${selectedRows.length} middlewares`);
|
||||
} catch (err) {
|
||||
const e = ConnectError.from(err);
|
||||
toast.error('Failed to delete routers', { description: e.message });
|
||||
toast.error('Failed to delete middlewares', { description: e.message });
|
||||
}
|
||||
}
|
||||
async function refreshData(pageSize: number, pageIndex: number) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import type { BulkAction } from '$lib/components/tables/types';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import { RouterType, type Router } from '$lib/gen/mantrae/v1/router_pb';
|
||||
import type { RouterTLSConfig } from '$lib/gen/tygo/dynamic';
|
||||
import type { RouterTLSConfig } from '$lib/gen/zen/traefik-schemas';
|
||||
import { pageIndex, pageSize } from '$lib/stores/common';
|
||||
import { profile } from '$lib/stores/profile';
|
||||
import { ConnectError } from '@connectrpc/connect';
|
||||
|
||||
Reference in New Issue
Block a user