fix: 修复CSP白屏并优化LDAP配置
This commit is contained in:
1 parent
a14d9e62e6
commit
c7f59f2cbf
12 files changed
+928
-68
No files matched your search
@@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -19,6 +18,7 @@ import (
|
|||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"vpn-platform/backend/internal/ldaputil"
|
||||||
"vpn-platform/backend/internal/model"
|
"vpn-platform/backend/internal/model"
|
||||||
"vpn-platform/backend/internal/service/ikev2"
|
"vpn-platform/backend/internal/service/ikev2"
|
||||||
"vpn-platform/backend/internal/service/l2tp"
|
"vpn-platform/backend/internal/service/l2tp"
|
||||||
@@ -85,27 +85,20 @@ func ldapSettings() (*model.LDAPConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ldapConnect(cfg *model.LDAPConfig) (*ldap.Conn, error) {
|
func ldapConnect(cfg *model.LDAPConfig) (*ldap.Conn, error) {
|
||||||
url := cfg.URL
|
dialURL, err := ldaputil.DialURL(cfg.URL)
|
||||||
if !strings.HasPrefix(url, "ldap://") && !strings.HasPrefix(url, "ldaps://") {
|
|
||||||
// 安全默认:未显式指定协议时按 ldaps,避免口令明文过网
|
|
||||||
url = "ldaps://" + url
|
|
||||||
}
|
|
||||||
conn, err := ldap.DialURL(url)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if cfg.StartTLS && strings.HasPrefix(url, "ldap://") {
|
conn, err := ldap.DialURL(dialURL)
|
||||||
host := strings.TrimPrefix(url, "ldap://")
|
if err != nil {
|
||||||
if h, _, err := net.SplitHostPort(host); err == nil {
|
return nil, err
|
||||||
host = h
|
}
|
||||||
}
|
if cfg.StartTLS && strings.HasPrefix(dialURL, "ldap://") {
|
||||||
|
host := ldaputil.Hostname(dialURL)
|
||||||
if err := conn.StartTLS(&tls.Config{ServerName: host}); err != nil {
|
if err := conn.StartTLS(&tls.Config{ServerName: host}); err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return nil, fmt.Errorf("StartTLS 升级失败: %w", err)
|
return nil, fmt.Errorf("StartTLS 升级失败: %w", err)
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(url, "ldap://") {
|
|
||||||
conn.Close()
|
|
||||||
return nil, fmt.Errorf("明文 ldap:// 存在口令泄露风险,请改用 ldaps:// 或开启 StartTLS")
|
|
||||||
}
|
}
|
||||||
if cfg.BindDN != "" {
|
if cfg.BindDN != "" {
|
||||||
if err := conn.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
|
if err := conn.Bind(cfg.BindDN, cfg.BindPassword); err != nil {
|
||||||
@@ -126,7 +119,12 @@ func (s *Server) authenticateLDAP(username, password string) (*model.User, error
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
filter := fmt.Sprintf("(&%s(%s=%s))", cfg.UserFilter, cfg.UsernameAttribute, ldap.EscapeFilter(username))
|
filter := cfg.UserFilter
|
||||||
|
if strings.Contains(filter, "%s") {
|
||||||
|
filter = fmt.Sprintf(filter, ldap.EscapeFilter(username))
|
||||||
|
} else {
|
||||||
|
filter = fmt.Sprintf("(&%s(%s=%s))", filter, cfg.UsernameAttribute, ldap.EscapeFilter(username))
|
||||||
|
}
|
||||||
result, err := conn.Search(ldap.NewSearchRequest(cfg.BaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 1, 5, false, filter, []string{"dn", cfg.UsernameAttribute, "cn", "mail"}, nil))
|
result, err := conn.Search(ldap.NewSearchRequest(cfg.BaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 1, 5, false, filter, []string{"dn", cfg.UsernameAttribute, "cn", "mail"}, nil))
|
||||||
if err != nil || len(result.Entries) != 1 {
|
if err != nil || len(result.Entries) != 1 {
|
||||||
return nil, fmt.Errorf("LDAP 用户不存在")
|
return nil, fmt.Errorf("LDAP 用户不存在")
|
||||||
@@ -361,6 +359,12 @@ func (s *Server) saveLDAPConfig(c *gin.Context) {
|
|||||||
c.JSON(400, gin.H{"error": "LDAP 地址与 Base DN 必填"})
|
c.JSON(400, gin.H{"error": "LDAP 地址与 Base DN 必填"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if req.Enabled {
|
||||||
|
if _, err := ldaputil.DialURL(req.URL); err != nil {
|
||||||
|
c.JSON(400, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
var cfg model.LDAPConfig
|
var cfg model.LDAPConfig
|
||||||
store.DB.First(&cfg)
|
store.DB.First(&cfg)
|
||||||
cfg.URL, cfg.BindDN, cfg.BaseDN, cfg.UserFilter, cfg.UsernameAttribute, cfg.StartTLS, cfg.Enabled =
|
cfg.URL, cfg.BindDN, cfg.BaseDN, cfg.UserFilter, cfg.UsernameAttribute, cfg.StartTLS, cfg.Enabled =
|
||||||
@@ -373,17 +377,35 @@ func (s *Server) saveLDAPConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) testLDAP(c *gin.Context) {
|
func (s *Server) testLDAP(c *gin.Context) {
|
||||||
cfg, err := ldapSettings()
|
var req struct {
|
||||||
if err == nil {
|
URL string `json:"url"`
|
||||||
conn, connErr := ldapConnect(cfg)
|
BindDN string `json:"bind_dn"`
|
||||||
if connErr == nil {
|
BindPassword string `json:"bind_password"`
|
||||||
conn.Close()
|
StartTLS bool `json:"starttls"`
|
||||||
c.JSON(200, gin.H{"ok": true})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = connErr
|
|
||||||
}
|
}
|
||||||
c.JSON(400, gin.H{"error": "LDAP 连接失败: " + err.Error()})
|
if c.ShouldBindJSON(&req) != nil || strings.TrimSpace(req.URL) == "" {
|
||||||
|
c.JSON(400, gin.H{"error": "LDAP 服务器地址必填"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg := &model.LDAPConfig{URL: strings.TrimSpace(req.URL), BindDN: strings.TrimSpace(req.BindDN), BindPassword: req.BindPassword, StartTLS: req.StartTLS}
|
||||||
|
if cfg.BindPassword == "" {
|
||||||
|
var saved model.LDAPConfig
|
||||||
|
if store.DB.First(&saved).Error == nil && saved.BindPassword != "" {
|
||||||
|
plain, err := store.DecryptSecret(saved.BindPassword)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, gin.H{"error": "LDAP 配置密钥无效"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.BindPassword = plain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn, err := ldapConnect(cfg)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, gin.H{"error": "LDAP 连接失败: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
c.JSON(200, gin.H{"ok": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) listVPNUsers(c *gin.Context) {
|
func (s *Server) listVPNUsers(c *gin.Context) {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// Package ldaputil normalizes LDAP server addresses supplied by administrators.
|
||||||
|
package ldaputil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DialURL accepts an IP address or domain name, with an optional port. Bare
|
||||||
|
// addresses use LDAPS on port 636. Existing ldap:// and ldaps:// values remain
|
||||||
|
// supported for backward compatibility.
|
||||||
|
func DialURL(address string) (string, error) {
|
||||||
|
address = strings.TrimSpace(address)
|
||||||
|
if address == "" {
|
||||||
|
return "", fmt.Errorf("LDAP 服务器地址不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(address, "://") {
|
||||||
|
u, err := url.Parse(address)
|
||||||
|
if err != nil || (u.Scheme != "ldap" && u.Scheme != "ldaps") || u.Host == "" || u.Path != "" || u.RawQuery != "" || u.Fragment != "" {
|
||||||
|
return "", fmt.Errorf("LDAP 服务器地址格式无效")
|
||||||
|
}
|
||||||
|
port := "389"
|
||||||
|
if u.Scheme == "ldaps" {
|
||||||
|
port = "636"
|
||||||
|
}
|
||||||
|
host, err := withDefaultPort(u.Host, port)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
u.Host = host
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := withDefaultPort(address, "636")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "ldaps://" + host, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withDefaultPort(address, defaultPort string) (string, error) {
|
||||||
|
if strings.ContainsAny(address, " \t\r\n/?#@") {
|
||||||
|
return "", fmt.Errorf("LDAP 服务器地址格式无效")
|
||||||
|
}
|
||||||
|
if host, port, err := net.SplitHostPort(address); err == nil {
|
||||||
|
if host == "" || port == "" {
|
||||||
|
return "", fmt.Errorf("LDAP 服务器地址格式无效")
|
||||||
|
}
|
||||||
|
return address, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
host := strings.TrimSuffix(strings.TrimPrefix(address, "["), "]")
|
||||||
|
if host == "" || (strings.Contains(host, ":") && net.ParseIP(host) == nil) {
|
||||||
|
return "", fmt.Errorf("LDAP 服务器地址格式无效")
|
||||||
|
}
|
||||||
|
return net.JoinHostPort(host, defaultPort), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hostname returns the hostname or IP for TLS ServerName selection.
|
||||||
|
func Hostname(dialURL string) string {
|
||||||
|
u, err := url.Parse(dialURL)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return u.Hostname()
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package ldaputil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestDialURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
address string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"8.217.205.92", "ldaps://8.217.205.92:636"},
|
||||||
|
{"ldap.opsx.vip", "ldaps://ldap.opsx.vip:636"},
|
||||||
|
{"ldap.opsx.vip:1636", "ldaps://ldap.opsx.vip:1636"},
|
||||||
|
{"2001:db8::1", "ldaps://[2001:db8::1]:636"},
|
||||||
|
{"ldap://ldap.opsx.vip", "ldap://ldap.opsx.vip:389"},
|
||||||
|
{"ldaps://ldap.opsx.vip", "ldaps://ldap.opsx.vip:636"},
|
||||||
|
{" ldaps://8.217.205.92 ", "ldaps://8.217.205.92:636"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
got, err := DialURL(tt.address)
|
||||||
|
if err != nil || got != tt.want {
|
||||||
|
t.Errorf("DialURL(%q) = %q, %v; want %q", tt.address, got, err, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDialURLRejectsInvalidAddress(t *testing.T) {
|
||||||
|
for _, address := range []string{"", "ldap.opsx.vip/path", "ldap.opsx.vip:", "https://ldap.opsx.vip"} {
|
||||||
|
if _, err := DialURL(address); err == nil {
|
||||||
|
t.Errorf("DialURL(%q) succeeded; want error", address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"vpn-platform/backend/internal/core"
|
"vpn-platform/backend/internal/core"
|
||||||
|
"vpn-platform/backend/internal/ldaputil"
|
||||||
"vpn-platform/backend/internal/model"
|
"vpn-platform/backend/internal/model"
|
||||||
"vpn-platform/backend/internal/service"
|
"vpn-platform/backend/internal/service"
|
||||||
"vpn-platform/backend/internal/sessionmgr"
|
"vpn-platform/backend/internal/sessionmgr"
|
||||||
@@ -903,11 +904,11 @@ func verifyDialPassword(user *model.VPNUser, password string) error {
|
|||||||
if err := store.DB.Where("enabled = ?", true).First(&cfg).Error; err != nil {
|
if err := store.DB.Where("enabled = ?", true).First(&cfg).Error; err != nil {
|
||||||
return errors.New("LDAP 未启用")
|
return errors.New("LDAP 未启用")
|
||||||
}
|
}
|
||||||
url := cfg.URL
|
dialURL, err := ldaputil.DialURL(cfg.URL)
|
||||||
if !strings.HasPrefix(url, "ldap://") && !strings.HasPrefix(url, "ldaps://") {
|
if err != nil {
|
||||||
url = "ldap://" + url
|
return err
|
||||||
}
|
}
|
||||||
conn, err := ldap.DialURL(url)
|
conn, err := ldap.DialURL(dialURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+659
@@ -18,6 +18,7 @@
|
|||||||
"vue-router": "^4.4.5"
|
"vue-router": "^4.4.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@intlify/unplugin-vue-i18n": "4.0.0",
|
||||||
"@vitejs/plugin-vue": "^5.1.4",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"vite": "^5.4.10"
|
"vite": "^5.4.10"
|
||||||
}
|
}
|
||||||
@@ -502,6 +503,35 @@
|
|||||||
"integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
|
"integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@intlify/bundle-utils": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@intlify/bundle-utils/-/bundle-utils-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-1B++zykRnMwQ+20SpsZI1JCnV/YJt9Oq7AGlEurzkWJOFtFAVqaGc/oV36PBRYeiKnTbY9VYfjBimr2Vt42wLQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@intlify/message-compiler": "^9.4.0",
|
||||||
|
"@intlify/shared": "^9.4.0",
|
||||||
|
"acorn": "^8.8.2",
|
||||||
|
"escodegen": "^2.1.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"jsonc-eslint-parser": "^2.3.0",
|
||||||
|
"mlly": "^1.2.0",
|
||||||
|
"source-map-js": "^1.0.1",
|
||||||
|
"yaml-eslint-parser": "^1.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"petite-vue-i18n": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vue-i18n": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@intlify/core-base": {
|
"node_modules/@intlify/core-base": {
|
||||||
"version": "9.14.5",
|
"version": "9.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz",
|
||||||
@@ -546,12 +576,90 @@
|
|||||||
"url": "https://github.com/sponsors/kazupon"
|
"url": "https://github.com/sponsors/kazupon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@intlify/unplugin-vue-i18n": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-q2Mhqa/mLi0tulfLFO4fMXXvEbkSZpI5yGhNNsLTNJJ41icEGUuyDe+j5zRZIKSkOJRgX6YbCyibTDJdRsukmw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@intlify/bundle-utils": "^8.0.0",
|
||||||
|
"@intlify/shared": "^9.4.0",
|
||||||
|
"@rollup/pluginutils": "^5.1.0",
|
||||||
|
"@vue/compiler-sfc": "^3.2.47",
|
||||||
|
"debug": "^4.3.3",
|
||||||
|
"fast-glob": "^3.2.12",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"json5": "^2.2.3",
|
||||||
|
"pathe": "^1.0.0",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2",
|
||||||
|
"unplugin": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"petite-vue-i18n": "*",
|
||||||
|
"vue-i18n": "*",
|
||||||
|
"vue-i18n-bridge": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"petite-vue-i18n": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vue-i18n": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vue-i18n-bridge": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.5.5",
|
"version": "1.5.5",
|
||||||
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.stat": "2.0.5",
|
||||||
|
"run-parallel": "^1.1.9"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nodelib/fs.stat": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nodelib/fs.walk": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.scandir": "2.1.5",
|
||||||
|
"fastq": "^1.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@popperjs/core": {
|
"node_modules/@popperjs/core": {
|
||||||
"name": "@sxzz/popperjs-es",
|
"name": "@sxzz/popperjs-es",
|
||||||
"version": "2.11.8",
|
"version": "2.11.8",
|
||||||
@@ -563,6 +671,29 @@
|
|||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/pluginutils": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/estree": "^1.0.0",
|
||||||
|
"estree-walker": "^2.0.2",
|
||||||
|
"picomatch": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"rollup": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.62.2",
|
"version": "4.62.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
"resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
|
||||||
@@ -1097,6 +1228,29 @@
|
|||||||
"vue": "^3.5.0"
|
"vue": "^3.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/acorn": {
|
||||||
|
"version": "8.17.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.17.0.tgz",
|
||||||
|
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/acorn-jsx": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/agent-base": {
|
"node_modules/agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
@@ -1133,6 +1287,13 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/argparse": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Python-2.0"
|
||||||
|
},
|
||||||
"node_modules/async-validator": {
|
"node_modules/async-validator": {
|
||||||
"version": "4.2.5",
|
"version": "4.2.5",
|
||||||
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
|
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
|
||||||
@@ -1157,6 +1318,19 @@
|
|||||||
"proxy-from-env": "^2.1.0"
|
"proxy-from-env": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/call-bind-apply-helpers": {
|
"node_modules/call-bind-apply-helpers": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
@@ -1220,6 +1394,13 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/confbox": {
|
||||||
|
"version": "0.1.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz",
|
||||||
|
"integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
|
||||||
@@ -1425,12 +1606,152 @@
|
|||||||
"@esbuild/win32-x64": "0.21.5"
|
"@esbuild/win32-x64": "0.21.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/escodegen": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/escodegen/-/escodegen-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": "^4.0.1",
|
||||||
|
"estraverse": "^5.2.0",
|
||||||
|
"esutils": "^2.0.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"escodegen": "bin/escodegen.js",
|
||||||
|
"esgenerate": "bin/esgenerate.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"source-map": "~0.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/espree": {
|
||||||
|
"version": "9.6.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz",
|
||||||
|
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.9.0",
|
||||||
|
"acorn-jsx": "^5.3.2",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"bin": {
|
||||||
|
"esparse": "bin/esparse.js",
|
||||||
|
"esvalidate": "bin/esvalidate.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/estraverse": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/estree-walker": {
|
"node_modules/estree-walker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/esutils": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-glob": {
|
||||||
|
"version": "3.3.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||||
|
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@nodelib/fs.stat": "^2.0.2",
|
||||||
|
"@nodelib/fs.walk": "^1.2.3",
|
||||||
|
"glob-parent": "^5.1.2",
|
||||||
|
"merge2": "^1.3.0",
|
||||||
|
"micromatch": "^4.0.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-glob/node_modules/glob-parent": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"is-glob": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fastq": {
|
||||||
|
"version": "1.20.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz",
|
||||||
|
"integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"reusify": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz",
|
||||||
|
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/find-up": {
|
"node_modules/find-up": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
|
||||||
@@ -1614,6 +1935,16 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-fullwidth-code-point": {
|
"node_modules/is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
@@ -1623,6 +1954,84 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/js-yaml": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/puzrin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/nodeca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"argparse": "^2.0.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"js-yaml": "bin/js-yaml.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/json5": {
|
||||||
|
"version": "2.2.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
|
||||||
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"json5": "lib/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jsonc-eslint-parser": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.5.0",
|
||||||
|
"eslint-visitor-keys": "^3.0.0",
|
||||||
|
"espree": "^9.0.0",
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ota-meshi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -1682,6 +2091,43 @@
|
|||||||
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
|
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/merge2": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.3",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromatch/node_modules/picomatch": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
@@ -1703,6 +2149,26 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mlly": {
|
||||||
|
"version": "1.8.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.8.2.tgz",
|
||||||
|
"integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.16.0",
|
||||||
|
"pathe": "^2.0.3",
|
||||||
|
"pkg-types": "^1.3.1",
|
||||||
|
"ufo": "^1.6.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mlly/node_modules/pathe": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||||
@@ -1778,12 +2244,51 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pathe": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pkg-types": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"confbox": "^0.1.8",
|
||||||
|
"mlly": "^1.7.4",
|
||||||
|
"pathe": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/pkg-types/node_modules/pathe": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/pngjs": {
|
"node_modules/pngjs": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
|
||||||
@@ -1847,6 +2352,27 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/queue-microtask": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/require-directory": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@@ -1862,6 +2388,17 @@
|
|||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/reusify": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"iojs": ">=1.0.0",
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.62.2",
|
"version": "4.62.2",
|
||||||
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.62.2.tgz",
|
"resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.62.2.tgz",
|
||||||
@@ -1907,12 +2444,60 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/run-parallel": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"queue-microtask": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "7.8.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz",
|
||||||
|
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/set-blocking": {
|
"node_modules/set-blocking": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
@@ -1948,12 +2533,46 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
|
"node_modules/ufo": {
|
||||||
|
"version": "1.6.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.4.tgz",
|
||||||
|
"integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/unplugin": {
|
||||||
|
"version": "1.16.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.1.tgz",
|
||||||
|
"integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^8.14.0",
|
||||||
|
"webpack-virtual-modules": "^0.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.4.21",
|
"version": "5.4.21",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz",
|
||||||
@@ -2077,6 +2696,13 @@
|
|||||||
"vue": "^3.5.0"
|
"vue": "^3.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webpack-virtual-modules": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/which-module": {
|
"node_modules/which-module": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
|
||||||
@@ -2103,6 +2729,39 @@
|
|||||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/yaml": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"yaml": "bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.6"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/eemeli"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yaml-eslint-parser": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/yaml-eslint-parser/-/yaml-eslint-parser-1.3.2.tgz",
|
||||||
|
"integrity": "sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"eslint-visitor-keys": "^3.0.0",
|
||||||
|
"yaml": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.17.0 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ota-meshi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "15.4.1",
|
"version": "15.4.1",
|
||||||
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
|
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
"vue-router": "^4.4.5"
|
"vue-router": "^4.4.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@intlify/unplugin-vue-i18n": "4.0.0",
|
||||||
"@vitejs/plugin-vue": "^5.1.4",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"vite": "^5.4.10"
|
"vite": "^5.4.10"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"passwordLabel": "Password",
|
"passwordLabel": "Password",
|
||||||
"passwordPlaceholder": "Enter password",
|
"passwordPlaceholder": "Enter password",
|
||||||
"loginButton": "Sign In",
|
"loginButton": "Sign In",
|
||||||
"defaultAccount": "Default account: <strong>admin / admin123</strong> — please change password after first login",
|
"defaultAccount": "Default account: {account} — please change password after first login",
|
||||||
"errorEmpty": "Please enter username and password",
|
"errorEmpty": "Please enter username and password",
|
||||||
"loginSuccess": "Login successful",
|
"loginSuccess": "Login successful",
|
||||||
"changePasswordFirst": "Please change your password first",
|
"changePasswordFirst": "Please change your password first",
|
||||||
@@ -279,14 +279,22 @@
|
|||||||
"roleOperator": "Operator",
|
"roleOperator": "Operator",
|
||||||
"roleViewer": "Viewer",
|
"roleViewer": "Viewer",
|
||||||
"noUsers": "No users yet",
|
"noUsers": "No users yet",
|
||||||
"ldapTitle": "LDAP Identity Source",
|
"ldapTitle": "LDAP / Active Directory",
|
||||||
"ldapHint": "LDAP users can be auto-synced on first login, or pre-imported using the \"LDAP Import\" on the left.",
|
"ldapHint": "LDAP users can be auto-synced on first login, or pre-imported using the \"LDAP Import\" on the left.",
|
||||||
"ldapUrl": "LDAP URL",
|
"ldapConfigHint": "Configure an LDAP server for centralized identity authentication",
|
||||||
"bindDn": "Bind DN",
|
"ldapEnabled": "Enable LDAP",
|
||||||
"bindPassword": "Bind Password",
|
"ldapServerAddress": "LDAP Server Address",
|
||||||
|
"ldapServerAddressPlaceholder": "e.g. 8.217.205.92 or ldap.example.com",
|
||||||
|
"ldapPort": "Port",
|
||||||
|
"ldapProtocol": "Protocol",
|
||||||
|
"ldapProtocolLDAPS": "LDAPS (Recommended)",
|
||||||
|
"ldapProtocolLDAP": "LDAP",
|
||||||
|
"bindDn": "Administrator Bind DN",
|
||||||
|
"bindPassword": "Administrator Password",
|
||||||
"keepOriginal": "Leave empty to keep original",
|
"keepOriginal": "Leave empty to keep original",
|
||||||
"baseDn": "Base DN",
|
"baseDn": "Base DN (User Search Base)",
|
||||||
"userFilter": "User Filter",
|
"userFilter": "Search Filter (optional; %s is the username)",
|
||||||
|
"enableLdaps": "Enable LDAPS (SSL encryption)",
|
||||||
"usernameAttr": "Username Attribute",
|
"usernameAttr": "Username Attribute",
|
||||||
"testConnection": "Test Connection",
|
"testConnection": "Test Connection",
|
||||||
"editUser": "Edit User",
|
"editUser": "Edit User",
|
||||||
@@ -320,6 +328,7 @@
|
|||||||
"ldapLoadFailed": "LDAP load failed",
|
"ldapLoadFailed": "LDAP load failed",
|
||||||
"ldapConfigSaved": "LDAP configuration saved",
|
"ldapConfigSaved": "LDAP configuration saved",
|
||||||
"ldapConnected": "LDAP connection successful",
|
"ldapConnected": "LDAP connection successful",
|
||||||
|
"ldapTestRequired": "Test the LDAP connection successfully before saving",
|
||||||
"ldapConnectFailed": "Connection failed",
|
"ldapConnectFailed": "Connection failed",
|
||||||
"emptyUsername": "(empty)",
|
"emptyUsername": "(empty)",
|
||||||
"errorDetails": "Error details:"
|
"errorDetails": "Error details:"
|
||||||
@@ -502,8 +511,9 @@
|
|||||||
"plugins": {
|
"plugins": {
|
||||||
"title": "Custom Protocol Plugins",
|
"title": "Custom Protocol Plugins",
|
||||||
"registerPlugin": "Register Plugin",
|
"registerPlugin": "Register Plugin",
|
||||||
"pluginHint": "Plugins implement the unified protocol contract via <b>command hooks</b>: the platform pipes tunnel config JSON to hook commands via stdin.",
|
"commandHooks": "command hooks",
|
||||||
"pluginContract": "Contract: <code>Create / Start / Stop / Status / Config</code>; Status hook outputs <code>running</code> or <code>stopped</code> on stdout; Config hook outputs client config text.",
|
"pluginHint": "Plugins implement the unified protocol contract via {hooks}: the platform pipes tunnel config JSON to hook commands via stdin.",
|
||||||
|
"pluginContract": "Contract: {contract}; Status hook outputs {running} or {stopped} on stdout; Config hook outputs client config text.",
|
||||||
"protocolId": "Protocol ID",
|
"protocolId": "Protocol ID",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"passwordLabel": "密码",
|
"passwordLabel": "密码",
|
||||||
"passwordPlaceholder": "请输入密码",
|
"passwordPlaceholder": "请输入密码",
|
||||||
"loginButton": "登 录",
|
"loginButton": "登 录",
|
||||||
"defaultAccount": "默认账号 <strong>admin / admin123</strong>,登录后请立即修改",
|
"defaultAccount": "默认账号 {account},登录后请立即修改",
|
||||||
"errorEmpty": "请输入用户名和密码",
|
"errorEmpty": "请输入用户名和密码",
|
||||||
"loginSuccess": "登录成功",
|
"loginSuccess": "登录成功",
|
||||||
"changePasswordFirst": "首次登录请先修改密码",
|
"changePasswordFirst": "首次登录请先修改密码",
|
||||||
@@ -279,14 +279,22 @@
|
|||||||
"roleOperator": "运维",
|
"roleOperator": "运维",
|
||||||
"roleViewer": "只读",
|
"roleViewer": "只读",
|
||||||
"noUsers": "还没有用户",
|
"noUsers": "还没有用户",
|
||||||
"ldapTitle": "LDAP 身份源",
|
"ldapTitle": "LDAP / Active Directory",
|
||||||
"ldapHint": "LDAP 用户可首次登录后自动同步,也可使用左侧「LDAP 导入」预先添加。",
|
"ldapHint": "LDAP 用户可首次登录后自动同步,也可使用左侧「LDAP 导入」预先添加。",
|
||||||
"ldapUrl": "LDAP URL",
|
"ldapConfigHint": "配置 LDAP 服务器,实现统一身份认证",
|
||||||
"bindDn": "Bind DN",
|
"ldapEnabled": "启用 LDAP",
|
||||||
"bindPassword": "Bind 密码",
|
"ldapServerAddress": "LDAP 服务器地址",
|
||||||
|
"ldapServerAddressPlaceholder": "例如 8.217.205.92 或 ldap.example.com",
|
||||||
|
"ldapPort": "端口",
|
||||||
|
"ldapProtocol": "连接协议",
|
||||||
|
"ldapProtocolLDAPS": "LDAPS(推荐)",
|
||||||
|
"ldapProtocolLDAP": "LDAP",
|
||||||
|
"bindDn": "管理员 Bind DN",
|
||||||
|
"bindPassword": "管理员密码",
|
||||||
"keepOriginal": "留空保持原值",
|
"keepOriginal": "留空保持原值",
|
||||||
"baseDn": "Base DN",
|
"baseDn": "Base DN(用户搜索基础)",
|
||||||
"userFilter": "用户过滤",
|
"userFilter": "搜索过滤器(可选,%s 表示用户名)",
|
||||||
|
"enableLdaps": "启用 LDAPS(SSL 加密)",
|
||||||
"usernameAttr": "用户名属性",
|
"usernameAttr": "用户名属性",
|
||||||
"testConnection": "测试连接",
|
"testConnection": "测试连接",
|
||||||
"editUser": "编辑用户",
|
"editUser": "编辑用户",
|
||||||
@@ -320,6 +328,7 @@
|
|||||||
"ldapLoadFailed": "LDAP 加载失败",
|
"ldapLoadFailed": "LDAP 加载失败",
|
||||||
"ldapConfigSaved": "LDAP 配置已保存",
|
"ldapConfigSaved": "LDAP 配置已保存",
|
||||||
"ldapConnected": "LDAP 连接成功",
|
"ldapConnected": "LDAP 连接成功",
|
||||||
|
"ldapTestRequired": "请先测试 LDAP 连接,通过后才能保存",
|
||||||
"ldapConnectFailed": "连接失败",
|
"ldapConnectFailed": "连接失败",
|
||||||
"emptyUsername": "(空)",
|
"emptyUsername": "(空)",
|
||||||
"errorDetails": "失败详情:"
|
"errorDetails": "失败详情:"
|
||||||
@@ -502,8 +511,9 @@
|
|||||||
"plugins": {
|
"plugins": {
|
||||||
"title": "自定义协议插件",
|
"title": "自定义协议插件",
|
||||||
"registerPlugin": "注册插件",
|
"registerPlugin": "注册插件",
|
||||||
"pluginHint": "插件通过<b>命令钩子</b>实现统一协议契约:平台将专线配置 JSON 通过 stdin 传给钩子命令。",
|
"commandHooks": "命令钩子",
|
||||||
"pluginContract": "契约:<code>Create / Start / Stop / Status / Config</code>;Status 钩子 stdout 输出 <code>running</code> 或 <code>stopped</code>;Config 钩子 stdout 输出客户端配置文本。",
|
"pluginHint": "插件通过 {hooks} 实现统一协议契约:平台将专线配置 JSON 通过 stdin 传给钩子命令。",
|
||||||
|
"pluginContract": "契约:{contract};Status 钩子 stdout 输出 {running} 或 {stopped};Config 钩子 stdout 输出客户端配置文本。",
|
||||||
"protocolId": "协议标识",
|
"protocolId": "协议标识",
|
||||||
"enabled": "启用",
|
"enabled": "启用",
|
||||||
"disabled": "停用",
|
"disabled": "停用",
|
||||||
|
|||||||
@@ -72,7 +72,9 @@
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="login-footer">
|
<div class="login-footer">
|
||||||
<p v-html="$t('login.defaultAccount')"></p>
|
<i18n-t keypath="login.defaultAccount" tag="p">
|
||||||
|
<template #account><strong>admin / admin123</strong></template>
|
||||||
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,8 +8,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-alert type="info" :closable="false" style="margin-bottom:14px">
|
<el-alert type="info" :closable="false" style="margin-bottom:14px">
|
||||||
<p style="margin:0" v-html="$t('plugins.pluginHint')"></p>
|
<i18n-t keypath="plugins.pluginHint" tag="p" style="margin:0">
|
||||||
<p style="margin:4px 0 0;font-size:12px" v-html="$t('plugins.pluginContract')"></p>
|
<template #hooks><b>{{ $t('plugins.commandHooks') }}</b></template>
|
||||||
|
</i18n-t>
|
||||||
|
<i18n-t keypath="plugins.pluginContract" tag="p" style="margin:4px 0 0;font-size:12px">
|
||||||
|
<template #contract><code>Create / Start / Stop / Status / Config</code></template>
|
||||||
|
<template #running><code>running</code></template>
|
||||||
|
<template #stopped><code>stopped</code></template>
|
||||||
|
</i18n-t>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
<el-table :data="plugins" size="default" v-loading="loading">
|
<el-table :data="plugins" size="default" v-loading="loading">
|
||||||
<el-table-column prop="display_name" :label="$t('common.name')" width="160" />
|
<el-table-column prop="display_name" :label="$t('common.name')" width="160" />
|
||||||
|
|||||||
@@ -46,20 +46,28 @@
|
|||||||
|
|
||||||
<el-col :xs="24" :lg="9">
|
<el-col :xs="24" :lg="9">
|
||||||
<el-card class="page-card" shadow="never">
|
<el-card class="page-card" shadow="never">
|
||||||
<template #header><b>{{ $t('users.ldapTitle') }}</b></template>
|
<template #header>
|
||||||
<el-alert type="info" :closable="false"
|
<div>
|
||||||
:title="$t('users.ldapHint')" style="margin-bottom:12px" />
|
<b>{{ $t('users.ldapTitle') }}</b>
|
||||||
<el-form label-width="90px" size="small">
|
<div style="margin-top:4px;font-size:12px;color:var(--text-secondary)">{{ $t('users.ldapConfigHint') }}</div>
|
||||||
<el-form-item :label="$t('common.enabled')"><el-switch v-model="ldap.enabled" /></el-form-item>
|
</div>
|
||||||
<el-form-item :label="$t('users.ldapUrl')"><el-input v-model="ldap.url" placeholder="ldaps://ldap.example.com:636" /></el-form-item>
|
</template>
|
||||||
<el-form-item :label="$t('users.bindDn')"><el-input v-model="ldap.bind_dn" /></el-form-item>
|
<el-form label-width="112px" size="small">
|
||||||
|
<el-form-item :label="$t('users.ldapEnabled')"><el-switch v-model="ldap.enabled" /></el-form-item>
|
||||||
|
<el-form-item :label="$t('users.ldapServerAddress')">
|
||||||
|
<el-input v-model.trim="ldap.url" :placeholder="$t('users.ldapServerAddressPlaceholder')" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('users.ldapPort')">
|
||||||
|
<el-input-number v-model="ldapPort" :min="1" :max="65535" :controls="false" style="width:100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('users.baseDn')"><el-input v-model.trim="ldap.base_dn" placeholder="dc=opsx,dc=vip" /></el-form-item>
|
||||||
|
<el-form-item :label="$t('users.bindDn')"><el-input v-model.trim="ldap.bind_dn" placeholder="cn=admin,dc=opsx,dc=vip" /></el-form-item>
|
||||||
<el-form-item :label="$t('users.bindPassword')"><el-input v-model="ldap.bind_password" type="password" show-password :placeholder="$t('users.keepOriginal')" /></el-form-item>
|
<el-form-item :label="$t('users.bindPassword')"><el-input v-model="ldap.bind_password" type="password" show-password :placeholder="$t('users.keepOriginal')" /></el-form-item>
|
||||||
<el-form-item :label="$t('users.baseDn')"><el-input v-model="ldap.base_dn" placeholder="dc=example,dc=com" /></el-form-item>
|
<el-form-item :label="$t('users.userFilter')"><el-input v-model.trim="ldap.user_filter" placeholder="(uid=%s)" /></el-form-item>
|
||||||
<el-form-item :label="$t('users.userFilter')"><el-input v-model="ldap.user_filter" placeholder="(objectClass=inetOrgPerson)" /></el-form-item>
|
<el-form-item :label="$t('users.enableLdaps')"><el-switch v-model="ldapUseLDAPS" /></el-form-item>
|
||||||
<el-form-item :label="$t('users.usernameAttr')"><el-input v-model="ldap.username_attribute" placeholder="uid" /></el-form-item>
|
|
||||||
<div style="text-align:right">
|
<div style="text-align:right">
|
||||||
<el-button @click="testLDAP">{{ $t('users.testConnection') }}</el-button>
|
<el-button :loading="ldapTesting" @click="testLDAP">{{ $t('users.testConnection') }}</el-button>
|
||||||
<el-button type="primary" @click="saveLDAP">{{ $t('common.save') }}</el-button>
|
<el-button type="primary" :disabled="ldap.enabled && !ldapTested" :title="ldap.enabled && !ldapTested ? $t('users.ldapTestRequired') : ''" @click="saveLDAP">{{ $t('common.save') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -147,7 +155,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, watch } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import api, { auth } from '../api'
|
import api, { auth } from '../api'
|
||||||
@@ -163,6 +171,10 @@ const ldap = ref({
|
|||||||
base_dn: '', user_filter: '(objectClass=inetOrgPerson)', username_attribute: 'uid',
|
base_dn: '', user_filter: '(objectClass=inetOrgPerson)', username_attribute: 'uid',
|
||||||
start_tls: false,
|
start_tls: false,
|
||||||
})
|
})
|
||||||
|
const ldapUseLDAPS = ref(false)
|
||||||
|
const ldapPort = ref(389)
|
||||||
|
const ldapTested = ref(false)
|
||||||
|
const ldapTesting = ref(false)
|
||||||
|
|
||||||
// 批量导入
|
// 批量导入
|
||||||
const batchVisible = ref(false)
|
const batchVisible = ref(false)
|
||||||
@@ -183,6 +195,13 @@ async function load() {
|
|||||||
const [u, l] = await Promise.all([api.get('/users'), api.get('/ldap')])
|
const [u, l] = await Promise.all([api.get('/users'), api.get('/ldap')])
|
||||||
users.value = u.data || []
|
users.value = u.data || []
|
||||||
if (l.data) {
|
if (l.data) {
|
||||||
|
const savedAddress = String(l.data.url || '').trim()
|
||||||
|
const protocolMatch = savedAddress.match(/^(ldap|ldaps):\/\/(\[[^\]]+\]|[^/:]+)(?::(\d+))?$/i)
|
||||||
|
if (protocolMatch) {
|
||||||
|
ldapUseLDAPS.value = protocolMatch[1].toLowerCase() === 'ldaps'
|
||||||
|
l.data.url = protocolMatch[2].replace(/^\[|\]$/g, '')
|
||||||
|
ldapPort.value = Number(protocolMatch[3]) || (ldapUseLDAPS.value ? 636 : 389)
|
||||||
|
}
|
||||||
ldap.value = { ...ldap.value, ...l.data, bind_password: '' }
|
ldap.value = { ...ldap.value, ...l.data, bind_password: '' }
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -190,6 +209,20 @@ async function load() {
|
|||||||
} finally { loading.value = false }
|
} finally { loading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ldapPayload() {
|
||||||
|
const address = ldap.value.url.trim()
|
||||||
|
const host = address.includes(':') && !address.startsWith('[') ? `[${address}]` : address
|
||||||
|
const port = Number(ldapPort.value)
|
||||||
|
const protocol = ldapUseLDAPS.value ? 'ldaps' : 'ldap'
|
||||||
|
return { ...ldap.value, url: address && port >= 1 && port <= 65535 ? `${protocol}://${host}:${port}` : '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(ldapUseLDAPS, (useLDAPS, previousUseLDAPS) => {
|
||||||
|
const previousPort = previousUseLDAPS ? 636 : 389
|
||||||
|
if (ldapPort.value === previousPort) ldapPort.value = useLDAPS ? 636 : 389
|
||||||
|
})
|
||||||
|
watch([ldap, ldapUseLDAPS, ldapPort], () => { ldapTested.value = false }, { deep: true })
|
||||||
|
|
||||||
// ---- 单用户 CRUD ----
|
// ---- 单用户 CRUD ----
|
||||||
function openCreate() {
|
function openCreate() {
|
||||||
editing.value = null
|
editing.value = null
|
||||||
@@ -290,16 +323,22 @@ async function doLDAPImport() {
|
|||||||
// ---- LDAP 配置 ----
|
// ---- LDAP 配置 ----
|
||||||
async function saveLDAP() {
|
async function saveLDAP() {
|
||||||
try {
|
try {
|
||||||
await api.put('/ldap', ldap.value)
|
if (ldap.value.enabled && !ldapTested.value) return ElMessage.warning(t('users.ldapTestRequired'))
|
||||||
|
await api.put('/ldap', ldapPayload())
|
||||||
ldap.value.bind_password = ''
|
ldap.value.bind_password = ''
|
||||||
ElMessage.success(t('users.ldapConfigSaved'))
|
ElMessage.success(t('users.ldapConfigSaved'))
|
||||||
} catch (e) { ElMessage.error(e.response?.data?.error || t('common.saveFailed')) }
|
} catch (e) { ElMessage.error(e.response?.data?.error || t('common.saveFailed')) }
|
||||||
}
|
}
|
||||||
async function testLDAP() {
|
async function testLDAP() {
|
||||||
|
ldapTesting.value = true
|
||||||
try {
|
try {
|
||||||
await api.post('/ldap/test')
|
await api.post('/ldap/test', ldapPayload())
|
||||||
|
ldapTested.value = true
|
||||||
ElMessage.success(t('users.ldapConnected'))
|
ElMessage.success(t('users.ldapConnected'))
|
||||||
} catch (e) { ElMessage.error(e.response?.data?.error || t('users.ldapConnectFailed')) }
|
} catch (e) {
|
||||||
|
ldapTested.value = false
|
||||||
|
ElMessage.error(e.response?.data?.error || t('users.ldapConnectFailed'))
|
||||||
|
} finally { ldapTesting.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(load)
|
onMounted(load)
|
||||||
|
|||||||
+10
-1
@@ -1,8 +1,17 @@
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import vue from '@vitejs/plugin-vue'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
|
||||||
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue()],
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
VueI18nPlugin({
|
||||||
|
include: [fileURLToPath(new URL('./src/locales/**', import.meta.url))],
|
||||||
|
runtimeOnly: true,
|
||||||
|
jitCompilation: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
server: {
|
server: {
|
||||||
port: 5173,
|
port: 5173,
|
||||||
proxy: { '/api': 'http://localhost:8080' }
|
proxy: { '/api': 'http://localhost:8080' }
|
||||||
|
|||||||
Reference in new issue
Block a user