diff --git a/.gitignore b/.gitignore index 458da062..35db31f9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # workspace go.work +go.work* diff --git a/Dockerfile b/Dockerfile index 6b0e9683..e2ea2a9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,20 @@ # syntax=docker/dockerfile:1 - -ARG GO_VERSION=1.21 +# Copyright (C) 2023 Kevin Z +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +ARG GO_VERSION=1.23 ARG REPO=github.com/LiterMC/go-openbmclapi ARG NPM_DIR=dashboard @@ -23,6 +37,7 @@ ARG NPM_DIR WORKDIR "/go/src/${REPO}/" +ENV CGO_ENABLED=0 COPY ./go.mod ./go.sum "/go/src/${REPO}/" RUN go mod download COPY . "/go/src/${REPO}" @@ -31,7 +46,7 @@ COPY --from=WEB_BUILD "/web/dist" "/go/src/${REPO}/${NPM_DIR}/dist" ENV ldflags="-X 'github.com/LiterMC/go-openbmclapi/internal/build.BuildVersion=$TAG'" RUN --mount=type=cache,target=/root/.cache/go-build \ - CGO_ENABLED=0 go build -v -o "/go/bin/go-openbmclapi" -ldflags="$ldflags" "." + go build -v -o "/go/bin/go-openbmclapi" -ldflags="$ldflags" "." FROM alpine:latest @@ -40,4 +55,4 @@ COPY ./config.yaml /opt/openbmclapi/config.yaml COPY --from=BUILD "/go/bin/go-openbmclapi" "/go-openbmclapi" -CMD ["/go-openbmclapi"] +ENTRYPOINT ["/go-openbmclapi"] diff --git a/README.MD b/README.MD index 8454a49a..581470d7 100644 --- a/README.MD +++ b/README.MD @@ -63,7 +63,7 @@ A: 请确认中间所有的反向代理都支持 WebSocket ### 无依赖直接运行 1. 从 [Github Release](https://github.com/LiterMC/go-openbmclapi/releases/latest) 找到**适合您服务器平台**的程序并下载到节点服务器上 -2. 配置配置文件, 可以直接使用与bangbang93的openbmclapi相同的环境变量配置, 也可以从`config.yaml`进行配置 _(下文有讲)_ +2. 配置 `config.yaml` 配置文件 _(下文有讲)_ 3. 运行程序 ### 从docker运行 @@ -79,7 +79,6 @@ A: 请确认中间所有的反向代理都支持 WebSocket ```sh curl -fsSL https://raw.githubusercontent.com/LiterMC/go-openbmclapi/HEAD/installer/service/installer.sh | sudo bash -s ``` - > 注意, 新版新增使用 `openbmclapi` 用户执行程序, 可能需要执行 `sudo chown -R openbmclapi /opt/openbmclapi` 指令修复权限 国内对 Github 的支持较差, 可以使用 ghproxy 等镜像站运行脚本, 本例中使用了 [crashmc.com](https://crashmc.com) 提供的 CDN: ```sh @@ -89,7 +88,7 @@ A: 请确认中间所有的反向代理都支持 WebSocket 如果需要下载指定版本, 只需设置 `-t|--tag` 标志即可 ```sh - curl -fsSL https://raw.githubusercontent.com/LiterMC/go-openbmclapi/HEAD/installer/service/installer.sh | sudo bash -s -- --tag v1.9.7-8 + curl -fsSL https://raw.githubusercontent.com/LiterMC/go-openbmclapi/HEAD/installer/service/installer.sh | sudo bash -s -- --tag v1.13.1-2 ``` 3. 配置`/opt/openbmclapi/config.yaml`配置文件 4. 使用`systemctl start go-openbmclapi.service`启动服务 @@ -101,7 +100,7 @@ A: 请确认中间所有的反向代理都支持 WebSocket ### 从源代码运行 -1. 确保您的服务器上装有 `go 1.21+` 以及 `node & npm` +1. 确保您的服务器上装有 `go 1.23+` 以及 `node & npm` 2. 下载本仓库 _(可以使用`git clone https://github.com/LiterMC/go-openbmclapi.git`)_ 3. cd 进入本仓库 4. 配置配置文件或环境变量 @@ -176,8 +175,8 @@ tunneler: # 缓存 cache: # 缓存类型: - # nocache: 不缓存 - # inmem: 程序内内存缓存 + # no-cache: 不缓存 + # memory: 程序内内存缓存 # redis: Redis 缓存 type: redis # 如果使用 Redis 缓存则还需要配置用户名密码等: diff --git a/api.go b/api.go deleted file mode 100644 index 7d52ddf9..00000000 --- a/api.go +++ /dev/null @@ -1,1185 +0,0 @@ -/** - * OpenBmclAPI (Golang Edition) - * Copyright (C) 2023 Kevin Z - * All rights reserved - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package main - -import ( - "compress/gzip" - "context" - "crypto/subtle" - "encoding/json" - "errors" - "fmt" - "io" - "mime" - "net/http" - "os" - "path/filepath" - "strconv" - "strings" - "sync/atomic" - "time" - - "runtime/pprof" - // "github.com/gorilla/websocket" - "github.com/google/uuid" - - "github.com/LiterMC/go-openbmclapi/database" - "github.com/LiterMC/go-openbmclapi/internal/build" - "github.com/LiterMC/go-openbmclapi/limited" - "github.com/LiterMC/go-openbmclapi/log" - "github.com/LiterMC/go-openbmclapi/notify" - "github.com/LiterMC/go-openbmclapi/utils" -) - -const ( - clientIdCookieName = "_id" - - clientIdKey = "go-openbmclapi.cluster.client.id" -) - -func apiGetClientId(req *http.Request) (id string) { - return req.Context().Value(clientIdKey).(string) -} - -func (cr *Cluster) cliIdHandle(next http.Handler) http.Handler { - return (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { - var id string - if cid, _ := req.Cookie(clientIdCookieName); cid != nil { - id = cid.Value - } else { - var err error - id, err = utils.GenRandB64(16) - if err != nil { - http.Error(rw, "cannot generate random number", http.StatusInternalServerError) - return - } - http.SetCookie(rw, &http.Cookie{ - Name: clientIdCookieName, - Value: id, - Expires: time.Now().Add(time.Hour * 24 * 365 * 16), - Secure: true, - HttpOnly: true, - }) - } - req = req.WithContext(context.WithValue(req.Context(), clientIdKey, utils.AsSha256(id))) - next.ServeHTTP(rw, req) - }) -} - -func (cr *Cluster) authMiddleware(rw http.ResponseWriter, req *http.Request, next http.Handler) { - cli := apiGetClientId(req) - - ctx := req.Context() - - var ( - id string - uid string - err error - ) - if req.Method == http.MethodGet { - if tk := req.URL.Query().Get("_t"); tk != "" { - path := GetRequestRealPath(req) - if id, uid, err = cr.verifyAPIToken(cli, tk, path, req.URL.Query()); err == nil { - ctx = context.WithValue(ctx, tokenTypeKey, tokenTypeAPI) - } - } - } - if id == "" { - auth := req.Header.Get("Authorization") - tk, ok := strings.CutPrefix(auth, "Bearer ") - if !ok { - if err == nil { - err = ErrUnsupportAuthType - } - } else if id, uid, err = cr.verifyAuthToken(cli, tk); err != nil { - id = "" - } else { - ctx = context.WithValue(ctx, tokenTypeKey, tokenTypeAuth) - } - } - if id != "" { - ctx = context.WithValue(ctx, loggedUserKey, uid) - ctx = context.WithValue(ctx, tokenIdKey, id) - req = req.WithContext(ctx) - } - next.ServeHTTP(rw, req) -} - -func (cr *Cluster) apiAuthHandle(next http.Handler) http.Handler { - return (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { - if req.Context().Value(tokenTypeKey) == nil { - writeJson(rw, http.StatusUnauthorized, Map{ - "error": "403 Unauthorized", - }) - return - } - next.ServeHTTP(rw, req) - }) -} - -func (cr *Cluster) apiAuthHandleFunc(next http.HandlerFunc) http.Handler { - return cr.apiAuthHandle(next) -} - -func (cr *Cluster) initAPIv0() http.Handler { - mux := http.NewServeMux() - mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) { - writeJson(rw, http.StatusNotFound, Map{ - "error": "404 not found", - "path": req.URL.Path, - }) - }) - - mux.HandleFunc("/ping", cr.apiV1Ping) - mux.HandleFunc("/status", cr.apiV0Status) - mux.Handle("/stat/", http.StripPrefix("/stat/", (http.HandlerFunc)(cr.apiV0Stat))) - - mux.HandleFunc("/challenge", cr.apiV1Challenge) - mux.HandleFunc("/login", cr.apiV0Login) - mux.Handle("/requestToken", cr.apiAuthHandleFunc(cr.apiV0RequestToken)) - mux.Handle("/logout", cr.apiAuthHandleFunc(cr.apiV1Logout)) - - mux.HandleFunc("/log.io", cr.apiV1LogIO) - mux.Handle("/pprof", cr.apiAuthHandleFunc(cr.apiV1Pprof)) - mux.HandleFunc("/subscribeKey", cr.apiV0SubscribeKey) - mux.Handle("/subscribe", cr.apiAuthHandleFunc(cr.apiV0Subscribe)) - mux.Handle("/subscribe_email", cr.apiAuthHandleFunc(cr.apiV0SubscribeEmail)) - mux.Handle("/webhook", cr.apiAuthHandleFunc(cr.apiV0Webhook)) - - mux.Handle("/log_files", cr.apiAuthHandleFunc(cr.apiV0LogFiles)) - mux.Handle("/log_file/", cr.apiAuthHandle(http.StripPrefix("/log_file/", (http.HandlerFunc)(cr.apiV0LogFile)))) - - next := cr.apiRateLimiter.WrapHandler(mux) - return (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { - cr.authMiddleware(rw, req, next) - }) -} - -func (cr *Cluster) initAPIv1() http.Handler { - mux := http.NewServeMux() - mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) { - writeJson(rw, http.StatusNotFound, Map{ - "error": "404 not found", - "path": req.URL.Path, - }) - }) - - mux.HandleFunc("/ping", cr.apiV1Ping) - - mux.HandleFunc("/challenge", cr.apiV1Challenge) - mux.Handle("/logout", cr.apiAuthHandleFunc(cr.apiV1Logout)) - - mux.HandleFunc("/log.io", cr.apiV1LogIO) - mux.Handle("/pprof", cr.apiAuthHandleFunc(cr.apiV1Pprof)) - - next := cr.apiRateLimiter.WrapHandler(mux) - return (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { - cr.authMiddleware(rw, req, next) - }) -} - -func (cr *Cluster) apiV1Ping(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - limited.SetSkipRateLimit(req) - authed := getRequestTokenType(req) == tokenTypeAuth - writeJson(rw, http.StatusOK, Map{ - "version": build.BuildVersion, - "time": time.Now().UnixMilli(), - "authed": authed, - }) -} - -func (cr *Cluster) apiV0Status(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - limited.SetSkipRateLimit(req) - type syncData struct { - Prog int64 `json:"prog"` - Total int64 `json:"total"` - } - type statusData struct { - StartAt time.Time `json:"startAt"` - Stats *notify.Stats `json:"stats"` - Enabled bool `json:"enabled"` - IsSync bool `json:"isSync"` - Sync *syncData `json:"sync,omitempty"` - Storages []string `json:"storages"` - } - storages := make([]string, len(cr.storageOpts)) - for i, opt := range cr.storageOpts { - storages[i] = opt.Id - } - status := statusData{ - StartAt: startTime, - Stats: &cr.stats, - Enabled: cr.enabled.Load(), - IsSync: cr.issync.Load(), - Storages: storages, - } - if status.IsSync { - status.Sync = &syncData{ - Prog: cr.syncProg.Load(), - Total: cr.syncTotal.Load(), - } - } - writeJson(rw, http.StatusOK, &status) -} - -func (cr *Cluster) apiV0Stat(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - limited.SetSkipRateLimit(req) - name := req.URL.Path - if name == "" { - rw.Header().Set("Cache-Control", "public, max-age=60") - writeJson(rw, http.StatusOK, &cr.stats) - return - } - data, err := cr.stats.MarshalSubStat(name) - if err != nil { - http.Error(rw, "Error when encoding response: "+err.Error(), http.StatusInternalServerError) - return - } - rw.Header().Set("Cache-Control", "public, max-age=30") - writeJson(rw, http.StatusOK, (json.RawMessage)(data)) -} - -func (cr *Cluster) apiV1Challenge(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - cli := apiGetClientId(req) - query := req.URL.Query() - action := query.Get("action") - token, err := cr.generateChallengeToken(cli, action) - if err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "Cannot generate token", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, Map{ - "token": token, - }) -} - -func (cr *Cluster) apiV0Login(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodPost) { - return - } - if !config.Dashboard.Enable { - writeJson(rw, http.StatusServiceUnavailable, Map{ - "error": "dashboard is disabled in the config", - }) - return - } - cli := apiGetClientId(req) - - type T = struct { - User string `json:"username"` - Challenge string `json:"challenge"` - Signature string `json:"signature"` - } - data, ok := parseRequestBody(rw, req, func(rw http.ResponseWriter, req *http.Request, ct string, data *T) error { - switch ct { - case "application/x-www-form-urlencoded": - data.User = req.PostFormValue("username") - data.Challenge = req.PostFormValue("challenge") - data.Signature = req.PostFormValue("signature") - return nil - default: - return errUnknownContent - } - }) - if !ok { - return - } - - expectUsername, expectPassword := config.Dashboard.Username, config.Dashboard.Password - if expectUsername == "" || expectPassword == "" { - writeJson(rw, http.StatusUnauthorized, Map{ - "error": "The username or password was not set on the server", - }) - return - } - - if err := cr.verifyChallengeToken(cli, "login", data.Challenge); err != nil { - writeJson(rw, http.StatusUnauthorized, Map{ - "error": "Invalid challenge", - }) - return - } - expectPassword = utils.AsSha256Hex(expectPassword) - expectSignature := utils.HMACSha256Hex(expectPassword, data.Challenge) - if subtle.ConstantTimeCompare(([]byte)(expectUsername), ([]byte)(data.User)) == 0 || - subtle.ConstantTimeCompare(([]byte)(expectSignature), ([]byte)(data.Signature)) == 0 { - writeJson(rw, http.StatusUnauthorized, Map{ - "error": "The username or password is incorrect", - }) - return - } - token, err := cr.generateAuthToken(cli, data.User) - if err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "Cannot generate token", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, Map{ - "token": token, - }) -} - -func (cr *Cluster) apiV0RequestToken(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodPost) { - return - } - defer req.Body.Close() - if getRequestTokenType(req) != tokenTypeAuth { - writeJson(rw, http.StatusUnauthorized, Map{ - "error": "invalid authorization type", - }) - return - } - - var payload struct { - Path string `json:"path"` - Query map[string]string `json:"query,omitempty"` - } - if err := json.NewDecoder(req.Body).Decode(&payload); err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "cannot decode payload in json format", - "message": err.Error(), - }) - } - log.Debugf("payload: %#v", payload) - if payload.Path == "" || payload.Path[0] != '/' { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "path is invalid", - "message": "'path' must be a non empty string which starts with '/'", - }) - return - } - cli := apiGetClientId(req) - user := getLoggedUser(req) - token, err := cr.generateAPIToken(cli, user, payload.Path, payload.Query) - if err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "cannot generate token", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, Map{ - "token": token, - }) -} - -func (cr *Cluster) apiV1Logout(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodPost) { - return - } - limited.SetSkipRateLimit(req) - tid := req.Context().Value(tokenIdKey).(string) - cr.database.RemoveJTI(tid) - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV1LogIO(rw http.ResponseWriter, req *http.Request) { - addr, _ := req.Context().Value(RealAddrCtxKey).(string) - - conn, err := cr.wsUpgrader.Upgrade(rw, req, nil) - if err != nil { - log.Debugf("[log.io]: Websocket upgrade error: %v", err) - http.Error(rw, err.Error(), http.StatusInternalServerError) - return - } - defer conn.Close() - - cli := apiGetClientId(req) - - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - - conn.SetReadLimit(1024 * 4) - pongTimeoutTimer := time.NewTimer(time.Second * 75) - go func() { - defer conn.Close() - defer cancel() - defer pongTimeoutTimer.Stop() - select { - case _, ok := <-pongTimeoutTimer.C: - if !ok { - return - } - log.Error("[log.io]: Did not receive packet from client longer than 75s") - return - case <-ctx.Done(): - return - } - }() - - var authData struct { - Token string `json:"token"` - } - deadline := time.Now().Add(time.Second * 10) - conn.SetReadDeadline(deadline) - err = conn.ReadJSON(&authData) - conn.SetReadDeadline(time.Time{}) - if err != nil { - if time.Now().After(deadline) { - conn.WriteJSON(Map{ - "type": "error", - "message": "auth timeout", - }) - } else { - conn.WriteJSON(Map{ - "type": "error", - "message": "unexpected auth data: " + err.Error(), - }) - } - return - } - if _, _, err = cr.verifyAuthToken(cli, authData.Token); err != nil { - conn.WriteJSON(Map{ - "type": "error", - "message": "auth failed", - }) - return - } - if err := conn.WriteJSON(Map{ - "type": "ready", - }); err != nil { - return - } - - var level atomic.Int32 - level.Store((int32)(log.LevelInfo)) - - type logObj struct { - Type string `json:"type"` - Time int64 `json:"time"` // UnixMilli - Level string `json:"lvl"` - Log string `json:"log"` - } - c := make(chan *logObj, 64) - unregister := log.RegisterLogMonitor(log.LevelDebug, func(ts int64, l log.Level, msg string) { - if (log.Level)(level.Load()) > l&log.LevelMask { - return - } - select { - case c <- &logObj{ - Type: "log", - Time: ts, - Level: l.String(), - Log: msg, - }: - default: - } - }) - defer unregister() - - go func() { - defer log.RecoverPanic(nil) - defer conn.Close() - defer cancel() - var data map[string]any - for { - clear(data) - if err := conn.ReadJSON(&data); err != nil { - log.Errorf("[log.io]: Cannot read from peer: %v", err) - return - } - typ, ok := data["type"].(string) - if !ok { - continue - } - switch typ { - case "pong": - log.Debugf("[log.io]: received PONG from %s: %v", addr, data["data"]) - pongTimeoutTimer.Reset(time.Second * 75) - case "set-level": - l, ok := data["level"].(string) - if ok { - switch l { - case "DBUG": - level.Store((int32)(log.LevelDebug)) - case "INFO": - level.Store((int32)(log.LevelInfo)) - case "WARN": - level.Store((int32)(log.LevelWarn)) - case "ERRO": - level.Store((int32)(log.LevelError)) - default: - continue - } - select { - case c <- &logObj{ - Type: "log", - Time: time.Now().UnixMilli(), - Level: log.LevelInfo.String(), - Log: "[dashboard]: Set log level to " + l + " for this log.io", - }: - default: - } - } - } - } - }() - - sendMsgCh := make(chan any, 64) - go func() { - for { - select { - case v := <-c: - select { - case sendMsgCh <- v: - case <-ctx.Done(): - return - } - case <-ctx.Done(): - return - } - } - }() - - pingTicker := time.NewTicker(time.Second * 45) - defer pingTicker.Stop() - forceSendTimer := time.NewTimer(time.Second) - if !forceSendTimer.Stop() { - <-forceSendTimer.C - } - - batchMsg := make([]any, 0, 64) - for { - select { - case v := <-sendMsgCh: - batchMsg = append(batchMsg, v) - forceSendTimer.Reset(time.Second) - WAIT_MORE: - for { - select { - case v := <-sendMsgCh: - batchMsg = append(batchMsg, v) - case <-time.After(time.Millisecond * 20): - if !forceSendTimer.Stop() { - <-forceSendTimer.C - } - break WAIT_MORE - case <-forceSendTimer.C: - break WAIT_MORE - case <-ctx.Done(): - forceSendTimer.Stop() - return - } - } - if len(batchMsg) == 1 { - if err := conn.WriteJSON(batchMsg[0]); err != nil { - return - } - } else { - if err := conn.WriteJSON(batchMsg); err != nil { - return - } - } - // release objects - for i, _ := range batchMsg { - batchMsg[i] = nil - } - batchMsg = batchMsg[:0] - case <-pingTicker.C: - if err := conn.WriteJSON(Map{ - "type": "ping", - "data": time.Now().UnixMilli(), - }); err != nil { - log.Errorf("[log.io]: Error when sending ping packet: %v", err) - return - } - case <-ctx.Done(): - return - } - } -} - -func (cr *Cluster) apiV1Pprof(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - query := req.URL.Query() - lookup := query.Get("lookup") - p := pprof.Lookup(lookup) - if p == nil { - http.Error(rw, fmt.Sprintf("pprof.Lookup(%q) returned nil", lookup), http.StatusBadRequest) - return - } - view := query.Get("view") - debug, err := strconv.Atoi(query.Get("debug")) - if err != nil { - debug = 1 - } - if debug == 1 { - rw.Header().Set("Content-Type", "text/plain; charset=utf-8") - } else { - rw.Header().Set("Content-Type", "application/octet-stream") - } - if view != "1" { - name := fmt.Sprintf(time.Now().Format("dump-%s-20060102-150405"), lookup) - if debug == 1 { - name += ".txt" - } else { - name += ".dump" - } - rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name)) - } - rw.WriteHeader(http.StatusOK) - if debug == 1 { - fmt.Fprintf(rw, "version: %s (%s)\n", build.BuildVersion, build.ClusterVersion) - } - p.WriteTo(rw, debug) -} - -func (cr *Cluster) apiV0SubscribeKey(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - key := cr.webpushKeyB64 - etag := `"` + utils.AsSha256(key) + `"` - rw.Header().Set("ETag", etag) - if cachedTag := req.Header.Get("If-None-Match"); cachedTag == etag { - rw.WriteHeader(http.StatusNotModified) - return - } - writeJson(rw, http.StatusOK, Map{ - "publicKey": key, - }) -} - -func (cr *Cluster) apiV0Subscribe(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet, http.MethodPost, http.MethodDelete) { - return - } - cliId := apiGetClientId(req) - user := getLoggedUser(req) - if user == "" { - writeJson(rw, http.StatusForbidden, Map{ - "error": "Unauthorized", - }) - return - } - switch req.Method { - case http.MethodGet: - cr.apiV0SubscribeGET(rw, req, user, cliId) - case http.MethodPost: - cr.apiV0SubscribePOST(rw, req, user, cliId) - case http.MethodDelete: - cr.apiV0SubscribeDELETE(rw, req, user, cliId) - default: - panic("unreachable") - } -} - -func (cr *Cluster) apiV0SubscribeGET(rw http.ResponseWriter, req *http.Request, user string, client string) { - record, err := cr.database.GetSubscribe(user, client) - if err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no subscription was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, Map{ - "scopes": record.Scopes, - "reportAt": record.ReportAt, - }) -} - -func (cr *Cluster) apiV0SubscribePOST(rw http.ResponseWriter, req *http.Request, user string, client string) { - data, ok := parseRequestBody[database.SubscribeRecord](rw, req, nil) - if !ok { - return - } - data.User = user - data.Client = client - if err := cr.database.SetSubscribe(data); err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "Database update failed", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0SubscribeDELETE(rw http.ResponseWriter, req *http.Request, user string, client string) { - if err := cr.database.RemoveSubscribe(user, client); err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no subscription was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0SubscribeEmail(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet, http.MethodPost, http.MethodPatch, http.MethodDelete) { - return - } - user := getLoggedUser(req) - if user == "" { - writeJson(rw, http.StatusForbidden, Map{ - "error": "Unauthorized", - }) - return - } - switch req.Method { - case http.MethodGet: - cr.apiV0SubscribeEmailGET(rw, req, user) - case http.MethodPost: - cr.apiV0SubscribeEmailPOST(rw, req, user) - case http.MethodPatch: - cr.apiV0SubscribeEmailPATCH(rw, req, user) - case http.MethodDelete: - cr.apiV0SubscribeEmailDELETE(rw, req, user) - default: - panic("unreachable") - } -} - -func (cr *Cluster) apiV0SubscribeEmailGET(rw http.ResponseWriter, req *http.Request, user string) { - if addr := req.URL.Query().Get("addr"); addr != "" { - record, err := cr.database.GetEmailSubscription(user, addr) - if err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no email subscription was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, record) - return - } - records := make([]database.EmailSubscriptionRecord, 0, 4) - if err := cr.database.ForEachUsersEmailSubscription(user, func(rec *database.EmailSubscriptionRecord) error { - records = append(records, *rec) - return nil - }); err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, records) -} - -func (cr *Cluster) apiV0SubscribeEmailPOST(rw http.ResponseWriter, req *http.Request, user string) { - data, ok := parseRequestBody[database.EmailSubscriptionRecord](rw, req, nil) - if !ok { - return - } - - data.User = user - if err := cr.database.AddEmailSubscription(data); err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "Database update failed", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusCreated) -} - -func (cr *Cluster) apiV0SubscribeEmailPATCH(rw http.ResponseWriter, req *http.Request, user string) { - addr := req.URL.Query().Get("addr") - data, ok := parseRequestBody[database.EmailSubscriptionRecord](rw, req, nil) - if !ok { - return - } - data.User = user - data.Addr = addr - if err := cr.database.UpdateEmailSubscription(data); err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no email subscription was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0SubscribeEmailDELETE(rw http.ResponseWriter, req *http.Request, user string) { - addr := req.URL.Query().Get("addr") - if err := cr.database.RemoveEmailSubscription(user, addr); err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no email subscription was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0Webhook(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet, http.MethodPost, http.MethodPatch, http.MethodDelete) { - return - } - user := getLoggedUser(req) - if user == "" { - writeJson(rw, http.StatusForbidden, Map{ - "error": "Unauthorized", - }) - return - } - switch req.Method { - case http.MethodGet: - cr.apiV0WebhookGET(rw, req, user) - case http.MethodPost: - cr.apiV0WebhookPOST(rw, req, user) - case http.MethodPatch: - cr.apiV0WebhookPATCH(rw, req, user) - case http.MethodDelete: - cr.apiV0WebhookDELETE(rw, req, user) - default: - panic("unreachable") - } -} - -func (cr *Cluster) apiV0WebhookGET(rw http.ResponseWriter, req *http.Request, user string) { - if sid := req.URL.Query().Get("id"); sid != "" { - id, err := uuid.Parse(sid) - if err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "uuid format error", - "message": err.Error(), - }) - return - } - record, err := cr.database.GetWebhook(user, id) - if err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no webhook was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, record) - return - } - records := make([]database.WebhookRecord, 0, 4) - if err := cr.database.ForEachUsersWebhook(user, func(rec *database.WebhookRecord) error { - records = append(records, *rec) - return nil - }); err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - writeJson(rw, http.StatusOK, records) -} - -func (cr *Cluster) apiV0WebhookPOST(rw http.ResponseWriter, req *http.Request, user string) { - data, ok := parseRequestBody[database.WebhookRecord](rw, req, nil) - if !ok { - return - } - - data.User = user - if err := cr.database.AddWebhook(data); err != nil { - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "Database update failed", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusCreated) -} - -func (cr *Cluster) apiV0WebhookPATCH(rw http.ResponseWriter, req *http.Request, user string) { - id := req.URL.Query().Get("id") - data, ok := parseRequestBody[database.WebhookRecord](rw, req, nil) - if !ok { - return - } - data.User = user - var err error - if data.Id, err = uuid.Parse(id); err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "uuid format error", - "message": err.Error(), - }) - return - } - if err := cr.database.UpdateWebhook(data); err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no webhook was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0WebhookDELETE(rw http.ResponseWriter, req *http.Request, user string) { - id, err := uuid.Parse(req.URL.Query().Get("id")) - if err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "uuid format error", - "message": err.Error(), - }) - return - } - if err := cr.database.RemoveWebhook(user, id); err != nil { - if err == database.ErrNotFound { - writeJson(rw, http.StatusNotFound, Map{ - "error": "no webhook was found", - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "database error", - "message": err.Error(), - }) - return - } - rw.WriteHeader(http.StatusNoContent) -} - -func (cr *Cluster) apiV0LogFiles(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet) { - return - } - files := log.ListLogs() - type FileInfo struct { - Name string `json:"name"` - Size int64 `json:"size"` - } - data := make([]FileInfo, 0, len(files)) - for _, file := range files { - if s, err := os.Stat(filepath.Join(log.BaseDir(), file)); err == nil { - data = append(data, FileInfo{ - Name: file, - Size: s.Size(), - }) - } - } - writeJson(rw, http.StatusOK, Map{ - "files": data, - }) -} - -func (cr *Cluster) apiV0LogFile(rw http.ResponseWriter, req *http.Request) { - if checkRequestMethodOrRejectWithJson(rw, req, http.MethodGet, http.MethodHead) { - return - } - query := req.URL.Query() - fd, err := os.Open(filepath.Join(log.BaseDir(), req.URL.Path)) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - writeJson(rw, http.StatusNotFound, Map{ - "error": "file not exists", - "message": "Cannot find log file", - "path": req.URL.Path, - }) - return - } - writeJson(rw, http.StatusInternalServerError, Map{ - "error": "cannot open file", - "message": err.Error(), - }) - return - } - defer fd.Close() - name := filepath.Base(req.URL.Path) - isGzip := filepath.Ext(name) == ".gz" - if query.Get("no_encrypt") == "1" { - var modTime time.Time - if stat, err := fd.Stat(); err == nil { - modTime = stat.ModTime() - } - rw.Header().Set("Cache-Control", "public, max-age=60, stale-while-revalidate=600") - if isGzip { - rw.Header().Set("Content-Type", "application/octet-stream") - } else { - rw.Header().Set("Content-Type", "text/plain; charset=utf-8") - } - rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name)) - http.ServeContent(rw, req, name, modTime, fd) - } else { - if !isGzip { - name += ".gz" - } - rw.Header().Set("Content-Type", "application/octet-stream") - rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name+".encrypted")) - cr.apiV0LogFileEncrypted(rw, req, fd, !isGzip) - } -} - -func (cr *Cluster) apiV0LogFileEncrypted(rw http.ResponseWriter, req *http.Request, r io.Reader, useGzip bool) { - rw.WriteHeader(http.StatusOK) - if req.Method == http.MethodHead { - return - } - if useGzip { - pr, pw := io.Pipe() - defer pr.Close() - go func(r io.Reader) { - gw := gzip.NewWriter(pw) - if _, err := io.Copy(gw, r); err != nil { - pw.CloseWithError(err) - return - } - if err := gw.Close(); err != nil { - pw.CloseWithError(err) - return - } - pw.Close() - }(r) - r = pr - } - if err := utils.EncryptStream(rw, r, utils.DeveloporPublicKey); err != nil { - log.Errorf("Cannot write encrypted log stream: %v", err) - } -} - -type Map = map[string]any - -var errUnknownContent = errors.New("unknown content-type") - -type requestBodyParser[T any] func(rw http.ResponseWriter, req *http.Request, contentType string, data *T) error - -func parseRequestBody[T any](rw http.ResponseWriter, req *http.Request, fallback requestBodyParser[T]) (data T, parsed bool) { - contentType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) - if err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "Unexpected Content-Type", - "content-type": req.Header.Get("Content-Type"), - "message": err.Error(), - }) - return - } - switch contentType { - case "application/json": - if err := json.NewDecoder(req.Body).Decode(&data); err != nil { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "Cannot decode request body", - "message": err.Error(), - }) - return - } - return data, true - default: - if fallback != nil { - if err := fallback(rw, req, contentType, &data); err == nil { - return data, true - } else if err != errUnknownContent { - writeJson(rw, http.StatusBadRequest, Map{ - "error": "Cannot decode request body", - "message": err.Error(), - }) - return - } - } - writeJson(rw, http.StatusBadRequest, Map{ - "error": "Unexpected Content-Type", - "content-type": contentType, - }) - return - } -} - -func writeJson(rw http.ResponseWriter, code int, data any) (err error) { - buf, err := json.Marshal(data) - if err != nil { - http.Error(rw, "Error when encoding response: "+err.Error(), http.StatusInternalServerError) - return - } - rw.Header().Set("Content-Type", "application/json") - rw.Header().Set("Content-Length", strconv.Itoa(len(buf))) - rw.WriteHeader(code) - _, err = rw.Write(buf) - return -} - -func checkRequestMethodOrRejectWithJson(rw http.ResponseWriter, req *http.Request, allows ...string) (rejected bool) { - m := req.Method - for _, a := range allows { - if m == a { - return false - } - } - rw.Header().Set("Allow", strings.Join(allows, ", ")) - writeJson(rw, http.StatusMethodNotAllowed, Map{ - "error": "405 method not allowed", - "method": m, - "allow": allows, - }) - return true -} diff --git a/hijacker.go b/api/bmclapi/hijacker.go similarity index 87% rename from hijacker.go rename to api/bmclapi/hijacker.go index 6cc78049..3218c2b0 100644 --- a/hijacker.go +++ b/api/bmclapi/hijacker.go @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package main +package bmclapi import ( "context" @@ -33,6 +33,7 @@ import ( "sync" "time" + "github.com/LiterMC/go-openbmclapi/config" "github.com/LiterMC/go-openbmclapi/database" "github.com/LiterMC/go-openbmclapi/utils" ) @@ -52,6 +53,11 @@ func getDialerWithDNS(dnsaddr string) *net.Dialer { type downloadHandlerFn = func(rw http.ResponseWriter, req *http.Request, hash string) type HjProxy struct { + RequireAuth bool + AuthUsers []config.UserItem + EnableLocalCache bool + LocalCachePath string + client *http.Client fileMap database.DB downloadHandler downloadHandlerFn @@ -76,11 +82,11 @@ func NewHjProxy(client *http.Client, fileMap database.DB, downloadHandler downlo return } -func hjResponseWithCache(rw http.ResponseWriter, req *http.Request, c *cacheStat, force bool) (ok bool) { +func (h *HjProxy) hjResponseWithCache(rw http.ResponseWriter, req *http.Request, c *cacheStat, force bool) (ok bool) { if c == nil { return false } - cacheFileName := filepath.Join(config.Hijack.LocalCachePath, filepath.FromSlash(req.URL.Path)) + cacheFileName := filepath.Join(h.LocalCachePath, filepath.FromSlash(req.URL.Path)) age := c.ExpiresAt - time.Now().Unix() if !force && age <= 0 { return false @@ -107,15 +113,11 @@ func hjResponseWithCache(rw http.ResponseWriter, req *http.Request, c *cacheStat const hijackingHost = "bmclapi2.bangbang93.com" func (h *HjProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - if !config.Hijack.Enable { - http.Error(rw, "Hijack is disabled in the config", http.StatusServiceUnavailable) - return - } - if config.Hijack.RequireAuth { + if h.RequireAuth { needAuth := true user, passwd, ok := req.BasicAuth() if ok { - for _, u := range config.Hijack.AuthUsers { + for _, u := range h.AuthUsers { if u.Username == user && utils.ComparePasswd(u.Password, passwd) { needAuth = false return @@ -139,9 +141,9 @@ func (h *HjProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { nowUnix := time.Now().Unix() - cacheFileName := filepath.Join(config.Hijack.LocalCachePath, filepath.FromSlash(req.URL.Path)) + cacheFileName := filepath.Join(h.LocalCachePath, filepath.FromSlash(req.URL.Path)) cached := h.getCache(req.URL.Path) - if hjResponseWithCache(rw, req, cached, false) { + if h.hjResponseWithCache(rw, req, cached, false) { return } @@ -158,7 +160,7 @@ func (h *HjProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } res, err := h.client.Do(req2) if err != nil { - if hjResponseWithCache(rw, req, cached, true) { + if h.hjResponseWithCache(rw, req, cached, true) { return } http.Error(rw, "remote: "+err.Error(), http.StatusBadGateway) @@ -178,7 +180,7 @@ func (h *HjProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { } rw.WriteHeader(res.StatusCode) var body io.Reader = res.Body - if config.Hijack.EnableLocalCache && res.StatusCode == http.StatusOK { + if h.EnableLocalCache && res.StatusCode == http.StatusOK { if exp, ok := utils.ParseCacheControl(res.Header.Get("Cache-Control")); ok { if exp > 0 { os.MkdirAll(filepath.Dir(cacheFileName), 0755) @@ -211,7 +213,7 @@ type cacheStat struct { func (h *HjProxy) loadCache() (err error) { h.cache = make(map[string]*cacheStat) - fd, err := os.Open(filepath.Join(config.Hijack.LocalCachePath, "__cache.json")) + fd, err := os.Open(filepath.Join(h.LocalCachePath, "__cache.json")) if err != nil { return } @@ -220,7 +222,7 @@ func (h *HjProxy) loadCache() (err error) { } func (h *HjProxy) saveCache() (err error) { - fd, err := os.Create(filepath.Join(config.Hijack.LocalCachePath, "__cache.json")) + fd, err := os.Create(filepath.Join(h.LocalCachePath, "__cache.json")) if err != nil { return } diff --git a/api/cluster.go b/api/cluster.go new file mode 100644 index 00000000..31cd7a87 --- /dev/null +++ b/api/cluster.go @@ -0,0 +1,98 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "context" + "net/http" + + "github.com/LiterMC/go-openbmclapi/config" + "github.com/LiterMC/go-openbmclapi/storage" +) + +type ClusterStatus int32 + +const ( + ClusterDisconnected = iota + ClusterConnecting + ClusterDisabled + ClusterEnabling + ClusterEnabled +) + +// Disconnected returns true if the cluster is disconnected from the central server +func (s ClusterStatus) Disconnected() bool { + return s <= ClusterConnecting +} + +// Connected returns true if the cluster is connected to the central server +func (s ClusterStatus) Connected() bool { + return s > ClusterConnecting +} + +// Enabled returns true if the cluster is enabled or enabling +func (s ClusterStatus) Enabled() bool { + return s >= ClusterEnabling +} + +// Running returns true if the cluster is completely enabled +func (s ClusterStatus) Running() bool { + return s == ClusterEnabled +} + +type Cluster interface { + Name() string + ID() string + Secret() string + Host() string + Port() uint16 + PublicHosts() []string + Options() *config.ClusterOptions + + Status() ClusterStatus + Connect(context.Context) error + Disconnect(context.Context) error + Enable(context.Context) error + Disable(context.Context) error + + GetFileList(ctx context.Context, fileMap map[string]*StorageFileInfo, forceAll bool) error + ReportDownload(ctx context.Context, response *http.Response, err error) error +} + +type StorageFileInfo struct { + Hash string + Size int64 + Storages []storage.Storage + URLs map[string]RequestPath +} + +type RequestPath struct { + *http.Request + Cluster Cluster + Path string +} + +type ClusterManager interface { + GetClusters() []Cluster + GetCluster(name string) Cluster + AddCluster(name string, opts *config.ClusterOptions) error + UpdateCluster(name string, opts *config.ClusterOptions) error + RemoveCluster(name string) bool +} diff --git a/api/config.go b/api/config.go new file mode 100644 index 00000000..8d99aa3c --- /dev/null +++ b/api/config.go @@ -0,0 +1,41 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "errors" + + "github.com/LiterMC/go-openbmclapi/config" +) + +var ErrPreconditionFailed = errors.New("Precondition Failed") + +type ConfigHandler interface { + GetConfig() *config.Config + + MarshalJSON() (data []byte, err error) + UnmarshalJSON(data []byte) error + UnmarshalYAML(data []byte) error + MarshalJSONPath(path string) (data []byte, err error) + UnmarshalJSONPath(path string, data []byte) error + + DoReadLockedAction(callback func(ConfigHandler) error) error + DoWriteLockedAction(callback func(ConfigHandler) error) error +} diff --git a/exitcodes.go b/api/errors.go similarity index 62% rename from exitcodes.go rename to api/errors.go index 9d540825..3b0214d9 100644 --- a/exitcodes.go +++ b/api/errors.go @@ -17,19 +17,14 @@ * along with this program. If not, see . */ -package main +package api -const ( - CodeClientError = 0x01 - CodeServerError = 0x02 - CodeEnvironmentError = 0x04 - CodeUnexpectedError = 0x08 +import ( + "errors" ) -const ( - CodeClientOrServerError = CodeClientError | CodeServerError - CodeClientOrEnvionmentError = CodeClientError | CodeEnvironmentError - CodeClientUnexpectedError = CodeUnexpectedError | CodeClientError - CodeServerOrEnvionmentError = CodeServerError | CodeEnvironmentError - CodeServerUnexpectedError = CodeUnexpectedError | CodeServerError +var ( + ErrStopIter = errors.New("stop iteration") + ErrNotFound = errors.New("Item not found") + ErrExist = errors.New("Item is already exist") ) diff --git a/api/request.go b/api/request.go new file mode 100644 index 00000000..74588c34 --- /dev/null +++ b/api/request.go @@ -0,0 +1,45 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "net/http" +) + +const ( + RealAddrCtxKey = "handle.real.addr" + RealPathCtxKey = "handle.real.path" + AccessLogExtraCtxKey = "handle.access.extra" +) + +func GetRequestRealAddr(req *http.Request) string { + addr, _ := req.Context().Value(RealAddrCtxKey).(string) + return addr +} + +func GetRequestRealPath(req *http.Request) string { + return req.Context().Value(RealPathCtxKey).(string) +} + +func SetAccessInfo(req *http.Request, key string, value any) { + if info, ok := req.Context().Value(AccessLogExtraCtxKey).(map[string]any); ok { + info[key] = value + } +} diff --git a/api/stats.go b/api/stats.go new file mode 100644 index 00000000..f0cbaeeb --- /dev/null +++ b/api/stats.go @@ -0,0 +1,233 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "strconv" + "time" +) + +type StatsManager interface { + GetStatus() StatusData + // returns a cluster's stat data + // if name is empty then gets the overall access data + GetClusterAccessStat(name string) *AccessStatData + // returns a storage's stat data + // if name is empty then gets the overall access data + GetStorageAccessStat(name string) *AccessStatData +} + +type StatusData struct { + StartAt time.Time `json:"startAt"` + Clusters []string `json:"clusters"` + Storages []string `json:"storages"` +} + +type StatInstData struct { + Hits int32 `json:"hits"` + Bytes int64 `json:"bytes"` +} + +func (d *StatInstData) update(o *StatInstData) { + d.Hits += o.Hits + d.Bytes += o.Bytes +} + +// statTime always save a UTC time +type statTime struct { + Hour int `json:"hour"` + Day int `json:"day"` + Month int `json:"month"` + Year int `json:"year"` +} + +func makeStatTime(t time.Time) (st statTime) { + t = t.UTC() + st.Hour = t.Hour() + y, m, d := t.Date() + st.Day = d - 1 + st.Month = (int)(m) - 1 + st.Year = y + return +} + +func (t statTime) IsLastDay() bool { + return time.Date(t.Year, (time.Month)(t.Month+1), t.Day+1+1, 0, 0, 0, 0, time.UTC).Day() == 1 +} + +type ( + StatDataHours = [24]StatInstData + StatDataDays = [31]StatInstData + StatDataMonths = [12]StatInstData +) + +type AccessStatHistoryData struct { + Hours StatDataHours `json:"hours"` + Days StatDataDays `json:"days"` + Months StatDataMonths `json:"months"` +} + +type AccessStatData struct { + Date statTime `json:"date"` + AccessStatHistoryData + Prev AccessStatHistoryData `json:"prev"` + Years map[string]StatInstData `json:"years"` + + Accesses map[string]int `json:"accesses"` +} + +func NewAccessStatData() *AccessStatData { + return &AccessStatData{ + Years: make(map[string]StatInstData, 2), + Accesses: make(map[string]int, 5), + } +} + +func (d *AccessStatData) Clone() *AccessStatData { + cloned := new(AccessStatData) + *cloned = *d + cloned.Years = make(map[string]StatInstData, len(d.Years)) + for k, v := range d.Years { + cloned.Years[k] = v + } + cloned.Accesses = make(map[string]int, len(d.Accesses)) + for k, v := range d.Accesses { + cloned.Accesses[k] = v + } + return cloned +} + +func (d *AccessStatData) Update(newData *StatInstData) { + now := makeStatTime(time.Now()) + if d.Date.Year != 0 { + switch { + case d.Date.Year != now.Year: + iscont := now.Year == d.Date.Year+1 + isMonthCont := iscont && now.Month == 0 && d.Date.Month+1 == len(d.Months) + var inst StatInstData + for i := 0; i < d.Date.Month; i++ { + inst.update(&d.Months[i]) + } + if iscont { + for i := 0; i <= d.Date.Day; i++ { + inst.update(&d.Days[i]) + } + if isMonthCont { + for i := 0; i <= d.Date.Hour; i++ { + inst.update(&d.Hours[i]) + } + } + } + d.Years[strconv.Itoa(d.Date.Year)] = inst + // update history data + if iscont { + if isMonthCont { + if now.Day == 0 && d.Date.IsLastDay() { + d.Prev.Hours = d.Hours + for i := d.Date.Hour + 1; i < len(d.Hours); i++ { + d.Prev.Hours[i] = StatInstData{} + } + } else { + d.Prev.Hours = StatDataHours{} + } + d.Hours = StatDataHours{} + d.Prev.Days = d.Days + for i := d.Date.Day + 1; i < len(d.Days); i++ { + d.Prev.Days[i] = StatInstData{} + } + } else { + d.Prev.Days = StatDataDays{} + } + d.Days = StatDataDays{} + d.Prev.Months = d.Months + for i := d.Date.Month + 1; i < len(d.Months); i++ { + d.Prev.Months[i] = StatInstData{} + } + } else { + d.Prev.Months = StatDataMonths{} + } + d.Months = StatDataMonths{} + case d.Date.Month != now.Month: + iscont := now.Month == d.Date.Month+1 + var inst StatInstData + for i := 0; i < d.Date.Day; i++ { + inst.update(&d.Days[i]) + } + if iscont { + for i := 0; i <= d.Date.Hour; i++ { + inst.update(&d.Hours[i]) + } + } + d.Months[d.Date.Month] = inst + // clean up + for i := d.Date.Month + 1; i < now.Month; i++ { + d.Months[i] = StatInstData{} + } + clear(d.Accesses) + // update history data + if iscont { + if now.Day == 0 && d.Date.IsLastDay() { + d.Prev.Hours = d.Hours + for i := d.Date.Hour + 1; i < len(d.Hours); i++ { + d.Prev.Hours[i] = StatInstData{} + } + } else { + d.Prev.Hours = StatDataHours{} + } + d.Hours = StatDataHours{} + d.Prev.Days = d.Days + for i := d.Date.Day + 1; i < len(d.Days); i++ { + d.Prev.Days[i] = StatInstData{} + } + } else { + d.Prev.Days = StatDataDays{} + } + d.Days = StatDataDays{} + case d.Date.Day != now.Day: + var inst StatInstData + for i := 0; i <= d.Date.Hour; i++ { + inst.update(&d.Hours[i]) + } + d.Days[d.Date.Day] = inst + // clean up + for i := d.Date.Day + 1; i < now.Day; i++ { + d.Days[i] = StatInstData{} + } + // update history data + if now.Day == d.Date.Day+1 { + d.Prev.Hours = d.Hours + for i := d.Date.Hour + 1; i < len(d.Hours); i++ { + d.Prev.Hours[i] = StatInstData{} + } + } else { + d.Prev.Hours = StatDataHours{} + } + d.Hours = StatDataHours{} + case d.Date.Hour != now.Hour: + // clean up + for i := d.Date.Hour + 1; i < now.Hour; i++ { + d.Hours[i] = StatInstData{} + } + } + } + + d.Hours[now.Hour].update(newData) + d.Date = now +} diff --git a/api/subscription.go b/api/subscription.go new file mode 100644 index 00000000..2749c895 --- /dev/null +++ b/api/subscription.go @@ -0,0 +1,300 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/google/uuid" + + "github.com/LiterMC/go-openbmclapi/utils" +) + +type SubscriptionManager interface { + GetWebPushKey() string + + GetSubscribe(user string, client string) (*SubscribeRecord, error) + SetSubscribe(SubscribeRecord) error + RemoveSubscribe(user string, client string) error + ForEachSubscribe(cb func(*SubscribeRecord) error) error + + GetEmailSubscription(user string, addr string) (*EmailSubscriptionRecord, error) + AddEmailSubscription(EmailSubscriptionRecord) error + UpdateEmailSubscription(EmailSubscriptionRecord) error + RemoveEmailSubscription(user string, addr string) error + ForEachEmailSubscription(cb func(*EmailSubscriptionRecord) error) error + ForEachUsersEmailSubscription(user string, cb func(*EmailSubscriptionRecord) error) error + ForEachEnabledEmailSubscription(cb func(*EmailSubscriptionRecord) error) error + + GetWebhook(user string, id uuid.UUID) (*WebhookRecord, error) + AddWebhook(WebhookRecord) error + UpdateWebhook(WebhookRecord) error + UpdateEnableWebhook(user string, id uuid.UUID, enabled bool) error + RemoveWebhook(user string, id uuid.UUID) error + ForEachWebhook(cb func(*WebhookRecord) error) error + ForEachUsersWebhook(user string, cb func(*WebhookRecord) error) error + ForEachEnabledWebhook(cb func(*WebhookRecord) error) error +} + +type SubscribeRecord struct { + User string `json:"user"` + Client string `json:"client"` + EndPoint string `json:"endpoint"` + Keys SubscribeRecordKeys `json:"keys"` + Scopes NotificationScopes `json:"scopes"` + ReportAt Schedule `json:"report_at"` + LastReport sql.NullTime `json:"-"` +} + +type SubscribeRecordKeys struct { + Auth string `json:"auth"` + P256dh string `json:"p256dh"` +} + +var ( + _ sql.Scanner = (*SubscribeRecordKeys)(nil) + _ driver.Valuer = (*SubscribeRecordKeys)(nil) +) + +func (sk *SubscribeRecordKeys) Scan(src any) error { + var data []byte + switch v := src.(type) { + case []byte: + data = v + case string: + data = ([]byte)(v) + default: + return errors.New("Source is not a string") + } + return json.Unmarshal(data, sk) +} + +func (sk SubscribeRecordKeys) Value() (driver.Value, error) { + return json.Marshal(sk) +} + +type NotificationScopes struct { + Disabled bool `json:"disabled"` + Enabled bool `json:"enabled"` + SyncBegin bool `json:"syncbegin"` + SyncDone bool `json:"syncdone"` + Updates bool `json:"updates"` + DailyReport bool `json:"dailyreport"` +} + +var ( + _ sql.Scanner = (*NotificationScopes)(nil) + _ driver.Valuer = (*NotificationScopes)(nil) +) + +//// !!WARN: Do not edit nsFlag's order //// + +const ( + nsFlagDisabled = 1 << iota + nsFlagEnabled + nsFlagSyncDone + nsFlagUpdates + nsFlagDailyReport + nsFlagSyncBegin +) + +func (ns NotificationScopes) ToInt64() (v int64) { + if ns.Disabled { + v |= nsFlagDisabled + } + if ns.Enabled { + v |= nsFlagEnabled + } + if ns.SyncBegin { + v |= nsFlagSyncBegin + } + if ns.SyncDone { + v |= nsFlagSyncDone + } + if ns.Updates { + v |= nsFlagUpdates + } + if ns.DailyReport { + v |= nsFlagDailyReport + } + return +} + +func (ns *NotificationScopes) FromInt64(v int64) { + ns.Disabled = v&nsFlagDisabled != 0 + ns.Enabled = v&nsFlagEnabled != 0 + ns.SyncBegin = v&nsFlagSyncBegin != 0 + ns.SyncDone = v&nsFlagSyncDone != 0 + ns.Updates = v&nsFlagUpdates != 0 + ns.DailyReport = v&nsFlagDailyReport != 0 +} + +func (ns *NotificationScopes) Scan(src any) error { + v, ok := src.(int64) + if !ok { + return errors.New("Source is not a integer") + } + ns.FromInt64(v) + return nil +} + +func (ns NotificationScopes) Value() (driver.Value, error) { + return ns.ToInt64(), nil +} + +func (ns *NotificationScopes) FromStrings(scopes []string) { + for _, s := range scopes { + switch s { + case "disabled": + ns.Disabled = true + case "enabled": + ns.Enabled = true + case "syncbegin": + ns.SyncBegin = true + case "syncdone": + ns.SyncDone = true + case "updates": + ns.Updates = true + case "dailyreport": + ns.DailyReport = true + } + } +} + +func (ns *NotificationScopes) UnmarshalJSON(data []byte) (err error) { + { + type T NotificationScopes + if err = json.Unmarshal(data, (*T)(ns)); err == nil { + return + } + } + var v []string + if err = json.Unmarshal(data, &v); err != nil { + return + } + ns.FromStrings(v) + return +} + +type Schedule struct { + Hour int + Minute int +} + +var ( + _ sql.Scanner = (*Schedule)(nil) + _ driver.Valuer = (*Schedule)(nil) +) + +func (s Schedule) String() string { + return fmt.Sprintf("%02d:%02d", s.Hour, s.Minute) +} + +func (s *Schedule) UnmarshalText(buf []byte) (err error) { + if _, err = fmt.Sscanf((string)(buf), "%02d:%02d", &s.Hour, &s.Minute); err != nil { + return + } + if s.Hour < 0 || s.Hour >= 24 { + return fmt.Errorf("Hour %d out of range [0, 24)", s.Hour) + } + if s.Minute < 0 || s.Minute >= 60 { + return fmt.Errorf("Minute %d out of range [0, 60)", s.Minute) + } + return +} + +func (s *Schedule) UnmarshalJSON(buf []byte) (err error) { + var v string + if err = json.Unmarshal(buf, &v); err != nil { + return + } + return s.UnmarshalText(([]byte)(v)) +} + +func (s *Schedule) MarshalJSON() (buf []byte, err error) { + return json.Marshal(s.String()) +} + +func (s *Schedule) Scan(src any) error { + var v []byte + switch w := src.(type) { + case []byte: + v = w + case string: + v = ([]byte)(w) + default: + return fmt.Errorf("Unexpected type %T", src) + } + return s.UnmarshalText(v) +} + +func (s Schedule) Value() (driver.Value, error) { + return s.String(), nil +} + +func (s Schedule) ReadySince(last, now time.Time) bool { + if last.IsZero() { + last = now.Add(-time.Hour*24 + 1) + } + mustAfter := last.Add(time.Hour * 12) + if now.Before(mustAfter) { + return false + } + if !now.Before(last.Add(time.Hour * 24)) { + return true + } + hour, min := now.Hour(), now.Minute() + if s.Hour < hour && s.Hour+3 > hour || s.Hour == hour && s.Minute <= min { + return true + } + return false +} + +type EmailSubscriptionRecord struct { + User string `json:"user"` + Addr string `json:"addr"` + Scopes NotificationScopes `json:"scopes"` + Enabled bool `json:"enabled"` +} + +type WebhookRecord struct { + User string `json:"user"` + Id uuid.UUID `json:"id"` + Name string `json:"name"` + EndPoint string `json:"endpoint"` + Auth *string `json:"auth,omitempty"` + AuthHash string `json:"authHash,omitempty"` + Scopes NotificationScopes `json:"scopes"` + Enabled bool `json:"enabled"` +} + +func (rec *WebhookRecord) CovertAuthHash() { + if rec.Auth == nil || *rec.Auth == "" { + rec.AuthHash = "" + } else { + rec.AuthHash = "sha256:" + utils.AsSha256Hex(*rec.Auth) + } + rec.Auth = nil +} diff --git a/database/db_test.go b/api/subscription_test.go similarity index 97% rename from database/db_test.go rename to api/subscription_test.go index 4300f23d..146505a8 100644 --- a/database/db_test.go +++ b/api/subscription_test.go @@ -17,13 +17,13 @@ * along with this program. If not, see . */ -package database_test +package api_test import ( "encoding/json" "time" - . "github.com/LiterMC/go-openbmclapi/database" + . "github.com/LiterMC/go-openbmclapi/api" "testing" ) diff --git a/api/token.go b/api/token.go new file mode 100644 index 00000000..8dfcbdc9 --- /dev/null +++ b/api/token.go @@ -0,0 +1,38 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +import ( + "net/url" +) + +type TokenVerifier interface { + VerifyChallengeToken(clientId string, token string, action string) (err error) + VerifyAuthToken(clientId string, token string) (tokenId string, userId string, err error) + VerifyAPIToken(clientId string, token string, path string, query url.Values) (userId string, err error) +} + +type TokenManager interface { + TokenVerifier + GenerateChallengeToken(clientId string, action string) (token string, err error) + GenerateAuthToken(clientId string, userId string) (token string, err error) + GenerateAPIToken(clientId string, userId string, path string, query map[string]string) (token string, err error) + InvalidToken(tokenId string) error +} diff --git a/api/user.go b/api/user.go new file mode 100644 index 00000000..5d22fad3 --- /dev/null +++ b/api/user.go @@ -0,0 +1,67 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package api + +type UserManager interface { + GetUsers() []*User + GetUser(id string) *User + AddUser(*User) error + RemoveUser(id string) error + ForEachUser(cb func(*User) error) error + UpdateUserPassword(username string, password string) error + UpdateUserPermissions(username string, permissions PermissionFlag) error + + VerifyUserPassword(userId string, comparator func(password string) bool) error +} + +type PermissionFlag uint32 + +const ( + // BasicPerm includes majority client side actions, such as login, which do not have a significant impact on the server + BasicPerm PermissionFlag = 1 << iota + // SubscribePerm allows the user to subscribe server status & other posts + SubscribePerm + // LogPerm allows the user to view non-debug logs & download access logs + LogPerm + // DebugPerm allows the user to access debug settings & download debug logs + DebugPerm + // FullConfigPerm allows the user to access all config values + FullConfigPerm + // ClusterPerm allows the user to configure clusters' settings & stop/start clusters + ClusterPerm + // StoragePerm allows the user to configure storages' settings & decides to manually start storages' sync process + StoragePerm + // BypassLimitPerm allows the user to ignore API access limit + BypassLimitPerm + // RootPerm user can add/remove users, reset their password, and change their permission flags + RootPerm PermissionFlag = 1 << 31 + + AllPerm = ^(PermissionFlag)(0) +) + +type User struct { + Username string + Password string // as sha256 + Permissions PermissionFlag +} + +func (u *User) HasPerm(perm PermissionFlag) bool { + return u.Permissions&perm == perm +} diff --git a/api/v0/api.go b/api/v0/api.go new file mode 100644 index 00000000..42129980 --- /dev/null +++ b/api/v0/api.go @@ -0,0 +1,172 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2023 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "encoding/json" + "errors" + "mime" + "net/http" + "strconv" + + "github.com/gorilla/schema" + "github.com/gorilla/websocket" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/utils" +) + +type Handler struct { + handler *utils.HttpMiddleWareHandler + router *http.ServeMux + wsUpgrader *websocket.Upgrader + config api.ConfigHandler + clusters api.ClusterManager + users api.UserManager + tokens api.TokenManager + subscriptions api.SubscriptionManager + stats api.StatsManager +} + +var _ http.Handler = (*Handler)(nil) + +func NewHandler( + wsUpgrader *websocket.Upgrader, + config api.ConfigHandler, + clusters api.ClusterManager, + users api.UserManager, + tokenManager api.TokenManager, + subManager api.SubscriptionManager, + statsManager api.StatsManager, +) *Handler { + mux := http.NewServeMux() + h := &Handler{ + router: mux, + handler: utils.NewHttpMiddleWareHandler(mux), + wsUpgrader: wsUpgrader, + config: config, + clusters: clusters, + users: users, + tokens: tokenManager, + subscriptions: subManager, + stats: statsManager, + } + h.buildRoute() + h.handler.UseFunc(cliIdMiddleWare, h.authMiddleWare) + return h +} + +func (h *Handler) Handler() *utils.HttpMiddleWareHandler { + return h.handler +} + +func (h *Handler) buildRoute() { + mux := h.router + + mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) { + writeJson(rw, http.StatusNotFound, Map{ + "error": "404 not found", + "path": req.URL.Path, + }) + }) + + h.buildAuthRoute(mux) + h.buildClusterRoute(mux) + h.buildConfigureRoute(mux) + h.buildDebugRoute(mux) + h.buildStatRoute(mux) + h.buildSubscriptionRoute(mux) +} + +func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + h.handler.ServeHTTP(rw, req) +} + +type Map = map[string]any + +var errUnknownContent = errors.New("unknown content-type") +var formDecoder = schema.NewDecoder() + +func parseRequestBody(rw http.ResponseWriter, req *http.Request, ptr any) (parsed bool) { + contentType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": err.Error(), + }) + return + } + switch contentType { + case "application/json": + if err := json.NewDecoder(req.Body).Decode(ptr); err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Cannot decode request body", + "message": err.Error(), + }) + return + } + return true + case "application/x-www-form-urlencoded": + if err := req.ParseForm(); err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Cannot decode request body", + "message": err.Error(), + }) + return + } + if err := formDecoder.Decode(ptr, req.PostForm); err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Cannot decode request body", + "message": err.Error(), + }) + return + } + return true + default: + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected Content-Type", + "content-type": contentType, + }) + return + } +} + +func calcSha256ETag(data []byte) string { + return `"sha256:` + utils.BytesAsSha256(data) + `"` +} + +func writeJson(rw http.ResponseWriter, code int, data any) (err error) { + buf, err := json.Marshal(data) + if err != nil { + http.Error(rw, "Error when encoding response: "+err.Error(), http.StatusInternalServerError) + return + } + rw.Header().Set("Content-Type", "application/json") + rw.Header().Set("Content-Length", strconv.Itoa(len(buf))) + rw.WriteHeader(code) + _, err = rw.Write(buf) + return +} + +func errorMethodNotAllowed(rw http.ResponseWriter, req *http.Request, allow string) { + rw.Header().Set("Allow", allow) + rw.WriteHeader(http.StatusMethodNotAllowed) +} diff --git a/api/v0/auth.go b/api/v0/auth.go new file mode 100644 index 00000000..1500188d --- /dev/null +++ b/api/v0/auth.go @@ -0,0 +1,295 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "context" + "crypto/subtle" + "errors" + "net/http" + "strings" + "time" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/limited" + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/utils" +) + +const ( + clientIdCookieName = "_id" + + clientIdKey = "go-openbmclapi.cluster.client.id" +) + +func apiGetClientId(req *http.Request) (id string) { + return req.Context().Value(clientIdKey).(string) +} + +const jwtIssuerPrefix = "GOBA.dash.api" + +const ( + tokenTypeKey = "go-openbmclapi.cluster.token.typ" + tokenIdKey = "go-openbmclapi.cluster.token.id" + + loggedUserKey = "go-openbmclapi.cluster.logged.user" +) + +const ( + tokenTypeAuth = "auth" + tokenTypeAPI = "api" +) + +func getRequestTokenType(req *http.Request) string { + if t, ok := req.Context().Value(tokenTypeKey).(string); ok { + return t + } + return "" +} + +func getLoggedUser(req *http.Request) *api.User { + if user, ok := req.Context().Value(loggedUserKey).(*api.User); ok { + return user + } + return nil +} + +func cliIdMiddleWare(rw http.ResponseWriter, req *http.Request, next http.Handler) { + var id string + if cid, _ := req.Cookie(clientIdCookieName); cid != nil { + id = cid.Value + } else { + var err error + id, err = utils.GenRandB64(16) + if err != nil { + http.Error(rw, "cannot generate random number", http.StatusInternalServerError) + return + } + http.SetCookie(rw, &http.Cookie{ + Name: clientIdCookieName, + Value: id, + Expires: time.Now().Add(time.Hour * 24 * 365 * 16), + Secure: true, + HttpOnly: true, + }) + } + req = req.WithContext(context.WithValue(req.Context(), clientIdKey, utils.AsSha256(id))) + next.ServeHTTP(rw, req) +} + +func (h *Handler) authMiddleWare(rw http.ResponseWriter, req *http.Request, next http.Handler) { + cli := apiGetClientId(req) + + ctx := req.Context() + + var ( + typ string + id string + uid string + err error + ) + if req.Method == http.MethodGet { + if tk := req.URL.Query().Get("_t"); tk != "" { + path := api.GetRequestRealPath(req) + if uid, err = h.tokens.VerifyAPIToken(cli, tk, path, req.URL.Query()); err == nil { + typ = tokenTypeAPI + } + } + } + if typ == "" { + auth := req.Header.Get("Authorization") + tk, ok := strings.CutPrefix(auth, "Bearer ") + if !ok { + if err == nil { + err = errors.New("Unsupported authorization type") + } + } else if id, uid, err = h.tokens.VerifyAuthToken(cli, tk); err == nil { + typ = tokenTypeAuth + } + } + if typ != "" { + user := h.users.GetUser(uid) + if user != nil { + ctx = context.WithValue(ctx, tokenTypeKey, typ) + ctx = context.WithValue(ctx, loggedUserKey, user) + ctx = context.WithValue(ctx, tokenIdKey, id) + req = req.WithContext(ctx) + if user.HasPerm(api.RootPerm) { + req = limited.SetSkipRateLimit(req) + } + } + } + next.ServeHTTP(rw, req) +} + +func authHandle(next http.Handler) http.Handler { + return permHandle(api.BasicPerm, next) +} + +func authHandleFunc(next http.HandlerFunc) http.Handler { + return authHandle(next) +} + +func permHandle(perm api.PermissionFlag, next http.Handler) http.Handler { + perm |= api.BasicPerm + return (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + if user == nil { + writeJson(rw, http.StatusUnauthorized, Map{ + "error": "403 Unauthorized", + }) + return + } + if user.Permissions&perm != perm { + writeJson(rw, http.StatusForbidden, Map{ + "error": "Permission denied", + }) + return + } + next.ServeHTTP(rw, req) + }) +} + +func permHandleFunc(perm api.PermissionFlag, next http.HandlerFunc) http.Handler { + return permHandle(perm, next) +} + +func (h *Handler) buildAuthRoute(mux *http.ServeMux) { + mux.HandleFunc("/challenge", h.routeChallenge) + mux.HandleFunc("POST /login", h.routeLogin) + mux.Handle("POST /requestToken", authHandleFunc(h.routeRequestToken)) + mux.Handle("POST /logout", authHandleFunc(h.routeLogout)) + mux.Handle("GET /user_info", authHandleFunc(h.routeUserInfo)) +} + +func (h *Handler) routeChallenge(rw http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodGet { + errorMethodNotAllowed(rw, req, http.MethodGet) + return + } + cli := apiGetClientId(req) + query := req.URL.Query() + action := query.Get("action") + token, err := h.tokens.GenerateChallengeToken(cli, action) + if err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "Cannot generate token", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, Map{ + "token": token, + }) +} + +func (h *Handler) routeLogin(rw http.ResponseWriter, req *http.Request) { + cli := apiGetClientId(req) + + var data struct { + User string `json:"username" schema:"username"` + Challenge string `json:"challenge" schema:"challenge"` + Signature string `json:"signature" schema:"signature"` + } + if !parseRequestBody(rw, req, &data) { + return + } + + if err := h.tokens.VerifyChallengeToken(cli, "login", data.Challenge); err != nil { + writeJson(rw, http.StatusUnauthorized, Map{ + "error": "Invalid challenge", + }) + return + } + if err := h.users.VerifyUserPassword(data.User, func(password string) bool { + expectSignature := utils.HMACSha256HexBytes(password, data.Challenge) + return subtle.ConstantTimeCompare(expectSignature, ([]byte)(data.Signature)) == 0 + }); err != nil { + writeJson(rw, http.StatusUnauthorized, Map{ + "error": "The username or password is incorrect", + }) + return + } + token, err := h.tokens.GenerateAuthToken(cli, data.User) + if err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "Cannot generate token", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, Map{ + "token": token, + }) +} + +func (h *Handler) routeRequestToken(rw http.ResponseWriter, req *http.Request) { + defer req.Body.Close() + if getRequestTokenType(req) != tokenTypeAuth { + writeJson(rw, http.StatusUnauthorized, Map{ + "error": "invalid authorization type", + }) + return + } + + var payload struct { + Path string `json:"path"` + Query map[string]string `json:"query,omitempty"` + } + if !parseRequestBody(rw, req, &payload) { + return + } + log.Debugf("payload: %#v", payload) + if payload.Path == "" || payload.Path[0] != '/' { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "path is invalid", + "message": "'path' must be a non empty string which starts with '/'", + }) + return + } + cli := apiGetClientId(req) + user := getLoggedUser(req) + token, err := h.tokens.GenerateAPIToken(cli, user.Username, payload.Path, payload.Query) + if err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "cannot generate token", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, Map{ + "token": token, + }) +} + +func (h *Handler) routeLogout(rw http.ResponseWriter, req *http.Request) { + limited.SetSkipRateLimit(req) + tid := req.Context().Value(tokenIdKey).(string) + h.tokens.InvalidToken(tid) + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeUserInfo(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + writeJson(rw, http.StatusOK, Map{ + "name": user.Username, + "permissions": user.Permissions, + }) +} diff --git a/api/v0/cluster.go b/api/v0/cluster.go new file mode 100644 index 00000000..76812bd8 --- /dev/null +++ b/api/v0/cluster.go @@ -0,0 +1,295 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2025 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "context" + "encoding/json" + "fmt" + "io" + "mime" + "net/http" + "strconv" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/config" + "github.com/LiterMC/go-openbmclapi/log" +) + +func (h *Handler) buildClusterRoute(mux *http.ServeMux) { + mux.Handle("GET /cluster/list", permHandleFunc(api.ClusterPerm, h.routeClusterList)) + mux.Handle("GET /cluster/status", permHandleFunc(api.ClusterPerm, h.routeClusterStatus)) + mux.Handle("GET /cluster/config", permHandleFunc(api.ClusterPerm, h.routeClusterConfigGET)) + mux.Handle("PUT /cluster/config", permHandleFunc(api.ClusterPerm, h.routeClusterConfigPUT)) + mux.Handle("DELETE /cluster/config", permHandleFunc(api.ClusterPerm, h.routeClusterConfigDELETE)) + mux.Handle("POST /cluster/connect", permHandleFunc(api.ClusterPerm, h.routeClusterConnect)) + mux.Handle("POST /cluster/sync", permHandleFunc(api.ClusterPerm, h.routeClusterSync)) + mux.Handle("POST /cluster/enable", permHandleFunc(api.ClusterPerm, h.routeClusterEnable)) + mux.Handle("POST /cluster/disable", permHandleFunc(api.ClusterPerm, h.routeClusterDisable)) +} + +func (h *Handler) routeClusterList(rw http.ResponseWriter, req *http.Request) { + data, err := json.Marshal(h.config.GetConfig().Clusters) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "MarshalJSONError", + "message": err.Error(), + }) + return + } + etag := calcSha256ETag(data) + rw.Header().Set("ETag", etag) + if req.Header.Get("If-None-Match") == etag { + rw.WriteHeader(http.StatusNotModified) + return + } + rw.Header().Set("Content-Type", "application/json") + rw.Header().Set("Content-Length", strconv.Itoa(len(data))) + rw.WriteHeader(http.StatusOK) + rw.Write(data) +} + +func (h *Handler) routeClusterStatus(rw http.ResponseWriter, req *http.Request) { + type clusterStatus struct { + Status api.ClusterStatus `json:"status"` + Sync bool `json:"sync"` + } + data := make(map[string]*clusterStatus) + for _, cluster := range h.clusters.GetClusters() { + data[cluster.Name()] = &clusterStatus{ + Status: cluster.Status(), + Sync: false, // TODO + } + } + writeJson(rw, http.StatusOK, data) +} + +func (h *Handler) routeClusterConfigGET(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + clusterCfg, ok := h.config.GetConfig().Clusters[clusterId] + if !ok { + writeJson(rw, http.StatusNotFound, Map{ + "error": "ClusterNotFound", + }) + return + } + data, err := json.Marshal(clusterCfg) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "MarshalJSONError", + "message": err.Error(), + }) + return + } + etag := calcSha256ETag(data) + rw.Header().Set("ETag", etag) + if req.Header.Get("If-None-Match") == etag { + rw.WriteHeader(http.StatusNotModified) + return + } + rw.Header().Set("Content-Type", "application/json") + rw.Header().Set("Content-Length", strconv.Itoa(len(data))) + rw.WriteHeader(http.StatusOK) + rw.Write(data) +} + +func (h *Handler) routeClusterConfigPUT(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + contentType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) + if err != nil { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": err.Error(), + }) + return + } + etag := req.Header.Get("If-Match") + if err := h.config.DoWriteLockedAction(func(cfg api.ConfigHandler) error { + clustersCfg := cfg.GetConfig().Clusters + if etag != "" { + ccfg, ok := clustersCfg[clusterId] + if !ok { + return api.ErrPreconditionFailed + } + if data, err := json.Marshal(ccfg); err != nil { + return err + } else if etag != calcSha256ETag(data) { + return api.ErrPreconditionFailed + } + } + var clusterCfg config.ClusterOptions + switch contentType { + case "application/json": + buf, err := io.ReadAll(req.Body) + if err != nil { + return fmt.Errorf("Failed to read request body: %w", err) + } + if err := json.Unmarshal(buf, &clusterCfg); err != nil { + return err + } + default: + return errUnknownContent + } + clustersCfg[clusterId] = clusterCfg + return nil + }); err != nil { + if err == api.ErrPreconditionFailed { + rw.WriteHeader(http.StatusPreconditionFailed) + return + } + if err == errUnknownContent { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": "Expected application/json", + }) + return + } + writeJson(rw, http.StatusBadRequest, Map{ + "error": "UnmarshalError", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeClusterConfigDELETE(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + etag := req.Header.Get("If-Match") + if err := h.config.DoWriteLockedAction(func(config api.ConfigHandler) error { + clustersCfg := h.config.GetConfig().Clusters + if etag != "" { + buf, err := json.Marshal(clustersCfg) + if err != nil { + return err + } + if etag != calcSha256ETag(buf) { + return api.ErrPreconditionFailed + } + } + _, ok := clustersCfg[clusterId] + if !ok { + return api.ErrPreconditionFailed + } + delete(clustersCfg, clusterId) + return nil + }); err != nil { + if err == api.ErrPreconditionFailed { + rw.WriteHeader(http.StatusPreconditionFailed) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "InternalServerError", + "message": err.Error(), + }) + return + } + cluster := h.clusters.GetCluster(clusterId) + if cluster == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "ClusterNotFound", + }) + return + } + go func() { + if err := cluster.Disable(context.Background()); err != nil { + log.Errorf("API Disable Error: %v", err) + } + cluster.Disconnect(context.Background()) + }() + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeClusterConnect(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + cluster := h.clusters.GetCluster(clusterId) + if cluster == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "ClusterNotFound", + }) + return + } + go func() { + err := cluster.Connect(context.Background()) + if err != nil { + log.Errorf("API Connect Error: %v", err) + } + }() + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeClusterSync(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + clu := h.clusters.GetCluster(clusterId) + fileMap := make(map[string]*api.StorageFileInfo) + if err := clu.GetFileList(req.Context(), fileMap, false); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "FileListFetchError", + "message": err.Error(), + }) + return + } + go func() { + // TODO: sync file + // need make sure no conflict with timed sync + }() + writeJson(rw, http.StatusOK, Map{ + "count": len(fileMap), + }) +} + +func (h *Handler) routeClusterEnable(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + cluster := h.clusters.GetCluster(clusterId) + if cluster == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "ClusterNotFound", + }) + return + } + go func() { + err := cluster.Enable(context.Background()) + if err != nil { + log.Errorf("API Enable Error: %v", err) + } + }() + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeClusterDisable(rw http.ResponseWriter, req *http.Request) { + clusterId := req.URL.Query().Get("cluster_id") + cluster := h.clusters.GetCluster(clusterId) + if cluster == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "ClusterNotFound", + }) + return + } + go func() { + err := cluster.Disable(context.Background()) + if err != nil { + log.Errorf("API Disable Error: %v", err) + } + cluster.Disconnect(context.Background()) + }() + rw.WriteHeader(http.StatusNoContent) +} diff --git a/api/v0/configure.go b/api/v0/configure.go new file mode 100644 index 00000000..bd8b8fac --- /dev/null +++ b/api/v0/configure.go @@ -0,0 +1,258 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "fmt" + "io" + "mime" + "net/http" + "strconv" + + "github.com/LiterMC/go-openbmclapi/api" +) + +func (h *Handler) buildConfigureRoute(mux *http.ServeMux) { + mux.Handle("GET /config", permHandleFunc(api.FullConfigPerm, h.routeConfigGET)) + mux.Handle("GET /config/{path}", permHandleFunc(api.FullConfigPerm, h.routeConfigGETPath)) + mux.Handle("PUT /config", permHandleFunc(api.FullConfigPerm, h.routeConfigPUT)) + mux.Handle("PATCH /config/{path}", permHandleFunc(api.FullConfigPerm, h.routeConfigPATCH)) + + mux.Handle("GET /configure/storages", permHandleFunc(api.StoragePerm, h.routeConfigureStoragesGET)) + mux.Handle("GET /configure/storage/{storage_index}", permHandleFunc(api.StoragePerm, h.routeConfigureStorageGET)) + mux.Handle("PUT /configure/storage/{storage_index}", permHandleFunc(api.StoragePerm, h.routeConfigureStoragePUT)) + mux.Handle("PATCH /configure/storage/{storage_index}/{path}", permHandleFunc(api.StoragePerm, h.routeConfigureStoragePATCH)) + mux.Handle("DELETE /configure/storage/{storage_index}", permHandleFunc(api.StoragePerm, h.routeConfigureStorageDELETE)) + mux.Handle("POST /configure/storage/{storage_index}/move", permHandleFunc(api.StoragePerm, h.routeConfigureStorageMove)) +} + +func (h *Handler) routeConfigGET(rw http.ResponseWriter, req *http.Request) { + buf, err := h.config.MarshalJSON() + if err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "MarshalJSONError", + "message": err.Error(), + }) + return + } + etag := calcSha256ETag(buf) + rw.Header().Set("ETag", etag) + if req.Header.Get("If-None-Match") == etag { + rw.WriteHeader(http.StatusNotModified) + return + } + rw.WriteHeader(http.StatusOK) + rw.Write(buf) +} + +func (h *Handler) routeConfigPUT(rw http.ResponseWriter, req *http.Request) { + contentType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) + if err != nil { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": err.Error(), + }) + return + } + etag := req.Header.Get("If-Match") + if err := h.config.DoWriteLockedAction(func(config api.ConfigHandler) error { + if etag != "" { + buf, err := config.GetConfig().MarshalJSON() + if err != nil { + return err + } + if etag != calcSha256ETag(buf) { + return api.ErrPreconditionFailed + } + } + switch contentType { + case "application/json": + buf, err := io.ReadAll(req.Body) + if err != nil { + return fmt.Errorf("Failed to read request body: %w", err) + } + return config.UnmarshalJSON(buf) + case "application/x-yaml": + buf, err := io.ReadAll(req.Body) + if err != nil { + return fmt.Errorf("Failed to read request body: %w", err) + } + return config.UnmarshalYAML(buf) + default: + return errUnknownContent + } + }); err != nil { + if err == api.ErrPreconditionFailed { + rw.WriteHeader(http.StatusPreconditionFailed) + return + } + if err == errUnknownContent { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": "Expected application/json, application/x-yaml", + }) + return + } + writeJson(rw, http.StatusBadRequest, Map{ + "error": "UnmarshalError", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) + // TODO: restart +} + +func (h *Handler) routeConfigGETPath(rw http.ResponseWriter, req *http.Request) { + path := req.PathValue("path") + data, err := h.config.MarshalJSONPath(path) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "MarshalJSONError", + "message": err.Error(), + }) + return + } + rw.Header().Set("Content-Type", "application/json") + rw.Header().Set("Content-Length", strconv.Itoa(len(data))) + rw.WriteHeader(http.StatusOK) + rw.Write(data) +} + +func (h *Handler) routeConfigPATCH(rw http.ResponseWriter, req *http.Request) { + path := req.PathValue("path") + contentType, _, err := mime.ParseMediaType(req.Header.Get("Content-Type")) + if err != nil { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": err.Error(), + }) + return + } + etag := req.Header.Get("If-Match") + if err := h.config.DoWriteLockedAction(func(config api.ConfigHandler) error { + if etag != "" { + buf, err := config.GetConfig().MarshalJSON() + if err != nil { + return err + } + if etag != calcSha256ETag(buf) { + return api.ErrPreconditionFailed + } + } + switch contentType { + case "application/json": + buf, err := io.ReadAll(req.Body) + if err != nil { + return fmt.Errorf("Failed to read request body: %w", err) + } + return config.UnmarshalJSONPath(path, buf) + default: + return errUnknownContent + } + }); err != nil { + if err == api.ErrPreconditionFailed { + rw.WriteHeader(http.StatusPreconditionFailed) + return + } + if err == errUnknownContent { + writeJson(rw, http.StatusUnsupportedMediaType, Map{ + "error": "Unexpected Content-Type", + "content-type": req.Header.Get("Content-Type"), + "message": "Expected application/json, application/x-yaml", + }) + return + } + writeJson(rw, http.StatusBadRequest, Map{ + "error": "UnmarshalError", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeConfigureStoragesGET(rw http.ResponseWriter, req *http.Request) { +} + +func (h *Handler) routeConfigureStorageGET(rw http.ResponseWriter, req *http.Request) { + storageIndex, err := strconv.Atoi(req.PathValue("storage_index")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected storageIndex", + "message": err.Error(), + }) + return + } + _ = storageIndex +} + +func (h *Handler) routeConfigureStoragePUT(rw http.ResponseWriter, req *http.Request) { + storageIndex, err := strconv.Atoi(req.PathValue("storage_index")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected storageIndex", + "message": err.Error(), + }) + return + } + _ = storageIndex +} + +func (h *Handler) routeConfigureStoragePATCH(rw http.ResponseWriter, req *http.Request) { + storageIndex, err := strconv.Atoi(req.PathValue("storage_index")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected storageIndex", + "message": err.Error(), + }) + return + } + path := req.PathValue("path") + _, _ = storageIndex, path +} + +func (h *Handler) routeConfigureStorageDELETE(rw http.ResponseWriter, req *http.Request) { + storageIndex, err := strconv.Atoi(req.PathValue("storage_index")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected storageIndex", + "message": err.Error(), + }) + return + } + _ = storageIndex +} + +func (h *Handler) routeConfigureStorageMove(rw http.ResponseWriter, req *http.Request) { + storageIndex, err := strconv.Atoi(req.PathValue("storage_index")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "Unexpected storageIndex", + "message": err.Error(), + }) + return + } + storageIndexTo := req.URL.Query().Get("to") + _, _ = storageIndex, storageIndexTo +} diff --git a/api/v0/debug.go b/api/v0/debug.go new file mode 100644 index 00000000..9727d627 --- /dev/null +++ b/api/v0/debug.go @@ -0,0 +1,393 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2023 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "compress/gzip" + "context" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "runtime/pprof" + "strconv" + "sync/atomic" + "time" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/internal/build" + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/utils" +) + +func (h *Handler) buildDebugRoute(mux *http.ServeMux) { + mux.HandleFunc("/log.io", h.routeLogIO) + mux.Handle("/pprof", permHandleFunc(api.DebugPerm, h.routePprof)) + mux.Handle("GET /log_files", permHandleFunc(api.LogPerm, h.routeLogFiles)) + mux.Handle("GET /log_file/{file_name}", permHandleFunc(api.LogPerm, h.routeLogFile)) +} + +func (h *Handler) routeLogIO(rw http.ResponseWriter, req *http.Request) { + addr := api.GetRequestRealAddr(req) + + conn, err := h.wsUpgrader.Upgrade(rw, req, nil) + if err != nil { + log.Debugf("[log.io]: Websocket upgrade error: %v", err) + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + defer conn.Close() + + cli := apiGetClientId(req) + + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + + conn.SetReadLimit(1024 * 4) + pongTimeoutTimer := time.NewTimer(time.Second * 75) + go func() { + defer conn.Close() + defer cancel() + defer pongTimeoutTimer.Stop() + select { + case _, ok := <-pongTimeoutTimer.C: + if !ok { + return + } + log.Error("[log.io]: Did not receive packet from client longer than 75s") + return + case <-ctx.Done(): + return + } + }() + + var authData struct { + Token string `json:"token"` + } + deadline := time.Now().Add(time.Second * 10) + conn.SetReadDeadline(deadline) + err = conn.ReadJSON(&authData) + conn.SetReadDeadline(time.Time{}) + if err != nil { + if time.Now().After(deadline) { + conn.WriteJSON(Map{ + "type": "error", + "message": "auth timeout", + }) + } else { + conn.WriteJSON(Map{ + "type": "error", + "message": "unexpected auth data: " + err.Error(), + }) + } + return + } + if _, _, err = h.tokens.VerifyAuthToken(cli, authData.Token); err != nil { + conn.WriteJSON(Map{ + "type": "error", + "message": "auth failed", + }) + return + } + if err := conn.WriteJSON(Map{ + "type": "ready", + }); err != nil { + return + } + + var level atomic.Int32 + level.Store((int32)(log.LevelInfo)) + + type logObj struct { + Type string `json:"type"` + Time int64 `json:"time"` // UnixMilli + Level string `json:"lvl"` + Log string `json:"log"` + } + c := make(chan *logObj, 64) + unregister := log.RegisterLogMonitor(log.LevelDebug, func(ts int64, l log.Level, msg string) { + if (log.Level)(level.Load()) > l&log.LevelMask { + return + } + select { + case c <- &logObj{ + Type: "log", + Time: ts, + Level: l.String(), + Log: msg, + }: + default: + } + }) + defer unregister() + + go func() { + defer log.RecoverPanic(nil) + defer conn.Close() + defer cancel() + var data map[string]any + for { + clear(data) + if err := conn.ReadJSON(&data); err != nil { + log.Errorf("[log.io]: Cannot read from peer: %v", err) + return + } + typ, ok := data["type"].(string) + if !ok { + continue + } + switch typ { + case "pong": + log.Debugf("[log.io]: received PONG from %s: %v", addr, data["data"]) + pongTimeoutTimer.Reset(time.Second * 75) + case "set-level": + l, ok := data["level"].(string) + if ok { + switch l { + case "DBUG": + level.Store((int32)(log.LevelDebug)) + case "INFO": + level.Store((int32)(log.LevelInfo)) + case "WARN": + level.Store((int32)(log.LevelWarn)) + case "ERRO": + level.Store((int32)(log.LevelError)) + default: + continue + } + select { + case c <- &logObj{ + Type: "log", + Time: time.Now().UnixMilli(), + Level: log.LevelInfo.String(), + Log: "[dashboard]: Set log level to " + l + " for this log.io", + }: + default: + } + } + } + } + }() + + sendMsgCh := make(chan any, 64) + go func() { + for { + select { + case v := <-c: + select { + case sendMsgCh <- v: + case <-ctx.Done(): + return + } + case <-ctx.Done(): + return + } + } + }() + + pingTicker := time.NewTicker(time.Second * 45) + defer pingTicker.Stop() + forceSendTimer := time.NewTimer(time.Second) + if !forceSendTimer.Stop() { + <-forceSendTimer.C + } + + batchMsg := make([]any, 0, 64) + for { + select { + case v := <-sendMsgCh: + batchMsg = append(batchMsg, v) + forceSendTimer.Reset(time.Second) + WAIT_MORE: + for { + select { + case v := <-sendMsgCh: + batchMsg = append(batchMsg, v) + case <-time.After(time.Millisecond * 20): + if !forceSendTimer.Stop() { + <-forceSendTimer.C + } + break WAIT_MORE + case <-forceSendTimer.C: + break WAIT_MORE + case <-ctx.Done(): + forceSendTimer.Stop() + return + } + } + if len(batchMsg) == 1 { + if err := conn.WriteJSON(batchMsg[0]); err != nil { + return + } + } else { + if err := conn.WriteJSON(batchMsg); err != nil { + return + } + } + // release objects + for i, _ := range batchMsg { + batchMsg[i] = nil + } + batchMsg = batchMsg[:0] + case <-pingTicker.C: + if err := conn.WriteJSON(Map{ + "type": "ping", + "data": time.Now().UnixMilli(), + }); err != nil { + log.Errorf("[log.io]: Error when sending ping packet: %v", err) + return + } + case <-ctx.Done(): + return + } + } +} + +func (h *Handler) routePprof(rw http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodGet { + errorMethodNotAllowed(rw, req, http.MethodGet) + return + } + query := req.URL.Query() + lookup := query.Get("lookup") + p := pprof.Lookup(lookup) + if p == nil { + http.Error(rw, fmt.Sprintf("pprof.Lookup(%q) returned nil", lookup), http.StatusBadRequest) + return + } + view := query.Get("view") + debug, err := strconv.Atoi(query.Get("debug")) + if err != nil { + debug = 1 + } + if debug == 1 { + rw.Header().Set("Content-Type", "text/plain; charset=utf-8") + } else { + rw.Header().Set("Content-Type", "application/octet-stream") + } + if view != "1" { + name := fmt.Sprintf(time.Now().Format("dump-%s-20060102-150405"), lookup) + if debug == 1 { + name += ".txt" + } else { + name += ".dump" + } + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name)) + } + rw.WriteHeader(http.StatusOK) + if debug == 1 { + fmt.Fprintf(rw, "version: %s (%s)\n", build.BuildVersion, build.ClusterVersion) + } + p.WriteTo(rw, debug) +} + +func (h *Handler) routeLogFiles(rw http.ResponseWriter, req *http.Request) { + files := log.ListLogs() + type FileInfo struct { + Name string `json:"name"` + Size int64 `json:"size"` + } + data := make([]FileInfo, 0, len(files)) + for _, file := range files { + if s, err := os.Stat(filepath.Join(log.BaseDir(), file)); err == nil { + data = append(data, FileInfo{ + Name: file, + Size: s.Size(), + }) + } + } + writeJson(rw, http.StatusOK, Map{ + "files": data, + }) +} + +func (h *Handler) routeLogFile(rw http.ResponseWriter, req *http.Request) { + fileName := req.PathValue("file_name") + query := req.URL.Query() + fd, err := os.Open(filepath.Join(log.BaseDir(), fileName)) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + writeJson(rw, http.StatusNotFound, Map{ + "error": "file not exists", + "message": "Cannot find log file", + "path": req.URL.Path, + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "cannot open file", + "message": err.Error(), + }) + return + } + defer fd.Close() + name := filepath.Base(req.URL.Path) + isGzip := filepath.Ext(name) == ".gz" + if query.Get("no_encrypt") == "1" { + var modTime time.Time + if stat, err := fd.Stat(); err == nil { + modTime = stat.ModTime() + } + rw.Header().Set("Cache-Control", "public, max-age=60, stale-while-revalidate=600") + if isGzip { + rw.Header().Set("Content-Type", "application/octet-stream") + } else { + rw.Header().Set("Content-Type", "text/plain; charset=utf-8") + } + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name)) + http.ServeContent(rw, req, name, modTime, fd) + } else { + if !isGzip { + name += ".gz" + } + rw.Header().Set("Content-Type", "application/octet-stream") + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name+".encrypted")) + h.routeLogFileEncrypted(rw, req, fd, !isGzip) + } +} + +func (h *Handler) routeLogFileEncrypted(rw http.ResponseWriter, req *http.Request, r io.Reader, useGzip bool) { + rw.WriteHeader(http.StatusOK) + if req.Method == http.MethodHead { + return + } + if useGzip { + pr, pw := io.Pipe() + defer pr.Close() + go func(r io.Reader) { + gw := gzip.NewWriter(pw) + if _, err := io.Copy(gw, r); err != nil { + pw.CloseWithError(err) + return + } + if err := gw.Close(); err != nil { + pw.CloseWithError(err) + return + } + pw.Close() + }(r) + r = pr + } + if err := utils.EncryptStream(rw, r, utils.DeveloporPublicKey); err != nil { + log.Errorf("Cannot write encrypted log stream: %v", err) + } +} diff --git a/api/v0/stat.go b/api/v0/stat.go new file mode 100644 index 00000000..09b26b5e --- /dev/null +++ b/api/v0/stat.go @@ -0,0 +1,78 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2023 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "net/http" + "time" + + "github.com/LiterMC/go-openbmclapi/internal/build" + "github.com/LiterMC/go-openbmclapi/limited" +) + +func (h *Handler) buildStatRoute(mux *http.ServeMux) { + mux.HandleFunc("GET /ping", h.routePing) + mux.HandleFunc("GET /status", h.routeStatus) + mux.HandleFunc("GET /stat/cluster/{name}", h.routeStatCluster) + mux.HandleFunc("GET /stat/storage/{name}", h.routeStatStorage) +} + +func (h *Handler) routePing(rw http.ResponseWriter, req *http.Request) { + limited.SetSkipRateLimit(req) + authed := getRequestTokenType(req) == tokenTypeAuth + writeJson(rw, http.StatusOK, Map{ + "version": build.BuildVersion, + "time": time.Now().UnixMilli(), + "authed": authed, + }) +} + +func (h *Handler) routeStatus(rw http.ResponseWriter, req *http.Request) { + limited.SetSkipRateLimit(req) + writeJson(rw, http.StatusOK, h.stats.GetStatus()) +} + +func (h *Handler) routeStatCluster(rw http.ResponseWriter, req *http.Request) { + limited.SetSkipRateLimit(req) + name := req.PathValue("name") + data := h.stats.GetClusterAccessStat(name) + if data == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "AccessStatNotFound", + "name": name, + }) + return + } + writeJson(rw, http.StatusOK, data) +} + +func (h *Handler) routeStatStorage(rw http.ResponseWriter, req *http.Request) { + limited.SetSkipRateLimit(req) + name := req.PathValue("name") + data := h.stats.GetStorageAccessStat(name) + if data == nil { + writeJson(rw, http.StatusNotFound, Map{ + "error": "AccessStatNotFound", + "name": name, + }) + return + } + writeJson(rw, http.StatusOK, data) +} diff --git a/api/v0/subscription.go b/api/v0/subscription.go new file mode 100644 index 00000000..cdf30fc7 --- /dev/null +++ b/api/v0/subscription.go @@ -0,0 +1,338 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2023 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package v0 + +import ( + "net/http" + + "github.com/google/uuid" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/utils" +) + +func (h *Handler) buildSubscriptionRoute(mux *http.ServeMux) { + mux.HandleFunc("GET /subscribeKey", h.routeSubscribeKey) + mux.Handle("/subscribe", permHandle(api.SubscribePerm, &utils.HttpMethodHandler{ + Get: (http.HandlerFunc)(h.routeSubscribeGET), + Post: (http.HandlerFunc)(h.routeSubscribePOST), + Delete: (http.HandlerFunc)(h.routeSubscribeDELETE), + })) + mux.Handle("/subscribe_email", permHandle(api.SubscribePerm, &utils.HttpMethodHandler{ + Get: (http.HandlerFunc)(h.routeSubscribeEmailGET), + Post: (http.HandlerFunc)(h.routeSubscribeEmailPOST), + Patch: (http.HandlerFunc)(h.routeSubscribeEmailPATCH), + Delete: (http.HandlerFunc)(h.routeSubscribeEmailDELETE), + })) + mux.Handle("/webhook", permHandle(api.SubscribePerm, &utils.HttpMethodHandler{ + Get: (http.HandlerFunc)(h.routeWebhookGET), + Post: (http.HandlerFunc)(h.routeWebhookPOST), + Patch: (http.HandlerFunc)(h.routeWebhookPATCH), + Delete: (http.HandlerFunc)(h.routeWebhookDELETE), + })) +} + +func (h *Handler) routeSubscribeKey(rw http.ResponseWriter, req *http.Request) { + key := h.subscriptions.GetWebPushKey() + etag := `"` + utils.AsSha256(key) + `"` + rw.Header().Set("ETag", etag) + if cachedTag := req.Header.Get("If-None-Match"); cachedTag == etag { + rw.WriteHeader(http.StatusNotModified) + return + } + writeJson(rw, http.StatusOK, Map{ + "publicKey": key, + }) +} + +func (h *Handler) routeSubscribeGET(rw http.ResponseWriter, req *http.Request) { + client := apiGetClientId(req) + user := getLoggedUser(req) + record, err := h.subscriptions.GetSubscribe(user.Username, client) + if err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no subscription was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, Map{ + "scopes": record.Scopes, + "reportAt": record.ReportAt, + }) +} + +func (h *Handler) routeSubscribePOST(rw http.ResponseWriter, req *http.Request) { + client := apiGetClientId(req) + user := getLoggedUser(req) + var data api.SubscribeRecord + if !parseRequestBody(rw, req, &data) { + return + } + data.User = user.Username + data.Client = client + if err := h.subscriptions.SetSubscribe(data); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "Database update failed", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeSubscribeDELETE(rw http.ResponseWriter, req *http.Request) { + client := apiGetClientId(req) + user := getLoggedUser(req) + if err := h.subscriptions.RemoveSubscribe(user.Username, client); err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no subscription was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeSubscribeEmailGET(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + if addr := req.URL.Query().Get("addr"); addr != "" { + record, err := h.subscriptions.GetEmailSubscription(user.Username, addr) + if err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no email subscription was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, record) + return + } + records := make([]api.EmailSubscriptionRecord, 0, 4) + if err := h.subscriptions.ForEachUsersEmailSubscription(user.Username, func(rec *api.EmailSubscriptionRecord) error { + records = append(records, *rec) + return nil + }); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, records) +} + +func (h *Handler) routeSubscribeEmailPOST(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + var data api.EmailSubscriptionRecord + if !parseRequestBody(rw, req, &data) { + return + } + + data.User = user.Username + if err := h.subscriptions.AddEmailSubscription(data); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "Database update failed", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusCreated) +} + +func (h *Handler) routeSubscribeEmailPATCH(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + addr := req.URL.Query().Get("addr") + var data api.EmailSubscriptionRecord + if !parseRequestBody(rw, req, &data) { + return + } + data.User = user.Username + data.Addr = addr + if err := h.subscriptions.UpdateEmailSubscription(data); err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no email subscription was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeSubscribeEmailDELETE(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + addr := req.URL.Query().Get("addr") + if err := h.subscriptions.RemoveEmailSubscription(user.Username, addr); err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no email subscription was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeWebhookGET(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + if sid := req.URL.Query().Get("id"); sid != "" { + id, err := uuid.Parse(sid) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "uuid format error", + "message": err.Error(), + }) + return + } + record, err := h.subscriptions.GetWebhook(user.Username, id) + if err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no webhook was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, record) + return + } + records := make([]api.WebhookRecord, 0, 4) + if err := h.subscriptions.ForEachUsersWebhook(user.Username, func(rec *api.WebhookRecord) error { + records = append(records, *rec) + return nil + }); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + writeJson(rw, http.StatusOK, records) +} + +func (h *Handler) routeWebhookPOST(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + var data api.WebhookRecord + if !parseRequestBody(rw, req, &data) { + return + } + + data.User = user.Username + if err := h.subscriptions.AddWebhook(data); err != nil { + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "Database update failed", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusCreated) +} + +func (h *Handler) routeWebhookPATCH(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + id := req.URL.Query().Get("id") + var data api.WebhookRecord + if !parseRequestBody(rw, req, &data) { + return + } + data.User = user.Username + var err error + if data.Id, err = uuid.Parse(id); err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "uuid format error", + "message": err.Error(), + }) + return + } + if err := h.subscriptions.UpdateWebhook(data); err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no webhook was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} + +func (h *Handler) routeWebhookDELETE(rw http.ResponseWriter, req *http.Request) { + user := getLoggedUser(req) + id, err := uuid.Parse(req.URL.Query().Get("id")) + if err != nil { + writeJson(rw, http.StatusBadRequest, Map{ + "error": "uuid format error", + "message": err.Error(), + }) + return + } + if err := h.subscriptions.RemoveWebhook(user.Username, id); err != nil { + if err == api.ErrNotFound { + writeJson(rw, http.StatusNotFound, Map{ + "error": "no webhook was found", + }) + return + } + writeJson(rw, http.StatusInternalServerError, Map{ + "error": "database error", + "message": err.Error(), + }) + return + } + rw.WriteHeader(http.StatusNoContent) +} diff --git a/bar.go b/bar.go deleted file mode 100644 index a89c29b6..00000000 --- a/bar.go +++ /dev/null @@ -1,94 +0,0 @@ -/** - * OpenBmclAPI (Golang Edition) - * Copyright (C) 2023 Kevin Z - * All rights reserved - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package main - -import ( - "io" - "sync/atomic" - "time" - - "github.com/vbauerster/mpb/v8" -) - -type ProxiedReader struct { - io.Reader - bar, total *mpb.Bar - lastRead time.Time - lastInc *atomic.Int64 -} - -func ProxyReader(r io.Reader, bar, total *mpb.Bar, lastInc *atomic.Int64) *ProxiedReader { - return &ProxiedReader{ - Reader: r, - bar: bar, - total: total, - lastInc: lastInc, - } -} - -func (p *ProxiedReader) Read(buf []byte) (n int, err error) { - start := p.lastRead - if start.IsZero() { - start = time.Now() - } - n, err = p.Reader.Read(buf) - end := time.Now() - p.lastRead = end - used := end.Sub(start) - - p.bar.EwmaIncrBy(n, used) - nowSt := end.UnixNano() - last := p.lastInc.Swap(nowSt) - p.total.EwmaIncrBy(n, (time.Duration)(nowSt-last)*time.Nanosecond) - return -} - -type ProxiedReadSeeker struct { - io.ReadSeeker - bar, total *mpb.Bar - lastRead time.Time - lastInc *atomic.Int64 -} - -func ProxyReadSeeker(r io.ReadSeeker, bar, total *mpb.Bar, lastInc *atomic.Int64) *ProxiedReadSeeker { - return &ProxiedReadSeeker{ - ReadSeeker: r, - bar: bar, - total: total, - lastInc: lastInc, - } -} - -func (p *ProxiedReadSeeker) Read(buf []byte) (n int, err error) { - start := p.lastRead - if start.IsZero() { - start = time.Now() - } - n, err = p.ReadSeeker.Read(buf) - end := time.Now() - p.lastRead = end - used := end.Sub(start) - - p.bar.EwmaIncrBy(n, used) - nowSt := end.UnixNano() - last := p.lastInc.Swap(nowSt) - p.total.EwmaIncrBy(n, (time.Duration)(nowSt-last)*time.Nanosecond) - return -} diff --git a/cache/cache_redis.go b/cache/cache_redis.go index b88dac74..27a2def3 100644 --- a/cache/cache_redis.go +++ b/cache/cache_redis.go @@ -35,11 +35,11 @@ type RedisCache struct { var _ Cache = (*RedisCache)(nil) type RedisOptions struct { - Network string `yaml:"network"` - Addr string `yaml:"addr"` - ClientName string `yaml:"client-name"` - Username string `yaml:"username"` - Password string `yaml:"password"` + Network string `json:"network" yaml:"network"` + Addr string `json:"addr" yaml:"addr"` + ClientName string `json:"client_name" yaml:"client-name"` + Username string `json:"username" yaml:"username"` + Password string `json:"password" yaml:"password"` } func (o RedisOptions) ToRedis() *redis.Options { diff --git a/cluster.go b/cluster.go deleted file mode 100644 index a5a2df67..00000000 --- a/cluster.go +++ /dev/null @@ -1,770 +0,0 @@ -/** - * OpenBmclAPI (Golang Edition) - * Copyright (C) 2023 Kevin Z - * All rights reserved - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package main - -import ( - "context" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "net" - "net/http" - "os" - "path/filepath" - "regexp" - "runtime" - "sync" - "sync/atomic" - "time" - - "github.com/LiterMC/socket.io" - "github.com/LiterMC/socket.io/engine.io" - "github.com/gorilla/websocket" - "github.com/gregjones/httpcache" - - gocache "github.com/LiterMC/go-openbmclapi/cache" - "github.com/LiterMC/go-openbmclapi/database" - "github.com/LiterMC/go-openbmclapi/internal/build" - "github.com/LiterMC/go-openbmclapi/limited" - "github.com/LiterMC/go-openbmclapi/log" - "github.com/LiterMC/go-openbmclapi/notify" - "github.com/LiterMC/go-openbmclapi/notify/email" - "github.com/LiterMC/go-openbmclapi/notify/webpush" - "github.com/LiterMC/go-openbmclapi/storage" - "github.com/LiterMC/go-openbmclapi/utils" -) - -var ( - reFileHashMismatchError = regexp.MustCompile(` hash mismatch, expected ([0-9a-f]+), got ([0-9a-f]+)`) -) - -type Cluster struct { - host string // not the public access host, but maybe a public IP, or a host that will be resolved to the IP - publicHosts []string // should not contains port, can be nil - publicPort uint16 - clusterId string - clusterSecret string - prefix string - byoc bool - jwtIssuer string - - dataDir string - maxConn int - storageOpts []storage.StorageOption - storages []storage.Storage - storageWeights []uint - storageTotalWeight uint - cache gocache.Cache - apiHmacKey []byte - hijackProxy *HjProxy - - stats notify.Stats - lastHits, statOnlyHits atomic.Int32 - lastHbts, statOnlyHbts atomic.Int64 - issync atomic.Bool - syncProg atomic.Int64 - syncTotal atomic.Int64 - - mux sync.RWMutex - enabled atomic.Bool - disabled chan struct{} - waitEnable []chan struct{} - shouldEnable atomic.Bool - reconnectCount int - socket *socket.Socket - cancelKeepalive context.CancelFunc - downloadMux sync.RWMutex - downloading map[string]*downloadingItem - filesetMux sync.RWMutex - fileset map[string]int64 - authTokenMux sync.RWMutex - authToken *ClusterToken - - client *http.Client - cachedCli *http.Client - bufSlots *limited.BufSlots - database database.DB - notifyManager *notify.Manager - webpushKeyB64 string - updateChecker *time.Ticker - apiRateLimiter *limited.APIRateMiddleWare - - wsUpgrader *websocket.Upgrader - handlerAPIv0 http.Handler - handlerAPIv1 http.Handler - hijackHandler http.Handler -} - -func NewCluster( - ctx context.Context, - prefix string, - baseDir string, - host string, publicPort uint16, - clusterId string, clusterSecret string, - byoc bool, dialer *net.Dialer, - storageOpts []storage.StorageOption, - cache gocache.Cache, -) (cr *Cluster) { - transport := http.DefaultTransport - if dialer != nil { - transport = &http.Transport{ - DialContext: dialer.DialContext, - } - } - - cachedTransport := transport - if cache != gocache.NoCache { - cachedTransport = &httpcache.Transport{ - Transport: transport, - Cache: gocache.WrapToHTTPCache(gocache.NewCacheWithNamespace(cache, "http@")), - } - } - - cr = &Cluster{ - host: host, - publicPort: publicPort, - clusterId: clusterId, - clusterSecret: clusterSecret, - prefix: prefix, - byoc: byoc, - jwtIssuer: jwtIssuerPrefix + "#" + clusterId, - - dataDir: filepath.Join(baseDir, "data"), - maxConn: config.DownloadMaxConn, - storageOpts: storageOpts, - cache: cache, - - disabled: make(chan struct{}, 0), - fileset: make(map[string]int64, 0), - - downloading: make(map[string]*downloadingItem), - - client: &http.Client{ - Transport: transport, - CheckRedirect: redirectChecker, - }, - cachedCli: &http.Client{ - Transport: cachedTransport, - CheckRedirect: redirectChecker, - }, - - wsUpgrader: &websocket.Upgrader{ - HandshakeTimeout: time.Minute, - }, - } - close(cr.disabled) - - if cr.maxConn <= 0 { - panic("download-max-conn must be a positive integer") - } - cr.bufSlots = limited.NewBufSlots(cr.maxConn) - - { - var ( - n uint = 0 - wgs = make([]uint, len(storageOpts)) - sts = make([]storage.Storage, len(storageOpts)) - ) - for i, s := range storageOpts { - sts[i] = storage.NewStorage(s) - wgs[i] = s.Weight - n += s.Weight - } - cr.storages = sts - cr.storageWeights = wgs - cr.storageTotalWeight = n - } - return -} - -func redirectChecker(req *http.Request, via []*http.Request) error { - req.Header.Del("Referer") - if len(via) > 10 { - return errors.New("More than 10 redirects detected") - } - return nil -} - -func (cr *Cluster) Init(ctx context.Context) (err error) { - // create data folder - os.MkdirAll(cr.dataDir, 0755) - - if config.Database.Driver == "memory" { - cr.database = database.NewMemoryDB() - } else if cr.database, err = database.NewSqlDB(config.Database.Driver, config.Database.DSN); err != nil { - return - } - - if config.Hijack.Enable { - cr.hijackProxy = NewHjProxy(cr.client, cr.database, cr.handleDownload) - if config.Hijack.EnableLocalCache { - os.MkdirAll(config.Hijack.LocalCachePath, 0755) - } - } - - // Init notification manager - cr.notifyManager = notify.NewManager(cr.dataDir, cr.database, cr.client, config.Dashboard.NotifySubject) - // Add notification plugins - webpushPlg := new(webpush.Plugin) - cr.notifyManager.AddPlugin(webpushPlg) - if config.Notification.EnableEmail { - emailPlg, err := email.NewSMTP( - config.Notification.EmailSMTP, config.Notification.EmailSMTPEncryption, - config.Notification.EmailSender, config.Notification.EmailSenderPassword, - ) - if err != nil { - return err - } - cr.notifyManager.AddPlugin(emailPlg) - } - - if err = cr.notifyManager.Init(ctx); err != nil { - return - } - cr.webpushKeyB64 = base64.RawURLEncoding.EncodeToString(webpushPlg.GetPublicKey()) - - // Init storages - vctx := context.WithValue(ctx, storage.ClusterCacheCtxKey, cr.cache) - for _, s := range cr.storages { - s.Init(vctx) - } - - // read old stats - if err := cr.stats.Load(cr.dataDir); err != nil { - log.Errorf("Could not load stats: %v", err) - } - if cr.apiHmacKey, err = utils.LoadOrCreateHmacKey(cr.dataDir); err != nil { - return fmt.Errorf("Cannot load hmac key: %w", err) - } - - cr.updateChecker = time.NewTicker(time.Hour) - - go func(ticker *time.Ticker) { - defer log.RecoverPanic(nil) - defer ticker.Stop() - - if err := cr.checkUpdate(); err != nil { - log.Errorf(Tr("error.update.check.failed"), err) - } - for range ticker.C { - if err := cr.checkUpdate(); err != nil { - log.Errorf(Tr("error.update.check.failed"), err) - } - } - }(cr.updateChecker) - return -} - -func (cr *Cluster) Destroy(ctx context.Context) { - if cr.database != nil { - cr.database.Cleanup() - } - cr.updateChecker.Stop() - if cr.apiRateLimiter != nil { - cr.apiRateLimiter.Destroy() - } -} - -func (cr *Cluster) allocBuf(ctx context.Context) (slotId int, buf []byte, free func()) { - return cr.bufSlots.Alloc(ctx) -} - -func (cr *Cluster) Connect(ctx context.Context) bool { - cr.mux.Lock() - defer cr.mux.Unlock() - - if cr.socket != nil { - log.Debug("Extra connect") - return true - } - - _, err := cr.GetAuthToken(ctx) - if err != nil { - log.Errorf(Tr("error.cluster.auth.failed"), err) - osExit(CodeClientOrServerError) - } - - engio, err := engine.NewSocket(engine.Options{ - Host: cr.prefix, - Path: "/socket.io/", - ExtraHeaders: http.Header{ - "Origin": {cr.prefix}, - "User-Agent": {build.ClusterUserAgent}, - }, - DialTimeout: time.Minute * 6, - }) - if err != nil { - log.Errorf("Could not parse Engine.IO options: %v; exit.", err) - osExit(CodeClientUnexpectedError) - } - - cr.reconnectCount = 0 - connected := false - - if config.Advanced.SocketIOLog { - engio.OnRecv(func(_ *engine.Socket, data []byte) { - log.Debugf("Engine.IO recv: %q", (string)(data)) - }) - engio.OnSend(func(_ *engine.Socket, data []byte) { - log.Debugf("Engine.IO sending: %q", (string)(data)) - }) - } - engio.OnConnect(func(*engine.Socket) { - log.Info("Engine.IO connected") - }) - engio.OnDisconnect(func(_ *engine.Socket, err error) { - if ctx.Err() != nil { - // Ignore if the error is because context cancelled - return - } - if err != nil { - log.Warnf("Engine.IO disconnected: %v", err) - } - if config.MaxReconnectCount == 0 { - if cr.shouldEnable.Load() { - log.Errorf("Cluster disconnected from remote; exit.") - osExit(CodeServerOrEnvionmentError) - } - } - if !connected { - cr.reconnectCount++ - if config.MaxReconnectCount > 0 && cr.reconnectCount >= config.MaxReconnectCount { - if cr.shouldEnable.Load() { - log.Error(Tr("error.cluster.connect.failed.toomuch")) - osExit(CodeServerOrEnvionmentError) - } - } - } - connected = false - go cr.disconnected() - }) - engio.OnDialError(func(_ *engine.Socket, err error) { - cr.reconnectCount++ - log.Errorf(Tr("error.cluster.connect.failed"), cr.reconnectCount, config.MaxReconnectCount, err) - if config.MaxReconnectCount >= 0 && cr.reconnectCount >= config.MaxReconnectCount { - if cr.shouldEnable.Load() { - log.Error(Tr("error.cluster.connect.failed.toomuch")) - osExit(CodeServerOrEnvionmentError) - } - } - }) - - cr.socket = socket.NewSocket(engio, socket.WithAuthTokenFn(func() string { - token, err := cr.GetAuthToken(ctx) - if err != nil { - log.Errorf(Tr("error.cluster.auth.failed"), err) - osExit(CodeServerOrEnvionmentError) - } - return token - })) - cr.socket.OnBeforeConnect(func(*socket.Socket) { - log.Infof(Tr("info.cluster.connect.prepare"), cr.reconnectCount, config.MaxReconnectCount) - }) - cr.socket.OnConnect(func(*socket.Socket, string) { - connected = true - log.Debugf("shouldEnable is %v", cr.shouldEnable.Load()) - if cr.shouldEnable.Load() { - if err := cr.Enable(ctx); err != nil { - log.Errorf(Tr("error.cluster.enable.failed"), err) - osExit(CodeClientOrEnvionmentError) - } - } - }) - cr.socket.OnDisconnect(func(*socket.Socket, string) { - go cr.disconnected() - }) - cr.socket.OnError(func(_ *socket.Socket, err error) { - if ctx.Err() != nil { - // Ignore if the error is because context cancelled - return - } - log.Errorf("Socket.IO error: %v", err) - }) - cr.socket.OnMessage(func(event string, data []any) { - if event == "message" { - log.Infof("[remote]: %v", data[0]) - } - }) - log.Infof("Dialing %s", engio.URL().String()) - if err := engio.Dial(ctx); err != nil { - log.Errorf("Dial error: %v", err) - return false - } - log.Info("Connecting to socket.io namespace") - if err := cr.socket.Connect(""); err != nil { - log.Errorf("Open namespace error: %v", err) - return false - } - return true -} - -func (cr *Cluster) WaitForEnable() <-chan struct{} { - if cr.enabled.Load() { - return closedCh - } - - cr.mux.Lock() - defer cr.mux.Unlock() - - if cr.enabled.Load() { - return closedCh - } - ch := make(chan struct{}, 0) - cr.waitEnable = append(cr.waitEnable, ch) - return ch -} - -type EnableData struct { - Host string `json:"host"` - Port uint16 `json:"port"` - Version string `json:"version"` - Byoc bool `json:"byoc"` - NoFastEnable bool `json:"noFastEnable"` - Flavor ConfigFlavor `json:"flavor"` -} - -type ConfigFlavor struct { - Runtime string `json:"runtime"` - Storage string `json:"storage"` -} - -func (cr *Cluster) Enable(ctx context.Context) (err error) { - cr.mux.Lock() - defer cr.mux.Unlock() - - if cr.enabled.Load() { - log.Debug("Extra enable") - return - } - - if cr.socket != nil && !cr.socket.IO().Connected() && config.MaxReconnectCount == 0 { - log.Error(Tr("error.cluster.disconnected")) - osExit(CodeServerOrEnvionmentError) - return - } - - cr.shouldEnable.Store(true) - - storagesCount := make(map[string]int, 2) - for _, s := range cr.storageOpts { - switch s.Type { - case storage.StorageLocal: - storagesCount["file"]++ - case storage.StorageMount, storage.StorageWebdav: - storagesCount["alist"]++ - default: - log.Errorf("Unknown storage type %q", s.Type) - } - } - storageStr := "" - for s, _ := range storagesCount { - if len(storageStr) > 0 { - storageStr += "+" - } - storageStr += s - } - - log.Info(Tr("info.cluster.enable.sending")) - resCh, err := cr.socket.EmitWithAck("enable", EnableData{ - Host: cr.host, - Port: cr.publicPort, - Version: build.ClusterVersion, - Byoc: cr.byoc, - NoFastEnable: config.Advanced.NoFastEnable, - Flavor: ConfigFlavor{ - Runtime: "golang/" + runtime.GOOS + "-" + runtime.GOARCH, - Storage: storageStr, - }, - }) - if err != nil { - return - } - var data []any - tctx, cancel := context.WithTimeout(ctx, time.Minute*6) - select { - case <-tctx.Done(): - cancel() - return tctx.Err() - case data = <-resCh: - cancel() - } - log.Debug("got enable ack:", data) - if ero := data[0]; ero != nil { - if ero, ok := ero.(map[string]any); ok { - if msg, ok := ero["message"].(string); ok { - if hashMismatch := reFileHashMismatchError.FindStringSubmatch(msg); hashMismatch != nil { - hash := hashMismatch[1] - log.Warnf("Detected hash mismatch error, removing bad file %s", hash) - for _, s := range cr.storages { - s.Remove(hash) - } - } - return fmt.Errorf("Enable failed: %v", msg) - } - } - return fmt.Errorf("Enable failed: %v", ero) - } - if !data[1].(bool) { - return errors.New("Enable ack non true value") - } - log.Info(Tr("info.cluster.enabled")) - cr.reconnectCount = 0 - cr.disabled = make(chan struct{}, 0) - cr.enabled.Store(true) - for _, ch := range cr.waitEnable { - close(ch) - } - cr.waitEnable = cr.waitEnable[:0] - go cr.notifyManager.OnEnabled() - - const maxFailCount = 3 - var ( - keepaliveCtx context.Context - failedCount = 0 - ) - keepaliveCtx, cr.cancelKeepalive = context.WithCancel(ctx) - createInterval(keepaliveCtx, func() { - tctx, cancel := context.WithTimeout(keepaliveCtx, KeepAliveInterval/2) - status := cr.KeepAlive(tctx) - cancel() - if status == 0 { - failedCount = 0 - return - } - if status == -1 { - log.Errorf("Kicked by remote server!!!") - osExit(CodeEnvironmentError) - return - } - if keepaliveCtx.Err() == nil { - if tctx.Err() != nil { - failedCount++ - log.Warnf("keep-alive failed (%d/%d)", failedCount, maxFailCount) - if failedCount < maxFailCount { - return - } - } - log.Info(Tr("info.cluster.reconnect.keepalive")) - cr.disable(ctx) - log.Info(Tr("info.cluster.reconnecting")) - if !cr.Connect(ctx) { - log.Error(Tr("error.cluster.reconnect.failed")) - if ctx.Err() != nil { - return - } - osExit(CodeServerOrEnvionmentError) - } - if err := cr.Enable(ctx); err != nil { - log.Errorf(Tr("error.cluster.enable.failed"), err) - if ctx.Err() != nil { - return - } - osExit(CodeClientOrEnvionmentError) - } - } - }, KeepAliveInterval) - return -} - -// KeepAlive will fresh hits & hit bytes data and send the keep-alive packet -func (cr *Cluster) KeepAlive(ctx context.Context) (status int) { - hits, hbts := cr.stats.GetTmpHits() - lhits, lhbts := cr.lastHits.Load(), cr.lastHbts.Load() - hits2, hbts2 := cr.statOnlyHits.Load(), cr.statOnlyHbts.Load() - ahits, ahbts := hits-lhits-hits2, hbts-lhbts-hbts2 - resCh, err := cr.socket.EmitWithAck("keep-alive", Map{ - "time": time.Now().UTC().Format("2006-01-02T15:04:05Z"), - "hits": ahits, - "bytes": ahbts, - }) - go cr.notifyManager.OnReportStatus(&cr.stats) - - if e := cr.stats.Save(cr.dataDir); e != nil { - log.Errorf(Tr("error.cluster.stat.save.failed"), e) - } - if err != nil { - log.Errorf(Tr("error.cluster.keepalive.send.failed"), err) - return 1 - } - var data []any - select { - case <-ctx.Done(): - return 1 - case data = <-resCh: - } - log.Debugf("Keep-alive response: %v", data) - if ero := data[0]; len(data) <= 1 || ero != nil { - if ero, ok := ero.(map[string]any); ok { - if msg, ok := ero["message"].(string); ok { - if hashMismatch := reFileHashMismatchError.FindStringSubmatch(msg); hashMismatch != nil { - hash := hashMismatch[1] - log.Warnf("Detected hash mismatch error, removing bad file %s", hash) - for _, s := range cr.storages { - s.Remove(hash) - } - } - log.Errorf(Tr("error.cluster.keepalive.failed"), msg) - return 1 - } - } - log.Errorf(Tr("error.cluster.keepalive.failed"), ero) - return 1 - } - log.Infof(Tr("info.cluster.keepalive.success"), ahits, utils.BytesToUnit((float64)(ahbts)), data[1]) - cr.lastHits.Store(hits) - cr.lastHbts.Store(hbts) - cr.statOnlyHits.Add(-hits2) - cr.statOnlyHbts.Add(-hbts2) - if data[1] == false { - return -1 - } - return 0 -} - -func (cr *Cluster) disconnected() bool { - cr.mux.Lock() - defer cr.mux.Unlock() - - if cr.enabled.CompareAndSwap(true, false) { - return false - } - if cr.cancelKeepalive != nil { - cr.cancelKeepalive() - cr.cancelKeepalive = nil - } - cr.notifyManager.OnDisabled() - return true -} - -func (cr *Cluster) Disable(ctx context.Context) (ok bool) { - cr.shouldEnable.Store(false) - return cr.disable(ctx) -} - -func (cr *Cluster) disable(ctx context.Context) (ok bool) { - cr.mux.Lock() - defer cr.mux.Unlock() - - if !cr.enabled.Load() { - log.Debug("Extra disable") - return false - } - - defer cr.notifyManager.OnDisabled() - - if cr.cancelKeepalive != nil { - cr.cancelKeepalive() - cr.cancelKeepalive = nil - } - if cr.socket == nil { - return false - } - log.Info(Tr("info.cluster.disabling")) - resCh, err := cr.socket.EmitWithAck("disable", nil) - if err == nil { - tctx, cancel := context.WithTimeout(ctx, time.Second*(time.Duration)(config.Advanced.KeepaliveTimeout)) - select { - case <-tctx.Done(): - cancel() - err = tctx.Err() - case data := <-resCh: - cancel() - log.Debug("disable ack:", data) - if ero := data[0]; ero != nil { - log.Errorf("Disable failed: %v", ero) - } else if !data[1].(bool) { - log.Error("Disable failed: acked non true value") - } else { - ok = true - } - } - } - if err != nil { - log.Errorf(Tr("error.cluster.disable.failed"), err) - } - - cr.enabled.Store(false) - go cr.socket.Close() - cr.socket = nil - close(cr.disabled) - log.Warn(Tr("warn.cluster.disabled")) - return -} - -func (cr *Cluster) Enabled() bool { - return cr.enabled.Load() -} - -func (cr *Cluster) Disabled() <-chan struct{} { - cr.mux.RLock() - defer cr.mux.RUnlock() - return cr.disabled -} - -type CertKeyPair struct { - Cert string `json:"cert"` - Key string `json:"key"` -} - -func (cr *Cluster) RequestCert(ctx context.Context) (ckp *CertKeyPair, err error) { - resCh, err := cr.socket.EmitWithAck("request-cert") - if err != nil { - return - } - var data []any - select { - case <-ctx.Done(): - return nil, ctx.Err() - case data = <-resCh: - } - if ero := data[0]; ero != nil { - err = fmt.Errorf("socket.io remote error: %v", ero) - return - } - pair := data[1].(map[string]any) - ckp = &CertKeyPair{ - Cert: pair["cert"].(string), - Key: pair["key"].(string), - } - return -} - -func (cr *Cluster) GetConfig(ctx context.Context) (cfg *OpenbmclapiAgentConfig, err error) { - req, err := cr.makeReqWithAuth(ctx, http.MethodGet, "/openbmclapi/configuration", nil) - if err != nil { - return - } - res, err := cr.cachedCli.Do(req) - if err != nil { - return - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK { - err = utils.NewHTTPStatusErrorFromResponse(res) - return - } - cfg = new(OpenbmclapiAgentConfig) - if err = json.NewDecoder(res.Body).Decode(cfg); err != nil { - cfg = nil - return - } - return -} diff --git a/cluster/cluster.go b/cluster/cluster.go new file mode 100644 index 00000000..35d7df4b --- /dev/null +++ b/cluster/cluster.go @@ -0,0 +1,389 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "context" + "errors" + "fmt" + "regexp" + "runtime" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/LiterMC/socket.io" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/config" + "github.com/LiterMC/go-openbmclapi/internal/build" + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/storage" +) + +var ( + reFileHashMismatchError = regexp.MustCompile(` hash mismatch, expected ([0-9a-f]+), got ([0-9a-f]+)`) +) + +const DefaultBMCLAPIServer = "https://openbmclapi.bangbang93.com" + +type Cluster struct { + name string + opts config.ClusterOptions + gcfg config.ClusterGeneralConfig + + storageManager *storage.Manager + storages []int // the index of storages in the storage manager + statManager *StatManager + + enableSignals []chan bool + disableSignal chan struct{} + hits atomic.Int32 + hbts atomic.Int64 + + mux sync.RWMutex + status atomic.Int32 + shouldEnable atomic.Bool + socket *socket.Socket + client *HTTPClient + + authTokenMux sync.RWMutex + authToken *ClusterToken + fileListLastMod int64 +} + +var _ api.Cluster = (*Cluster)(nil) + +func NewCluster( + name string, opts config.ClusterOptions, gcfg config.ClusterGeneralConfig, + storageManager *storage.Manager, + statManager *StatManager, + client *HTTPClient, +) (cr *Cluster) { + storages := make([]int, len(opts.Storages)) + for i, name := range opts.Storages { + storages[i] = storageManager.GetIndex(name) + } + if opts.Server == "" { + opts.Server = DefaultBMCLAPIServer + } + cr = &Cluster{ + name: name, + opts: opts, + gcfg: gcfg, + + storageManager: storageManager, + storages: storages, + statManager: statManager, + client: client, + } + return +} + +// ID returns the cluster id +// The ID may not be unique in the OpenBMCLAPI cluster runtime. +// To identify the cluster instance for analyzing, use Name instead. +func (cr *Cluster) ID() string { + return cr.opts.Id +} + +// Name returns the cluster's alias name +// The name must be unique in the OpenBMCLAPI cluster runtime. +func (cr *Cluster) Name() string { + return cr.name +} + +// Secret returns the cluster secret +func (cr *Cluster) Secret() string { + return cr.opts.Secret +} + +// Host returns the cluster public host +func (cr *Cluster) Host() string { + return cr.gcfg.PublicHost +} + +// Port returns the cluster public port +func (cr *Cluster) Port() uint16 { + return cr.gcfg.PublicPort +} + +// PublicHosts returns the cluster public hosts +func (cr *Cluster) PublicHosts() []string { + return cr.opts.PublicHosts +} + +// AcceptHost checks if the host is binded to the cluster +func (cr *Cluster) AcceptHost(host string) bool { + host = strings.ToUpper(host) + for _, h := range cr.opts.PublicHosts { + if h == "*" || strings.ToUpper(h) == host { + return true + } + } + return false +} + +func (cr *Cluster) Options() *config.ClusterOptions { + return &cr.opts +} + +func (cr *Cluster) GeneralConfig() *config.ClusterGeneralConfig { + return &cr.gcfg +} + +// Init do setup on the cluster +// Init should only be called once during the cluster's whole life +// The context passed in only affect the logical of Init method +func (cr *Cluster) Init(ctx context.Context) error { + for i, ind := range cr.storages { + if ind == -1 { + return fmt.Errorf("Storage %q does not exists", cr.opts.Storages[i]) + } + } + return nil +} + +type EnableData struct { + Host string `json:"host"` + Port uint16 `json:"port"` + Version string `json:"version"` + Byoc bool `json:"byoc"` + NoFastEnable bool `json:"noFastEnable"` + Flavor ConfigFlavor `json:"flavor"` +} + +type ConfigFlavor struct { + Runtime string `json:"runtime"` + Storage string `json:"storage"` +} + +// Enable send enable packet to central server +// The context passed in only affect the logical of Enable method +func (cr *Cluster) Enable(ctx context.Context) error { + if cr.Status() == api.ClusterEnabled { + return nil + } + + cr.mux.Lock() + defer cr.mux.Unlock() + + if !cr.status.CompareAndSwap(api.ClusterDisabled, api.ClusterEnabling) { + return nil + } + + if err := cr.enable(ctx); err != nil { + cr.status.Store(api.ClusterDisabled) + return err + } + + enabled := cr.Status().Running() + for _, ch := range cr.enableSignals { + ch <- enabled + } + cr.enableSignals = cr.enableSignals[:0] + return nil +} + +type enableError struct { + Err any +} + +func (e *enableError) Error() string { + return fmt.Sprintf("Enable Failed: %v", e.Err) +} + +func (cr *Cluster) enable(ctx context.Context) error { + storageStr := cr.storageManager.GetFlavorString(cr.storages) + + log.TrInfof("info.cluster.enable.sending") + resCh, err := cr.socket.EmitWithAck("enable", EnableData{ + Host: cr.gcfg.PublicHost, + Port: cr.gcfg.PublicPort, + Version: build.ClusterVersion, + Byoc: cr.opts.Byoc, + NoFastEnable: cr.gcfg.NoFastEnable, + Flavor: ConfigFlavor{ + Runtime: "golang/" + runtime.GOOS + "-" + runtime.GOARCH, + Storage: storageStr, + }, + }) + if err != nil { + return err + } + var data []any + { + tctx, cancel := context.WithTimeout(ctx, time.Minute*6) + select { + case data = <-resCh: + cancel() + case <-tctx.Done(): + cancel() + return tctx.Err() + } + } + log.Debug("got enable ack:", data) + if ero := data[0]; ero != nil { + if ero, ok := ero.(map[string]any); ok { + if msg, ok := ero["message"].(string); ok { + if hashMismatch := reFileHashMismatchError.FindStringSubmatch(msg); hashMismatch != nil { + hash := hashMismatch[1] + log.TrWarnf("warn.cluster.detected.hash.mismatch", hash) + cr.storageManager.RemoveForAll(hash) + } + return &enableError{msg} + } + } + return &enableError{ero} + } + if v := data[1]; !v.(bool) { + return fmt.Errorf("FATAL: Enable acked non true value, got (%T) %#v", v, v) + } + disableSignal := make(chan struct{}, 0) + cr.disableSignal = disableSignal + log.TrInfof("info.cluster.enabled") + cr.status.Store(api.ClusterEnabled) + cr.socket.OnceConnect(func(_ *socket.Socket, ns string) { + if ns != "" { + return + } + cr.status.Store(api.ClusterDisabled) + if !cr.shouldEnable.Load() { + return + } + select { + case <-disableSignal: + return + default: + } + go cr.reEnable(disableSignal) + }) + cr.socket.OnceDisconnect(func(_ *socket.Socket, ns string) { + if ns != "" { + return + } + cr.status.Store(api.ClusterDisconnected) + }) + return nil +} + +func (cr *Cluster) reEnable(disableSignal <-chan struct{}) { + const ReEnableTimeout = time.Minute * 5 + + if !cr.status.CompareAndSwap(api.ClusterDisabled, api.ClusterEnabling) { + return + } + tctx, cancel := context.WithTimeout(context.Background(), ReEnableTimeout) + go func() { + select { + case <-tctx.Done(): + case <-disableSignal: + cancel() + } + }() + err := cr.enable(tctx) + cancel() + if err == nil { + return + } + log.TrErrorf("error.cluster.enable.failed", err) + if cr.Status() != api.ClusterEnabled { + return + } + ctx, cancel := context.WithCancel(context.Background()) + timer := time.AfterFunc(time.Minute, func() { + cancel() + cr.reEnable(disableSignal) + }) + go func() { + select { + case <-ctx.Done(): + case <-disableSignal: + timer.Stop() + cancel() + } + }() +} + +// Disable send disable packet to central server +// The context passed in only affect the logical of Disable method +// Disable method is thread-safe, and it will wait until the first invoke exited +// Connection will not be closed after disable +func (cr *Cluster) Disable(ctx context.Context) error { + if cr.Status().Enabled() { + cr.mux.Lock() + defer cr.mux.Unlock() + if cr.Status().Enabled() { + defer close(cr.disableSignal) + defer cr.status.Store(api.ClusterDisabled) + return cr.disable(ctx) + } + } + // sync disable + cr.mux.RLock() + disableCh := cr.disableSignal + cr.mux.RUnlock() + if disableCh == nil { + return nil + } + select { + case <-disableCh: + case <-ctx.Done(): + return ctx.Err() + } + return nil +} + +// disable send disable packet to central server +// The context passed in only affect the logical of disable method +func (cr *Cluster) disable(ctx context.Context) error { + log.TrInfof("info.cluster.disabling") + resCh, err := cr.socket.EmitWithAck("disable", nil) + if err != nil { + return err + } + select { + case data := <-resCh: + log.Debug("disable ack:", data) + if ero := data[0]; ero != nil { + return fmt.Errorf("Disable failed: %v", ero) + } else if !data[1].(bool) { + return errors.New("Disable acked non true value") + } + case <-ctx.Done(): + return ctx.Err() + } + return nil +} + +// markKicked marks the cluster as kicked +func (cr *Cluster) markKicked() { + if !cr.Status().Enabled() { + return + } + cr.mux.Lock() + defer cr.mux.Unlock() + if cr.Status().Enabled() { + return + } + defer close(cr.disableSignal) + cr.status.Store(api.ClusterDisabled) +} diff --git a/cluster/handler.go b/cluster/handler.go new file mode 100644 index 00000000..118f6d12 --- /dev/null +++ b/cluster/handler.go @@ -0,0 +1,209 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "crypto" + "encoding/base64" + "encoding/hex" + "fmt" + "io" + "net/http" + "net/textproto" + "strconv" + "strings" + "time" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/storage" +) + +func (cr *Cluster) HandleFile(rw http.ResponseWriter, req *http.Request, hash string) { + defer log.RecoverPanic(nil) + + if !cr.Status().Enabled() { + // do not serve file if cluster is not enabled yet + http.Error(rw, "Cluster is not enabled yet", http.StatusServiceUnavailable) + return + } + + if !cr.checkQuerySign(req, hash) { + http.Error(rw, "Cannot verify signature", http.StatusForbidden) + return + } + + log.Debugf("Handling download %s", hash) + + keepaliveRec := req.Context().Value("go-openbmclapi.handler.no.record.for.keepalive") != true + + countUA := true + if r := req.Header.Get("Range"); r != "" { + api.SetAccessInfo(req, "range", r) + if start, ok := parseRangeFirstStart(r); ok && start != 0 { + countUA = false + } + } + ua := "" + if countUA { + ua, _, _ = strings.Cut(req.UserAgent(), " ") + ua, _, _ = strings.Cut(ua, "/") + } + + rw.Header().Set("X-Bmclapi-Hash", hash) + + if _, ok := emptyHashes[hash]; ok { + name := req.URL.Query().Get("name") + rw.Header().Set("ETag", `"`+hash+`"`) + rw.Header().Set("Cache-Control", "public, max-age=31536000, immutable") // cache for a year + rw.Header().Set("Content-Type", "application/octet-stream") + rw.Header().Set("Content-Length", "0") + if name != "" { + rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name)) + } + rw.WriteHeader(http.StatusOK) + cr.statManager.AddHit(0, cr.ID(), "", ua) + if keepaliveRec { + cr.hits.Add(1) + } + return + } + + api.SetAccessInfo(req, "cluster", cr.ID()) + + var size int64 = -1 // TODO: get the size + + var ( + sto storage.Storage + err error + ) + ok := cr.storageManager.ForEachFromRandom(cr.storages, func(s storage.Storage) bool { + sto = s + opts := s.Options() + log.Debugf("[handler]: Checking %s on storage %s ...", hash, opts.Id) + + sz, er := s.ServeDownload(rw, req, hash, size) + if er != nil { + log.Debugf("[handler]: File %s failed on storage %s: %v", hash, opts.Id, er) + err = er + return false + } + if sz >= 0 { + if keepaliveRec { + cr.hits.Add(1) + cr.hbts.Add(sz) + } + cr.statManager.AddHit(sz, cr.ID(), opts.Id, ua) + } + return true + }) + if sto != nil { + api.SetAccessInfo(req, "storage", sto.Id()) + } + if ok { + return + } + http.Error(rw, err.Error(), http.StatusInternalServerError) +} + +func (cr *Cluster) HandleMeasure(rw http.ResponseWriter, req *http.Request, size int) { + if !cr.Status().Enabled() { + // do not serve file if cluster is not enabled yet + http.Error(rw, "Cluster is not enabled yet", http.StatusServiceUnavailable) + return + } + + if !cr.checkQuerySign(req, req.URL.Path) { + http.Error(rw, "Cannot verify signature", http.StatusForbidden) + return + } + + api.SetAccessInfo(req, "cluster", cr.ID()) + storage := cr.storageManager.Storages[cr.storages[0]] + api.SetAccessInfo(req, "storage", storage.Id()) + if err := storage.ServeMeasure(rw, req, size); err != nil { + log.Errorf("Could not serve measure %d: %v", size, err) + api.SetAccessInfo(req, "error", err.Error()) + http.Error(rw, err.Error(), http.StatusInternalServerError) + } +} + +func (cr *Cluster) checkQuerySign(req *http.Request, hash string) bool { + if cr.opts.SkipSignatureCheck { + return true + } + query := req.URL.Query() + sign, e := query.Get("s"), query.Get("e") + if len(sign) == 0 || len(e) == 0 { + return false + } + before, err := strconv.ParseInt(e, 36, 64) + if err != nil { + return false + } + if time.Now().UnixMilli() > before { + return false + } + hs := crypto.SHA1.New() + io.WriteString(hs, cr.Secret()) + io.WriteString(hs, hash) + io.WriteString(hs, e) + var ( + buf [20]byte + sbuf [27]byte + ) + base64.RawURLEncoding.Encode(sbuf[:], hs.Sum(buf[:0])) + if (string)(sbuf[:]) != sign { + return false + } + return true +} + +var emptyHashes = func() (hashes map[string]struct{}) { + hashMethods := []crypto.Hash{ + crypto.MD5, crypto.SHA1, + } + hashes = make(map[string]struct{}, len(hashMethods)) + for _, h := range hashMethods { + hs := hex.EncodeToString(h.New().Sum(nil)) + hashes[hs] = struct{}{} + } + return +}() + +// Note: this method is a fast parse, it does not deeply check if the range is valid or not +func parseRangeFirstStart(rg string) (start int64, ok bool) { + const b = "bytes=" + if rg, ok = strings.CutPrefix(rg, b); !ok { + return + } + rg, _, _ = strings.Cut(rg, ",") + if rg, _, ok = strings.Cut(rg, "-"); !ok { + return + } + if rg = textproto.TrimString(rg); rg == "" { + return -1, true + } + start, err := strconv.ParseInt(rg, 10, 64) + if err != nil { + return 0, false + } + return start, true +} diff --git a/cluster/http.go b/cluster/http.go new file mode 100644 index 00000000..4f16136b --- /dev/null +++ b/cluster/http.go @@ -0,0 +1,146 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "context" + "errors" + "io" + "net" + "net/http" + "net/url" + "path" + + "github.com/gregjones/httpcache" + + gocache "github.com/LiterMC/go-openbmclapi/cache" + "github.com/LiterMC/go-openbmclapi/internal/build" + "github.com/LiterMC/go-openbmclapi/utils" +) + +type HTTPClient struct { + cli, cachedCli *http.Client +} + +func NewHTTPClient(dialer *net.Dialer, cache gocache.Cache) *HTTPClient { + transport := http.DefaultTransport + if dialer != nil { + transport = &http.Transport{ + DialContext: dialer.DialContext, + } + } + transport = utils.NewRoundTripRedirectErrorWrapper(transport) + cachedTransport := transport + if cache != gocache.NoCache { + cachedTransport = &httpcache.Transport{ + Transport: transport, + Cache: gocache.WrapToHTTPCache(gocache.NewCacheWithNamespace(cache, "http@")), + } + } + return &HTTPClient{ + cli: &http.Client{ + Transport: transport, + CheckRedirect: redirectChecker, + }, + cachedCli: &http.Client{ + Transport: cachedTransport, + CheckRedirect: redirectChecker, + }, + } +} + +func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) { + return c.cli.Do(req) +} + +func (c *HTTPClient) DoUseCache(req *http.Request) (*http.Response, error) { + return c.cachedCli.Do(req) +} + +func (c *HTTPClient) Client() *http.Client { + return c.cli +} + +func (c *HTTPClient) CachedClient() *http.Client { + return c.cachedCli +} + +func redirectChecker(req *http.Request, via []*http.Request) error { + req.Header.Del("Referer") + if len(via) > 10 { + return errors.New("More than 10 redirects detected") + } + return nil +} + +func (cr *Cluster) getFullURL(relpath string) (u *url.URL, err error) { + if u, err = url.Parse(cr.opts.Server); err != nil { + return + } + u.Path = path.Join(u.Path, relpath) + return +} + +func (cr *Cluster) makeReq(ctx context.Context, method string, relpath string, query url.Values) (req *http.Request, err error) { + return cr.makeReqWithBody(ctx, method, relpath, query, nil) +} + +func (cr *Cluster) makeReqWithBody( + ctx context.Context, + method string, relpath string, + query url.Values, body io.Reader, +) (req *http.Request, err error) { + u, err := cr.getFullURL(relpath) + if err != nil { + return + } + if query != nil { + u.RawQuery = query.Encode() + } + target := u.String() + + req, err = http.NewRequestWithContext(ctx, method, target, body) + if err != nil { + return + } + req.Header.Set("User-Agent", build.ClusterUserAgent) + return +} + +func (cr *Cluster) makeReqWithAuth(ctx context.Context, method string, relpath string, query url.Values) (req *http.Request, err error) { + return cr.makeReqWithAuthBody(ctx, method, relpath, query, nil) +} + +func (cr *Cluster) makeReqWithAuthBody( + ctx context.Context, + method string, relpath string, + query url.Values, body io.Reader, +) (req *http.Request, err error) { + req, err = cr.makeReqWithBody(ctx, method, relpath, query, body) + if err != nil { + return + } + token, err := cr.GetAuthToken(ctx) + if err != nil { + return + } + req.Header.Set("Authorization", "Bearer "+token) + return +} diff --git a/cluster/keepalive.go b/cluster/keepalive.go new file mode 100644 index 00000000..78fc2eef --- /dev/null +++ b/cluster/keepalive.go @@ -0,0 +1,87 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "context" + "time" + + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/utils" +) + +type KeepAliveRes int + +const ( + KeepAliveSucceed KeepAliveRes = iota + KeepAliveFailed + KeepAliveKicked +) + +type keepAliveReq struct { + Time string `json:"time"` + Hits int32 `json:"hits"` + Bytes int64 `json:"bytes"` +} + +// KeepAlive will send the keep-alive packet and fresh hits & hit bytes data +// If cluster is kicked by the central server, the cluster status will be mark as kicked +func (cr *Cluster) KeepAlive(ctx context.Context) KeepAliveRes { + hits, hbts := cr.hits.Load(), cr.hbts.Load() + resCh, err := cr.socket.EmitWithAck("keep-alive", keepAliveReq{ + Time: time.Now().UTC().Format("2006-01-02T15:04:05Z"), + Hits: hits, + Bytes: hbts, + }) + if err != nil { + log.TrErrorf("error.cluster.keepalive.send.failed", err) + return KeepAliveFailed + } + var data []any + select { + case <-ctx.Done(): + return KeepAliveFailed + case data = <-resCh: + } + log.Debugf("Keep-alive response: %v", data) + if ero := data[0]; len(data) <= 1 || ero != nil { + if ero, ok := ero.(map[string]any); ok { + if msg, ok := ero["message"].(string); ok { + log.TrErrorf("error.cluster.keepalive.failed", msg) + if hashMismatch := reFileHashMismatchError.FindStringSubmatch(msg); hashMismatch != nil { + hash := hashMismatch[1] + log.Warnf("Detected hash mismatch error, removing bad file %s", hash) + cr.storageManager.RemoveForAll(hash) + } + return KeepAliveFailed + } + } + log.TrErrorf("error.cluster.keepalive.failed", ero) + return KeepAliveFailed + } + log.TrInfof("info.cluster.keepalive.success", hits, utils.BytesToUnit((float64)(hbts)), data[1]) + cr.hits.Add(-hits) + cr.hbts.Add(-hbts) + if data[1] == false { + cr.markKicked() + return KeepAliveKicked + } + return KeepAliveSucceed +} diff --git a/token.go b/cluster/requests.go similarity index 64% rename from token.go rename to cluster/requests.go index a86f1b91..0899c10e 100644 --- a/token.go +++ b/cluster/requests.go @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -package main +package cluster import ( "bytes" @@ -26,6 +26,8 @@ import ( "crypto/hmac" "encoding/hex" "encoding/json" + "errors" + "fmt" "net/http" "net/url" "time" @@ -85,7 +87,7 @@ func (cr *Cluster) fetchToken(ctx context.Context) (token *ClusterToken, err err } }() req, err := cr.makeReq(ctx, http.MethodGet, "/openbmclapi-agent/challenge", url.Values{ - "clusterId": {cr.clusterId}, + "clusterId": {cr.ID()}, }) if err != nil { return @@ -109,7 +111,7 @@ func (cr *Cluster) fetchToken(ctx context.Context) (token *ClusterToken, err err } var buf [32]byte - hs := hmac.New(crypto.SHA256.New, ([]byte)(cr.clusterSecret)) + hs := hmac.New(crypto.SHA256.New, ([]byte)(cr.Secret())) hs.Write(([]byte)(res1.Challenge)) signature := hex.EncodeToString(hs.Sum(buf[:0])) @@ -118,7 +120,7 @@ func (cr *Cluster) fetchToken(ctx context.Context) (token *ClusterToken, err err Challenge string `json:"challenge"` Signature string `json:"signature"` }{ - ClusterId: cr.clusterId, + ClusterId: cr.ID(), Challenge: res1.Challenge, Signature: signature, }) @@ -158,7 +160,7 @@ func (cr *Cluster) refreshToken(ctx context.Context, oldToken string) (token *Cl ClusterId string `json:"clusterId"` Token string `json:"token"` }{ - ClusterId: cr.clusterId, + ClusterId: cr.ID(), Token: oldToken, }) if err != nil { @@ -193,3 +195,105 @@ func (cr *Cluster) refreshToken(ctx context.Context, oldToken string) (token *Cl ExpireAt: time.Now().Add((time.Duration)(res.TTL)*time.Millisecond - 10*time.Second), }, nil } + +type OpenbmclapiAgentConfig struct { + Sync OpenbmclapiAgentSyncConfig `json:"sync"` +} + +type OpenbmclapiAgentSyncConfig struct { + Source string `json:"source"` + Concurrency int `json:"concurrency"` +} + +func (cr *Cluster) GetConfig(ctx context.Context) (cfg *OpenbmclapiAgentConfig, err error) { + req, err := cr.makeReqWithAuth(ctx, http.MethodGet, "/openbmclapi/configuration", nil) + if err != nil { + return + } + res, err := cr.client.DoUseCache(req) + if err != nil { + return + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + err = utils.NewHTTPStatusErrorFromResponse(res) + return + } + cfg = new(OpenbmclapiAgentConfig) + if err = json.NewDecoder(res.Body).Decode(cfg); err != nil { + cfg = nil + return + } + return +} + +type CertKeyPair struct { + Cert string `json:"cert"` + Key string `json:"key"` +} + +func (cr *Cluster) RequestCert(ctx context.Context) (ckp *CertKeyPair, err error) { + resCh, err := cr.socket.EmitWithAck("request-cert") + if err != nil { + return + } + var data []any + select { + case <-ctx.Done(): + return nil, ctx.Err() + case data = <-resCh: + } + if ero := data[0]; ero != nil { + err = fmt.Errorf("socket.io remote error: %v", ero) + return + } + pair := data[1].(map[string]any) + ckp = new(CertKeyPair) + var ok bool + if ckp.Cert, ok = pair["cert"].(string); !ok { + err = fmt.Errorf(`"cert" is not a string, got %T`, pair["cert"]) + return + } + if ckp.Key, ok = pair["key"].(string); !ok { + err = fmt.Errorf(`"key" is not a string, got %T`, pair["key"]) + return + } + return +} + +func (cr *Cluster) ReportDownload(ctx context.Context, response *http.Response, err error) error { + if errors.Is(err, context.Canceled) { + return nil + } + + type ReportPayload struct { + Urls []string `json:"urls"` + Error utils.EmbedJSON[struct { + Message string `json:"message"` + }] `json:"error"` + } + var payload ReportPayload + redirects := utils.GetRedirects(response) + payload.Urls = make([]string, len(redirects)) + for i, u := range redirects { + payload.Urls[i] = u.String() + } + payload.Error.V.Message = err.Error() + data, err := json.Marshal(payload) + if err != nil { + return err + } + req, err := cr.makeReqWithAuthBody(ctx, http.MethodPost, "/openbmclapi/report", nil, bytes.NewReader(data)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err := cr.client.Do(req) + if err != nil { + return err + } + if resp.StatusCode/100 != 2 { + return utils.NewHTTPStatusErrorFromResponse(resp) + } + return nil +} diff --git a/cluster/socket.go b/cluster/socket.go new file mode 100644 index 00000000..a84625ab --- /dev/null +++ b/cluster/socket.go @@ -0,0 +1,145 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + "github.com/LiterMC/socket.io" + "github.com/LiterMC/socket.io/engine.io" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/internal/build" + "github.com/LiterMC/go-openbmclapi/log" +) + +// Connect connects to the central server +// The context passed in only affect the logical of Connect method +// Connection will not be closed after disable +// +// See Disconnect +func (cr *Cluster) Connect(ctx context.Context) error { + if !cr.Status().Disconnected() { + return errors.New("Attempt to connect while connecting") + } + + cr.status.Store(api.ClusterConnecting) + defer cr.status.CompareAndSwap(api.ClusterConnecting, api.ClusterDisconnected) + + _, err := cr.GetAuthToken(ctx) + if err != nil { + return fmt.Errorf("Auth failed %w", err) + } + + engio, err := engine.NewSocket(engine.Options{ + Host: cr.opts.Server, + Path: "/socket.io/", + ExtraHeaders: http.Header{ + "Origin": {cr.opts.Server}, + "User-Agent": {build.ClusterUserAgent}, + }, + DialTimeout: time.Minute * 6, + }) + if err != nil { + return fmt.Errorf("Could not parse Engine.IO options: %w", err) + } + if ctx.Value("cluster.options.engine-io.debug") == true { + engio.OnRecv(func(s *engine.Socket, data []byte) { + log.Debugf("Engine.IO %s recv: %q", s.ID(), (string)(data)) + }) + engio.OnSend(func(s *engine.Socket, data []byte) { + log.Debugf("Engine.IO %s send: %q", s.ID(), (string)(data)) + }) + } + engio.OnConnect(func(s *engine.Socket) { + log.Infof("Engine.IO %s connected for cluster %s", s.ID(), cr.ID()) + }) + engio.OnDisconnect(cr.onDisconnected) + engio.OnDialError(func(s *engine.Socket, err *engine.DialErrorContext) { + if err.Count() < 0 { + return + } + log.TrErrorf("error.cluster.connect.failed", cr.ID(), err.Count(), cr.gcfg.MaxReconnectCount, err.Err()) + if cr.gcfg.MaxReconnectCount >= 0 && err.Count() >= cr.gcfg.MaxReconnectCount { + log.TrErrorf("error.cluster.connect.failed.toomuch", cr.ID()) + s.Close() + } + }) + log.Infof("Dialing %s for cluster %s(%s)", engio.URL().String(), cr.Name(), cr.ID()) + if err := engio.Dial(ctx); err != nil { + return fmt.Errorf("Dial error: %w", err) + } + + cr.socket = socket.NewSocket(engio, socket.WithAuthTokenFn(func() (string, error) { + token, err := cr.GetAuthToken(ctx) + if err != nil { + log.TrErrorf("error.cluster.auth.failed", err) + return "", err + } + return token, nil + })) + cr.socket.OnError(func(_ *socket.Socket, err error) { + log.Errorf("Socket.IO error: %v", err) + }) + cr.socket.OnMessage(func(event string, data []any) { + if event == "message" { + log.Infof("[remote]: %v", data[0]) + } else if event == "exception" { + log.Errorf("[remote exception]: %v", data[0]) + } else if event == "warden-error" { + log.Warnf("[warden]: %v", data[0]) + } + }) + log.Infof("Cluster %s is connecting to socket.io namespace", cr.Name()) + if err := cr.socket.Connect(""); err != nil { + return fmt.Errorf("Namespace connect error: %w", err) + } + + cr.status.Store(api.ClusterDisabled) + return nil +} + +// Disconnect close the connection which connected to the central server +// Disconnect will not disable the cluster +// +// See Connect +func (cr *Cluster) Disconnect(context.Context) error { + if cr.Status().Disconnected() { + return nil + } + cr.mux.Lock() + defer cr.mux.Unlock() + err := cr.socket.Close() + cr.status.Store(api.ClusterDisconnected) + cr.socket = nil + return err +} + +func (cr *Cluster) onDisconnected(s *engine.Socket, err error) { + if err != nil { + log.Warnf("Engine.IO %s disconnected: %v", s.ID(), err) + } + cr.status.Store(api.ClusterDisconnected) + cr.socket = nil +} diff --git a/cluster/stat.go b/cluster/stat.go new file mode 100644 index 00000000..d96a3307 --- /dev/null +++ b/cluster/stat.go @@ -0,0 +1,363 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2023 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "encoding/json" + "errors" + "os" + "path/filepath" + "slices" + "sort" + "strings" + "sync" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/internal/build" +) + +const statsOverallFileName = "stat.json" + +type StatManager struct { + mux sync.RWMutex + + clusters []string + storages []string + + Overall *api.AccessStatData + Clusters map[string]*api.AccessStatData + Storages map[string]*api.AccessStatData +} + +var _ json.Marshaler = (*StatManager)(nil) + +func NewStatManager() *StatManager { + return &StatManager{ + Overall: new(api.AccessStatData), + Clusters: make(map[string]*api.AccessStatData), + Storages: make(map[string]*api.AccessStatData), + } +} + +func (m *StatManager) GetStatus() api.StatusData { + m.mux.RLock() + defer m.mux.RUnlock() + + return api.StatusData{ + StartAt: build.StartAt, + Clusters: m.clusters, + Storages: m.storages, + } +} + +func (m *StatManager) AddCluster(name string) { + m.mux.Lock() + defer m.mux.Unlock() + + i := sort.SearchStrings(m.clusters, name) + if i == len(m.clusters) || m.clusters[i] != name { + m.clusters = slices.Insert(m.clusters, i, name) + } +} + +func (m *StatManager) AddStorage(name string) { + m.mux.Lock() + defer m.mux.Unlock() + + i := sort.SearchStrings(m.storages, name) + if i == len(m.storages) || m.storages[i] != name { + m.storages = slices.Insert(m.storages, i, name) + } +} + +func (m *StatManager) RemoveCluster(name string) { + m.mux.Lock() + defer m.mux.Unlock() + + i := sort.SearchStrings(m.clusters, name) + if i < len(m.clusters) && m.clusters[i] == name { + m.clusters = slices.Delete(m.clusters, i, i+1) + } +} + +func (m *StatManager) RemoveStorage(name string) { + m.mux.Lock() + defer m.mux.Unlock() + + i := sort.SearchStrings(m.storages, name) + if i < len(m.storages) && m.storages[i] == name { + m.storages = slices.Delete(m.storages, i, i+1) + } +} + +func (m *StatManager) RenameCluster(oldName, newName string) { + if oldName == newName { + return + } + m.mux.Lock() + defer m.mux.Unlock() + + oldInd := sort.SearchStrings(m.clusters, oldName) + if oldInd == len(m.clusters) || m.clusters[oldInd] != oldName { + return + } + newInd := sort.SearchStrings(m.clusters, newName) + if oldInd == newInd || oldInd+1 == newInd { + m.clusters[oldInd] = newName + } else if oldInd < newInd { + copy(m.clusters[oldInd:], m.clusters[oldInd+1:newInd]) + m.clusters[newInd-1] = newName + } else /*if oldInd > newInd*/ { + copy(m.clusters[newInd+1:], m.clusters[newInd:oldInd]) + m.clusters[newInd] = newName + } + m.Clusters[newName] = m.Clusters[oldName] + delete(m.Clusters, oldName) +} + +func (m *StatManager) RenameStorage(oldName, newName string) { + if oldName == newName { + return + } + m.mux.Lock() + defer m.mux.Unlock() + + oldInd := sort.SearchStrings(m.storages, oldName) + if oldInd == len(m.storages) || m.storages[oldInd] != oldName { + return + } + newInd := sort.SearchStrings(m.storages, newName) + if oldInd == newInd || oldInd+1 == newInd { + m.storages[oldInd] = newName + } else if oldInd < newInd { + copy(m.storages[oldInd:], m.storages[oldInd+1:newInd]) + m.storages[newInd-1] = newName + } else /*if oldInd > newInd*/ { + copy(m.storages[newInd+1:], m.storages[newInd:oldInd]) + m.storages[newInd] = newName + } + m.Storages[newName] = m.Storages[oldName] + delete(m.Storages, oldName) +} + +var emptyStat = api.NewAccessStatData() + +func (m *StatManager) GetClusterAccessStat(name string) *api.AccessStatData { + d := m.Clusters[name] + if d == nil { + return emptyStat + } + return d +} + +func (m *StatManager) GetStorageAccessStat(name string) *api.AccessStatData { + d := m.Storages[name] + if d == nil { + return emptyStat + } + return d +} + +func (m *StatManager) AddHit(bytes int64, cluster, storage string, userAgent string) { + m.mux.Lock() + defer m.mux.Unlock() + + data := &api.StatInstData{ + Hits: 1, + Bytes: bytes, + } + m.Overall.Update(data) + if userAgent != "" { + m.Overall.Accesses[userAgent]++ + } + if cluster != "" { + d := m.Clusters[cluster] + if d == nil { + d = api.NewAccessStatData() + m.Clusters[cluster] = d + } + d.Update(data) + if userAgent != "" { + d.Accesses[userAgent]++ + } + } + if storage != "" { + d := m.Storages[storage] + if d == nil { + d = api.NewAccessStatData() + m.Storages[storage] = d + } + d.Update(data) + if userAgent != "" { + d.Accesses[userAgent]++ + } + } +} + +func (m *StatManager) Load(dir string) error { + clustersDir, storagesDir := filepath.Join(dir, "clusters"), filepath.Join(dir, "storages") + + m.mux.Lock() + defer m.mux.Unlock() + + *m.Overall = api.AccessStatData{} + clear(m.Clusters) + clear(m.Storages) + + if err := loadStatData(m.Overall, filepath.Join(dir, statsOverallFileName)); err != nil { + return err + } + if entries, err := os.ReadDir(clustersDir); err == nil { + for _, entry := range entries { + if entry.IsDir() { + continue + } + if name, ok := strings.CutSuffix(entry.Name(), ".json"); ok { + d := new(api.AccessStatData) + if err := loadStatData(d, filepath.Join(clustersDir, entry.Name())); err != nil { + return err + } + m.Clusters[name] = d + } + } + } + if entries, err := os.ReadDir(storagesDir); err == nil { + for _, entry := range entries { + if entry.IsDir() { + continue + } + if name, ok := strings.CutSuffix(entry.Name(), ".json"); ok { + d := new(api.AccessStatData) + if err := loadStatData(d, filepath.Join(storagesDir, entry.Name())); err != nil { + return err + } + m.Storages[name] = d + } + } + } + return nil +} + +func (m *StatManager) Save(dir string) error { + clustersDir, storagesDir := filepath.Join(dir, "clusters"), filepath.Join(dir, "storages") + + m.mux.RLock() + defer m.mux.RUnlock() + + if err := saveStatData(m.Overall, filepath.Join(dir, statsOverallFileName)); err != nil { + return err + } + if err := os.Mkdir(clustersDir, 0755); err != nil && !errors.Is(err, os.ErrExist) { + return err + } + if err := os.Mkdir(storagesDir, 0755); err != nil && !errors.Is(err, os.ErrExist) { + return err + } + for name, data := range m.Clusters { + if err := saveStatData(data, filepath.Join(clustersDir, name+".json")); err != nil { + return err + } + } + for name, data := range m.Storages { + if err := saveStatData(data, filepath.Join(storagesDir, name+".json")); err != nil { + return err + } + } + return nil +} + +func (m *StatManager) MarshalJSON() ([]byte, error) { + m.mux.RLock() + defer m.mux.RUnlock() + + return json.Marshal(map[string]any{ + "overall": m.Overall, + "clusters": m.Clusters, + "storages": m.Storages, + }) +} + +func loadStatData(s *api.AccessStatData, name string) error { + if err := parseFileOrOld(name, func(buf []byte) error { + return json.Unmarshal(buf, s) + }); err != nil { + return err + } + + if s.Years == nil { + s.Years = make(map[string]api.StatInstData, 2) + } + if s.Accesses == nil { + s.Accesses = make(map[string]int, 5) + } + return nil +} + +func saveStatData(s *api.AccessStatData, name string) error { + buf, err := json.Marshal(s) + if err != nil { + return err + } + if err := writeFileWithOld(name, buf, 0644); err != nil { + return err + } + return nil +} + +func parseFileOrOld(path string, parser func(buf []byte) error) error { + oldpath := path + ".old" + buf, err := os.ReadFile(path) + if err == nil { + if err = parser(buf); err == nil { + return err + } + } + buf, er := os.ReadFile(oldpath) + if er == nil { + if er = parser(buf); er == nil { + os.WriteFile(path, buf, 0644) + return nil + } + } + if errors.Is(err, os.ErrNotExist) { + if errors.Is(er, os.ErrNotExist) { + return nil + } + err = er + } + return err +} + +func writeFileWithOld(path string, buf []byte, mode os.FileMode) error { + oldpath := path + ".old" + if err := os.Remove(oldpath); err != nil && !errors.Is(err, os.ErrNotExist) { + return err + } + if err := os.Rename(path, oldpath); err != nil && !errors.Is(err, os.ErrNotExist) { + return err + } + if err := os.WriteFile(path, buf, mode); err != nil { + return err + } + if err := os.WriteFile(oldpath, buf, mode); err != nil { + return err + } + return nil +} diff --git a/cluster/status.go b/cluster/status.go new file mode 100644 index 00000000..bdbf6009 --- /dev/null +++ b/cluster/status.go @@ -0,0 +1,53 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "github.com/LiterMC/go-openbmclapi/api" +) + +func (cr *Cluster) Status() api.ClusterStatus { + return (api.ClusterStatus)(cr.status.Load()) +} + +// Disabled returns true if the cluster is disabled manually +func (cr *Cluster) Disabled() bool { + return cr.Status() == api.ClusterDisabled && !cr.shouldEnable.Load() +} + +// IsKicked returns true if the cluster is kicked by the central server +func (cr *Cluster) IsKicked() bool { + return cr.Status() == api.ClusterDisabled && cr.shouldEnable.Load() +} + +// WaitForEnable returns a channel which receives true when cluster enabled succeed, or receives false when it failed to enable +// If the cluster is already enable, the channel always returns true +// The channel should not be used multiple times +func (cr *Cluster) WaitForEnable() <-chan bool { + cr.mux.Lock() + defer cr.mux.Unlock() + ch := make(chan bool, 1) + if cr.Status().Running() { + ch <- true + } else { + cr.enableSignals = append(cr.enableSignals, ch) + } + return ch +} diff --git a/cluster/storage.go b/cluster/storage.go new file mode 100644 index 00000000..f4a3a6cb --- /dev/null +++ b/cluster/storage.go @@ -0,0 +1,772 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster + +import ( + "compress/gzip" + "compress/zlib" + "context" + "crypto" + "encoding/hex" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "runtime" + "slices" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/hamba/avro/v2" + "github.com/klauspost/compress/zstd" + "github.com/vbauerster/mpb/v8" + "github.com/vbauerster/mpb/v8/decor" + + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/lang" + "github.com/LiterMC/go-openbmclapi/limited" + "github.com/LiterMC/go-openbmclapi/log" + "github.com/LiterMC/go-openbmclapi/storage" + "github.com/LiterMC/go-openbmclapi/utils" +) + +// from +var fileListSchema = avro.MustParse(`{ + "type": "array", + "items": { + "type": "record", + "name": "fileinfo", + "fields": [ + {"name": "path", "type": "string"}, + {"name": "hash", "type": "string"}, + {"name": "size", "type": "long"}, + {"name": "mtime", "type": "long"} + ] + } +}`) + +type FileInfo struct { + Path string `json:"path" avro:"path"` + Hash string `json:"hash" avro:"hash"` + Size int64 `json:"size" avro:"size"` + Mtime int64 `json:"mtime" avro:"mtime"` +} + +func (cr *Cluster) GetFileList(ctx context.Context, fileMap map[string]*api.StorageFileInfo, forceAll bool) error { + var query url.Values + lastMod := cr.fileListLastMod + if forceAll { + lastMod = 0 + } + if lastMod > 0 { + query = url.Values{ + "lastModified": {strconv.FormatInt(lastMod, 10)}, + } + } + req, err := cr.makeReqWithAuth(ctx, http.MethodGet, "/openbmclapi/files", query) + if err != nil { + return err + } + res, err := cr.client.DoUseCache(req) + if err != nil { + return err + } + defer res.Body.Close() + switch res.StatusCode { + case http.StatusOK: + case http.StatusNoContent, http.StatusNotModified: + return nil + default: + return utils.NewHTTPStatusErrorFromResponse(res) + } + log.Debug("Parsing filelist body ...") + zr, err := zstd.NewReader(res.Body) + if err != nil { + return err + } + defer zr.Close() + var files []FileInfo + if err := avro.NewDecoderForSchema(fileListSchema, zr).Decode(&files); err != nil { + return err + } + + for _, f := range files { + if f.Mtime > lastMod { + lastMod = f.Mtime + } + if ff, ok := fileMap[f.Hash]; ok { + if ff.Size != f.Size { + log.Panicf("Hash conflict detected, hash of both %q (%dB) and %v (%dB) is %s", f.Path, f.Size, ff.URLs, ff.Size, f.Hash) + } + for _, s := range cr.storages { + sto := cr.storageManager.Storages[s] + if i, ok := slices.BinarySearchFunc(ff.Storages, sto, storageIdSortFunc); !ok { + ff.Storages = slices.Insert(ff.Storages, i, sto) + } + } + } else { + ff := &api.StorageFileInfo{ + Hash: f.Hash, + Size: f.Size, + Storages: make([]storage.Storage, len(cr.storages)), + URLs: make(map[string]api.RequestPath), + } + for i, s := range cr.storages { + ff.Storages[i] = cr.storageManager.Storages[s] + } + slices.SortFunc(ff.Storages, storageIdSortFunc) + req, err := cr.makeReqWithAuth(context.Background(), http.MethodGet, f.Path, nil) + if err != nil { + return err + } + ff.URLs[req.URL.String()] = api.RequestPath{ + Request: req, + Cluster: cr, + Path: f.Path, + } + fileMap[f.Hash] = ff + } + } + cr.fileListLastMod = lastMod + log.Debugf("Filelist parsed, length = %d, lastMod = %d", len(files), lastMod) + return nil +} + +func storageIdSortFunc(a, b storage.Storage) int { + if a.Id() < b.Id() { + return -1 + } + return 1 +} + +var emptyStr string + +func checkFile( + ctx context.Context, + manager *storage.Manager, + files map[string]*api.StorageFileInfo, + heavy bool, + missing map[string]*api.StorageFileInfo, + pg *mpb.Progress, +) (err error) { + var missingCount atomic.Int32 + addMissing := func(f *api.StorageFileInfo, sto storage.Storage) { + missingCount.Add(1) + if info, ok := missing[f.Hash]; ok { + info.Storages = append(info.Storages, sto) + } else { + info := new(api.StorageFileInfo) + *info = *f + info.Storages = []storage.Storage{sto} + missing[f.Hash] = info + } + } + + log.TrInfof("info.check.start", heavy) + + var ( + checkingHash atomic.Pointer[string] + lastCheckingHash string + slots *limited.BufSlots + wg sync.WaitGroup + ) + checkingHash.Store(&emptyStr) + + if heavy { + slots = limited.NewBufSlots(runtime.GOMAXPROCS(0) * 2) + } + + bar := pg.AddBar(0, + mpb.BarRemoveOnComplete(), + mpb.PrependDecorators( + decor.Name(lang.Tr("hint.check.checking")), + decor.OnCondition( + decor.Any(func(decor.Statistics) string { + c, l := slots.Cap(), slots.Len() + return fmt.Sprintf(" (%d / %d)", c-l, c) + }), + heavy, + ), + ), + mpb.AppendDecorators( + decor.CountersNoUnit("%d / %d", decor.WCSyncSpaceR), + decor.NewPercentage("%d", decor.WCSyncSpaceR), + decor.EwmaETA(decor.ET_STYLE_GO, 60), + ), + mpb.BarExtender((mpb.BarFillerFunc)(func(w io.Writer, _ decor.Statistics) (err error) { + lastCheckingHash = *checkingHash.Load() + if lastCheckingHash != "" { + _, err = fmt.Fprintln(w, "\t", lastCheckingHash) + } + return + }), false), + ) + defer bar.Wait() + defer bar.Abort(true) + + bar.SetTotal(0x100, false) + + ssizeMap := make(map[storage.Storage]map[string]int64, len(manager.Storages)) + for _, sto := range manager.Storages { + sizeMap := make(map[string]int64, len(files)) + ssizeMap[sto] = sizeMap + wg.Add(1) + go func(sto storage.Storage, sizeMap map[string]int64) { + defer wg.Done() + start := time.Now() + var checkedMp [256]bool + if err := sto.WalkDir(func(hash string, size int64) error { + if n := utils.HexTo256(hash); !checkedMp[n] { + checkedMp[n] = true + now := time.Now() + bar.EwmaIncrement(now.Sub(start)) + start = now + } + sizeMap[hash] = size + return nil + }); err != nil { + log.Errorf("Cannot walk %s: %v", sto.Id(), err) + return + } + }(sto, sizeMap) + } + wg.Wait() + + bar.SetCurrent(0) + bar.SetTotal((int64)(len(files)), false) + for _, f := range files { + if err := ctx.Err(); err != nil { + return err + } + start := time.Now() + hash := f.Hash + checkingHash.Store(&hash) + if f.Size == 0 { + log.Debugf("Skipped empty file %s", hash) + bar.EwmaIncrement(time.Since(start)) + continue + } + for _, sto := range f.Storages { + name := sto.Id() + "/" + hash + size, ok := ssizeMap[sto][hash] + if !ok { + // log.Debugf("Could not found file %q", name) + addMissing(f, sto) + bar.EwmaIncrement(time.Since(start)) + continue + } + if size != f.Size { + log.TrWarnf("warn.check.modified.size", name, size, f.Size) + addMissing(f, sto) + bar.EwmaIncrement(time.Since(start)) + continue + } + if !heavy { + bar.EwmaIncrement(time.Since(start)) + continue + } + hashMethod, err := getHashMethod(len(hash)) + if err != nil { + log.TrErrorf("error.check.unknown.hash.method", hash) + bar.EwmaIncrement(time.Since(start)) + continue + } + _, buf, free := slots.Alloc(ctx) + if buf == nil { + return ctx.Err() + } + wg.Add(1) + go func(f *api.StorageFileInfo, buf []byte, free func()) { + defer log.RecoverPanic(nil) + defer wg.Done() + miss := true + r, err := sto.Open(hash) + if err != nil { + log.TrErrorf("error.check.open.failed", name, err) + } else { + hw := hashMethod.New() + _, err = io.CopyBuffer(hw, r, buf[:]) + r.Close() + if err != nil { + log.TrErrorf("error.check.hash.failed", name, err) + } else if hs := hex.EncodeToString(hw.Sum(buf[:0])); hs != hash { + log.TrWarnf("warn.check.modified.hash", name, hs, hash) + } else { + miss = false + } + } + bar.EwmaIncrement(time.Since(start)) + free() + if miss { + addMissing(f, sto) + } + }(f, buf, free) + } + } + wg.Wait() + + checkingHash.Store(&emptyStr) + + bar.SetTotal(-1, true) + log.TrInfof("info.check.done", missingCount.Load()) + return nil +} + +type syncStats struct { + slots *limited.BufSlots + + totalSize int64 + okCount, failCount atomic.Int32 + totalFiles int + + pg *mpb.Progress + totalBar *mpb.Bar + lastInc atomic.Int64 +} + +func (c *HTTPClient) SyncFiles( + ctx context.Context, + manager *storage.Manager, + files map[string]*api.StorageFileInfo, + heavy bool, + slots int, +) error { + pg := mpb.New(mpb.WithRefreshRate(time.Second/2), mpb.WithAutoRefresh(), mpb.WithWidth(140)) + defer pg.Shutdown() + log.SetLogOutput(pg) + defer log.SetLogOutput(nil) + + missingMap := make(map[string]*api.StorageFileInfo) + if err := checkFile(ctx, manager, files, heavy, missingMap, pg); err != nil { + return err + } + + totalFiles := len(missingMap) + + var stats syncStats + stats.pg = pg + stats.slots = limited.NewBufSlots(slots) + stats.totalFiles = totalFiles + for _, f := range missingMap { + stats.totalSize += f.Size + } + + var barUnit decor.SizeB1024 + stats.lastInc.Store(time.Now().UnixNano()) + stats.totalBar = pg.AddBar(stats.totalSize, + mpb.BarRemoveOnComplete(), + mpb.BarPriority(stats.slots.Cap()), + mpb.PrependDecorators( + decor.Name(lang.Tr("hint.sync.total")), + decor.NewPercentage("%.2f"), + ), + mpb.AppendDecorators( + decor.Any(func(decor.Statistics) string { + return fmt.Sprintf("(%d + %d / %d) ", stats.okCount.Load(), stats.failCount.Load(), stats.totalFiles) + }), + decor.Counters(barUnit, "(%.1f/%.1f) "), + decor.EwmaSpeed(barUnit, "%.1f ", 30), + decor.OnComplete( + decor.EwmaETA(decor.ET_STYLE_GO, 30), "done", + ), + ), + ) + + log.TrInfof("hint.sync.start", totalFiles, utils.BytesToUnit((float64)(stats.totalSize))) + start := time.Now() + + done := make(chan []storage.Storage, 1) + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(nil) + + stLen := len(manager.Storages) + aliveStorages := make(map[storage.Storage]struct{}, stLen) + for _, s := range manager.Storages { + if !s.Inited() { + log.Errorf("Storage %s is not initialized", s.String()) + continue + } + tctx, cancel := context.WithTimeout(ctx, time.Second*10) + err := s.CheckUpload(tctx) + cancel() + if err != nil { + if err := ctx.Err(); err != nil { + return err + } + log.Errorf("Storage %s does not work: %v", s.String(), err) + } else { + aliveStorages[s] = struct{}{} + } + } + if len(aliveStorages) == 0 { + err := errors.New("All storages are broken") + log.TrErrorf("error.sync.failed", err) + return err + } + if len(aliveStorages) < stLen { + log.TrErrorf("error.sync.part.working", len(aliveStorages), stLen) + select { + case <-time.After(time.Minute): + case <-ctx.Done(): + return ctx.Err() + } + } + + go func() { + for _, info := range missingMap { + log.Debugf("File %s is for %s", info.Hash, joinStorageIDs(info.Storages)) + fileRes, err := c.fetchFile(ctx, &stats, info) + if err != nil { + if err != ctx.Err() { + cancel(err) + } + return + } + go func(info *api.StorageFileInfo, fileRes <-chan *os.File) { + defer log.RecordPanic() + select { + case srcFd := <-fileRes: + // cr.syncProg.Add(1) + if srcFd == nil { + select { + case done <- nil: // TODO: or all storage? + case <-ctx.Done(): + } + return + } + defer os.Remove(srcFd.Name()) + defer srcFd.Close() + // acquire slot here + slotId, buf, free := stats.slots.Alloc(ctx) + if buf == nil { + return + } + defer free() + _ = slotId + var failed []storage.Storage + for _, target := range info.Storages { + if _, err = srcFd.Seek(0, io.SeekStart); err != nil { + log.Errorf("Cannot seek file %q to start: %v", srcFd.Name(), err) + continue + } + if err = target.Create(info.Hash, srcFd); err != nil { + failed = append(failed, target) + log.TrErrorf("error.sync.create.failed", target.String(), info.Hash, err) + continue + } + } + free() + srcFd.Close() + os.Remove(srcFd.Name()) + select { + case done <- failed: + case <-ctx.Done(): + } + case <-ctx.Done(): + return + } + }(info, fileRes) + } + }() + + for range len(missingMap) { + select { + case failed := <-done: + for _, s := range failed { + if _, ok := aliveStorages[s]; ok { + delete(aliveStorages, s) + log.Debugf("Broken storage %d / %d", stLen-len(aliveStorages), stLen) + if len(aliveStorages) == 0 { + cancel(nil) + err := errors.New("All storages are broken") + log.TrErrorf("error.sync.failed", err) + return err + } + } + } + case <-ctx.Done(): + log.TrWarnf("warn.sync.interrupted") + return ctx.Err() + } + } + + use := time.Since(start) + stats.totalBar.Abort(true) + pg.Wait() + + log.TrInfof("hint.sync.done", use, utils.BytesToUnit((float64)(stats.totalSize)/use.Seconds())) + return nil +} + +func (c *HTTPClient) fetchFile(ctx context.Context, stats *syncStats, f *api.StorageFileInfo) (<-chan *os.File, error) { + const maxRetryCount = 10 + + hashMethod, err := getHashMethod(len(f.Hash)) + if err != nil { + return nil, err + } + + slotId, buf, free := stats.slots.Alloc(ctx) + if buf == nil { + return nil, ctx.Err() + } + + reqInd := 0 + reqs := make([]api.RequestPath, 0, len(f.URLs)) + for _, rq := range f.URLs { + reqs = append(reqs, rq) + } + + fileRes := make(chan *os.File, 1) + go func() { + defer log.RecordPanic() + defer free() + defer close(fileRes) + + var barUnit decor.SizeB1024 + var tried atomic.Int32 + tried.Store(1) + + bar := stats.pg.AddBar(f.Size, + mpb.BarRemoveOnComplete(), + mpb.BarPriority(slotId), + mpb.PrependDecorators( + decor.Name(lang.Tr("hint.sync.downloading")), + decor.Any(func(decor.Statistics) string { + tc := tried.Load() + if tc <= 1 { + return "" + } + return fmt.Sprintf("(%d/%d) ", tc, maxRetryCount) + }), + decor.Name(f.Hash, decor.WCSyncSpaceR), + ), + mpb.AppendDecorators( + decor.NewPercentage("%d", decor.WCSyncSpace), + decor.Counters(barUnit, "[%.1f / %.1f]", decor.WCSyncSpace), + decor.EwmaSpeed(barUnit, "%.1f", 30, decor.WCSyncSpace), + decor.OnComplete( + decor.EwmaETA(decor.ET_STYLE_GO, 30, decor.WCSyncSpace), "done", + ), + ), + ) + defer bar.Abort(true) + + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + log.Errorf("Cannot create temporary file: %s", err) + stats.failCount.Add(1) + return + } + successed := false + defer func(fd *os.File) { + if !successed { + fd.Close() + os.Remove(fd.Name()) + } + }(fd) + // prealloc space + if err := fd.Truncate(f.Size); err != nil { + log.Warnf("File space pre-alloc failed: %v", err) + } + + downloadOnce := func() error { + if _, err := fd.Seek(io.SeekStart, 0); err != nil { + return err + } + rp := reqs[reqInd] + if err := c.fetchFileWithBuf(ctx, rp.Request, f.Size, hashMethod, f.Hash, fd, buf, func(r io.Reader) io.Reader { + return utils.ProxyPBReader(r, bar, stats.totalBar, &stats.lastInc) + }); err != nil { + reqInd = (reqInd + 1) % len(reqs) + var rerr *utils.RedirectError + if ctx.Err() == nil && errors.As(err, &rerr) { + go func(ctx context.Context) { + if err := rp.Cluster.ReportDownload(ctx, rerr.GetResponse(), rerr.Unwrap()); err != nil { + log.Warnf("Report API error: %v", err) + } + }(context.WithoutCancel(ctx)) + } + return err + } + return nil + } + + interval := time.Second + for { + bar.SetCurrent(0) + err := downloadOnce() + if err == nil { + break + } + bar.SetRefill(bar.Current()) + + c := tried.Add(1) + if c > maxRetryCount || errors.Is(err, context.Canceled) { + log.TrErrorf("error.sync.download.failed", f.Hash, err) + stats.failCount.Add(1) + return + } + log.TrErrorf("error.sync.download.failed.retry", f.Hash, interval, err) + select { + case <-time.After(interval): + interval = min(interval*2, time.Minute*10) + case <-ctx.Done(): + stats.failCount.Add(1) + return + } + } + successed = true + fileRes <- fd + stats.okCount.Add(1) + log.Infof(lang.Tr("info.sync.downloaded"), f.Hash, + utils.BytesToUnit((float64)(f.Size)), + (float64)(stats.totalBar.Current())/(float64)(stats.totalSize)*100) + }() + return fileRes, nil +} + +type fileSizeMismatchError struct { + Has int64 + Want int64 +} + +func (e *fileSizeMismatchError) Error() string { + return fmt.Sprintf("File size wrong, got %d, expect %d", e.Has, e.Want) +} + +type fileHashMismatchError struct { + Has string + Want string +} + +func (e *fileHashMismatchError) Error() string { + return fmt.Sprintf("File hash not match, got %s, expect %s", e.Has, e.Want) +} + +func (c *HTTPClient) fetchFileWithBuf( + ctx context.Context, req *http.Request, + size int64, hashMethod crypto.Hash, hash string, + rw io.ReadWriteSeeker, buf []byte, + wrapper func(io.Reader) io.Reader, +) (err error) { + var ( + res *http.Response + r io.Reader + ) + req = req.Clone(ctx) + req.Header.Set("Accept-Encoding", "gzip, deflate") + if res, err = c.Do(req); err != nil { + return + } + defer res.Body.Close() + if res.StatusCode != http.StatusOK { + err = utils.NewHTTPStatusErrorFromResponse(res) + } else { + switch ce := strings.ToLower(res.Header.Get("Content-Encoding")); ce { + case "": + r = res.Body + if res.ContentLength >= 0 && res.ContentLength != size { + err = &fileSizeMismatchError{Has: res.ContentLength, Want: size} + } + case "gzip": + r, err = gzip.NewReader(res.Body) + case "deflate": + r, err = zlib.NewReader(res.Body) + default: + err = fmt.Errorf("Unexpected Content-Encoding %q", ce) + } + } + if err != nil { + return utils.ErrorFromRedirect(err, res) + } + if wrapper != nil { + r = wrapper(r) + } + + if n, err := io.CopyBuffer(rw, r, buf); err != nil { + return utils.ErrorFromRedirect(err, res) + } else if n != size { + return utils.ErrorFromRedirect(&fileSizeMismatchError{Has: n, Want: size}, res) + } + if _, err := rw.Seek(io.SeekStart, 0); err != nil { + return err + } + hw := hashMethod.New() + if _, err := io.CopyBuffer(hw, rw, buf); err != nil { + return err + } + if hs := hex.EncodeToString(hw.Sum(buf[:0])); hs != hash { + return utils.ErrorFromRedirect(&fileHashMismatchError{Has: hs, Want: hash}, res) + } + return +} + +func (c *HTTPClient) Gc( + ctx context.Context, + manager *storage.Manager, + files map[string]*api.StorageFileInfo, +) error { + errs := make([]error, len(manager.Storages)) + var wg sync.WaitGroup + for i, s := range manager.Storages { + wg.Add(1) + go func(i int, s storage.Storage) { + defer wg.Done() + errs[i] = s.WalkDir(func(hash string, size int64) error { + info, ok := files[hash] + ok = ok && slices.Contains(info.Storages, s) + if !ok { + log.Debugf("removing expired file: %s", hash) + if err := s.Remove(hash); err != nil { + log.Warnf("Cannot remove file %s/%s: %v", s, hash, err) + } + } + return nil + }) + }(i, s) + } + wg.Wait() + return errors.Join(errs...) +} + +func getHashMethod(l int) (hashMethod crypto.Hash, err error) { + switch l { + case 32: + return crypto.MD5, nil + case 40: + return crypto.SHA1, nil + default: + return 0, fmt.Errorf("Unexpected hash length %d", l) + } +} + +func joinStorageIDs(storages []storage.Storage) string { + ss := make([]string, len(storages)) + for i, s := range storages { + ss[i] = s.Id() + } + return "[" + strings.Join(ss, ", ") + "]" +} diff --git a/cluster/storage_test.go b/cluster/storage_test.go new file mode 100644 index 00000000..0f805744 --- /dev/null +++ b/cluster/storage_test.go @@ -0,0 +1,136 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster_test + +import ( + "testing" + + "bytes" + "crypto" + "io" + "net" + "net/http" + "os" + "strconv" +) + +var emptyBytes = make([]byte, 1024) + +func startServer() string { + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{ + IP: net.IPv4(127, 0, 0, 1), + }) + if err != nil { + panic(err) + } + server := &http.Server{ + Handler: (http.HandlerFunc)(func(rw http.ResponseWriter, req *http.Request) { + size := 128 + rw.Header().Set("Content-Length", strconv.Itoa(size*len(emptyBytes))) + rw.WriteHeader(http.StatusOK) + for range size { + rw.Write(emptyBytes) + } + }), + } + go server.Serve(listener) + return "http://" + listener.Addr().String() +} + +var expectedDownloadHash = []byte{0xfa, 0x43, 0x23, 0x9b, 0xce, 0xe7, 0xb9, 0x7c, 0xa6, 0x2f, 0x0, 0x7c, 0xc6, 0x84, 0x87, 0x56, 0xa, 0x39, 0xe1, 0x9f, 0x74, 0xf3, 0xdd, 0xe7, 0x48, 0x6d, 0xb3, 0xf9, 0x8d, 0xf8, 0xe4, 0x71} + +func BenchmarkDownlaodWhileVerify(b *testing.B) { + url := startServer() + fd, err := os.CreateTemp("", "gotest-") + if err != nil { + b.Fatalf("Cannot create temporary file: %v", err) + } + defer fd.Close() + defer os.Remove(fd.Name()) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + b.Fatalf("Cannot form new request: %v", err) + } + + hashMethod := crypto.SHA256 + buf := make([]byte, 1024) + client := &http.Client{} + + b.ResetTimer() + for range b.N { + if _, err := fd.Seek(io.SeekStart, 0); err != nil { + b.Fatalf("Seek error: %v", err) + } + resp, err := client.Do(req) + if err != nil { + b.Fatalf("Request error: %v", err) + } + hw := hashMethod.New() + if _, err := io.CopyBuffer(io.MultiWriter(fd, hw), resp.Body, buf); err != nil { + b.Fatalf("Copy error: %v", err) + } + resp.Body.Close() + if hs := hw.Sum(buf[:0]); !bytes.Equal(hs, expectedDownloadHash) { + b.Fatalf("Hash mismatch: %#v", hs) + } + } +} + +func BenchmarkDownlaodThenVerify(b *testing.B) { + url := startServer() + fd, err := os.CreateTemp("", "gotest-") + if err != nil { + b.Fatalf("Cannot create temporary file: %v", err) + } + defer fd.Close() + defer os.Remove(fd.Name()) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + b.Fatalf("Cannot form new request: %v", err) + } + + hashMethod := crypto.SHA256 + buf := make([]byte, 1024) + client := &http.Client{} + + b.ResetTimer() + for range b.N { + if _, err := fd.Seek(io.SeekStart, 0); err != nil { + b.Fatalf("Seek error: %v", err) + } + resp, err := client.Do(req) + if err != nil { + b.Fatalf("Request error: %v", err) + } + if _, err := io.CopyBuffer(fd, resp.Body, buf); err != nil { + b.Fatalf("Copy error: %v", err) + } + resp.Body.Close() + hw := hashMethod.New() + if _, err := fd.Seek(io.SeekStart, 0); err != nil { + b.Fatalf("Seek error: %v", err) + } + if _, err := io.CopyBuffer(hw, fd, buf); err != nil { + b.Fatalf("Copy error: %v", err) + } + if hs := hw.Sum(buf[:0]); !bytes.Equal(hs, expectedDownloadHash) { + b.Fatalf("Hash mismatch: %#v", hs) + } + } +} diff --git a/cluster/tempfile_test.go b/cluster/tempfile_test.go new file mode 100644 index 00000000..a2ad6ab1 --- /dev/null +++ b/cluster/tempfile_test.go @@ -0,0 +1,180 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package cluster_test + +import ( + "testing" + + "io" + "os" +) + +var datas = func() [][]byte { + datas := make([][]byte, 0x7) + for i := range len(datas) { + b := make([]byte, 0xff00+i) + for j := range len(b) { + b[j] = (byte)(i + j) + } + datas[i] = b + } + return datas +}() + +func BenchmarkCreateAndRemoveFile(b *testing.B) { + b.ReportAllocs() + buf := make([]byte, 1024) + _ = buf + for i := 0; i < b.N; i++ { + d := datas[i%len(datas)] + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + if _, err = fd.Write(d); err != nil { + b.Errorf("Cannot write file: %v", err) + } else if err = fd.Sync(); err != nil { + b.Errorf("Cannot write file: %v", err) + } + fd.Close() + os.Remove(fd.Name()) + if err != nil { + b.FailNow() + } + } +} + +func BenchmarkWriteAndTruncateFile(b *testing.B) { + b.ReportAllocs() + buf := make([]byte, 1024) + _ = buf + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + defer os.Remove(fd.Name()) + for i := 0; i < b.N; i++ { + d := datas[i%len(datas)] + if _, err := fd.Write(d); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Sync(); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Truncate(0); err != nil { + b.Fatalf("Cannot truncate file: %v", err) + } + } +} + +func BenchmarkWriteAndSeekFile(b *testing.B) { + b.ReportAllocs() + buf := make([]byte, 1024) + _ = buf + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + defer os.Remove(fd.Name()) + for i := 0; i < b.N; i++ { + d := datas[i%len(datas)] + if _, err := fd.Write(d); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Sync(); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if _, err := fd.Seek(io.SeekStart, 0); err != nil { + b.Fatalf("Cannot seek file: %v", err) + } + } +} + +func BenchmarkParallelCreateAndRemoveFile(b *testing.B) { + b.ReportAllocs() + b.SetParallelism(4) + buf := make([]byte, 1024) + _ = buf + b.RunParallel(func(pb *testing.PB) { + for i := 0; pb.Next(); i++ { + d := datas[i%len(datas)] + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + if _, err = fd.Write(d); err != nil { + b.Errorf("Cannot write file: %v", err) + } else if err = fd.Sync(); err != nil { + b.Errorf("Cannot write file: %v", err) + } + fd.Close() + if err := os.Remove(fd.Name()); err != nil { + b.Fatalf("Cannot remove file: %v", err) + } + if err != nil { + b.FailNow() + } + } + }) +} + +func BenchmarkParallelWriteAndTruncateFile(b *testing.B) { + b.ReportAllocs() + b.SetParallelism(4) + buf := make([]byte, 1024) + _ = buf + b.RunParallel(func(pb *testing.PB) { + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + defer os.Remove(fd.Name()) + for i := 0; pb.Next(); i++ { + d := datas[i%len(datas)] + if _, err := fd.Write(d); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Sync(); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Truncate(0); err != nil { + b.Fatalf("Cannot truncate file: %v", err) + } + } + }) +} + +func BenchmarkParallelWriteAndSeekFile(b *testing.B) { + b.ReportAllocs() + b.SetParallelism(4) + buf := make([]byte, 1024) + _ = buf + b.RunParallel(func(pb *testing.PB) { + fd, err := os.CreateTemp("", "*.downloading") + if err != nil { + b.Fatalf("Cannot create temp file: %v", err) + } + defer os.Remove(fd.Name()) + for i := 0; pb.Next(); i++ { + d := datas[i%len(datas)] + if _, err := fd.Write(d); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if err := fd.Sync(); err != nil { + b.Fatalf("Cannot write file: %v", err) + } else if _, err := fd.Seek(io.SeekStart, 0); err != nil { + b.Fatalf("Cannot seel file: %v", err) + } + } + }) +} diff --git a/config.go b/config.go index e3ddb66c..5d178ffb 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,6 @@ /** * OpenBmclAPI (Golang Edition) - * Copyright (C) 2023 Kevin Z + * Copyright (C) 2024 Kevin Z * All rights reserved * * This program is free software: you can redistribute it and/or modify @@ -21,354 +21,94 @@ package main import ( "bytes" + "context" + "encoding/json" "errors" "fmt" - "net/url" "os" - "path/filepath" - "regexp" - "strconv" "strings" - "time" + "sync" "gopkg.in/yaml.v3" - "github.com/LiterMC/go-openbmclapi/cache" - "github.com/LiterMC/go-openbmclapi/limited" + "github.com/LiterMC/go-openbmclapi/api" + "github.com/LiterMC/go-openbmclapi/cluster" + "github.com/LiterMC/go-openbmclapi/config" "github.com/LiterMC/go-openbmclapi/log" "github.com/LiterMC/go-openbmclapi/storage" - "github.com/LiterMC/go-openbmclapi/utils" ) -type UserItem struct { - Username string `yaml:"username"` - Password string `yaml:"password"` -} - -type AdvancedConfig struct { - DebugLog bool `yaml:"debug-log"` - SocketIOLog bool `yaml:"socket-io-log"` - NoHeavyCheck bool `yaml:"no-heavy-check"` - NoGC bool `yaml:"no-gc"` - HeavyCheckInterval int `yaml:"heavy-check-interval"` - KeepaliveTimeout int `yaml:"keepalive-timeout"` - SkipFirstSync bool `yaml:"skip-first-sync"` - SkipSignatureCheck bool `yaml:"skip-signature-check"` - NoFastEnable bool `yaml:"no-fast-enable"` - WaitBeforeEnable int `yaml:"wait-before-enable"` - - DoNotRedirectHTTPSToSecureHostname bool `yaml:"do-NOT-redirect-https-to-SECURE-hostname"` - DoNotOpenFAQOnWindows bool `yaml:"do-not-open-faq-on-windows"` -} - -type CertificateConfig struct { - Cert string `yaml:"cert"` - Key string `yaml:"key"` -} - -type ServeLimitConfig struct { - Enable bool `yaml:"enable"` - MaxConn int `yaml:"max-conn"` - UploadRate int `yaml:"upload-rate"` -} - -type APIRateLimitConfig struct { - Anonymous limited.RateLimit `yaml:"anonymous"` - Logged limited.RateLimit `yaml:"logged"` -} - -type NotificationConfig struct { - EnableEmail bool `yaml:"enable-email"` - EmailSMTP string `yaml:"email-smtp"` - EmailSMTPEncryption string `yaml:"email-smtp-encryption"` - EmailSender string `yaml:"email-sender"` - EmailSenderPassword string `yaml:"email-sender-password"` - EnableWebhook bool `yaml:"enable-webhook"` -} - -type DatabaseConfig struct { - Driver string `yaml:"driver"` - DSN string `yaml:"data-source-name"` -} - -type HijackConfig struct { - Enable bool `yaml:"enable"` - EnableLocalCache bool `yaml:"enable-local-cache"` - LocalCachePath string `yaml:"local-cache-path"` - RequireAuth bool `yaml:"require-auth"` - AuthUsers []UserItem `yaml:"auth-users"` -} - -type CacheConfig struct { - Type string `yaml:"type"` - Data any `yaml:"data,omitempty"` - - newCache func() cache.Cache `yaml:"-"` -} - -func (c *CacheConfig) UnmarshalYAML(n *yaml.Node) (err error) { - var cfg struct { - Type string `yaml:"type"` - Data utils.RawYAML `yaml:"data,omitempty"` - } - if err = n.Decode(&cfg); err != nil { - return - } - c.Type = cfg.Type - c.Data = nil - switch strings.ToLower(c.Type) { - case "no", "off", "disabled", "nocache", "no-cache": - c.newCache = func() cache.Cache { return cache.NoCache } - case "mem", "memory", "inmem": - c.newCache = func() cache.Cache { return cache.NewInMemCache() } - case "redis": - opt := new(cache.RedisOptions) - if err = cfg.Data.Decode(opt); err != nil { - return - } - c.Data = opt - c.newCache = func() cache.Cache { return cache.NewRedisCache(opt.ToRedis()) } - default: - return fmt.Errorf("Unexpected cache type %q", c.Type) - } - return nil -} - -type GithubAPIConfig struct { - UpdateCheckInterval utils.YAMLDuration `yaml:"update-check-interval"` - Authorization string `yaml:"authorization"` -} - -type DashboardConfig struct { - Enable bool `yaml:"enable"` - Username string `yaml:"username"` - Password string `yaml:"password"` - PwaName string `yaml:"pwa-name"` - PwaShortName string `yaml:"pwa-short_name"` - PwaDesc string `yaml:"pwa-description"` - - NotifySubject string `yaml:"notification-subject"` -} - -type TunnelConfig struct { - Enable bool `yaml:"enable"` - TunnelProg string `yaml:"tunnel-program"` - OutputRegex string `yaml:"output-regex"` - TunnelTimeout int `yaml:"tunnel-timeout"` - - outputRegex *regexp.Regexp - hostOut int - portOut int -} - -func (c *TunnelConfig) UnmarshalYAML(n *yaml.Node) (err error) { - type T TunnelConfig - if err = n.Decode((*T)(c)); err != nil { - return - } - if !c.Enable { - return - } - if c.outputRegex, err = regexp.Compile(c.OutputRegex); err != nil { - return - } - c.hostOut = c.outputRegex.SubexpIndex("host") - c.portOut = c.outputRegex.SubexpIndex("port") - if c.hostOut <= 0 { - return errors.New("tunneler.output-regex: missing named `(?)` capture group") - } - if c.portOut <= 0 { - return errors.New("tunneler.output-regex: missing named `(?)` capture group") - } - return -} - -type Config struct { - LogSlots int `yaml:"log-slots"` - NoAccessLog bool `yaml:"no-access-log"` - AccessLogSlots int `yaml:"access-log-slots"` - Byoc bool `yaml:"byoc"` - UseCert bool `yaml:"use-cert"` - TrustedXForwardedFor bool `yaml:"trusted-x-forwarded-for"` - PublicHost string `yaml:"public-host"` - PublicPort uint16 `yaml:"public-port"` - Port uint16 `yaml:"port"` - ClusterId string `yaml:"cluster-id"` - ClusterSecret string `yaml:"cluster-secret"` - SyncInterval int `yaml:"sync-interval"` - OnlyGcWhenStart bool `yaml:"only-gc-when-start"` - DownloadMaxConn int `yaml:"download-max-conn"` - MaxReconnectCount int `yaml:"max-reconnect-count"` - - Certificates []CertificateConfig `yaml:"certificates"` - Tunneler TunnelConfig `yaml:"tunneler"` - Cache CacheConfig `yaml:"cache"` - ServeLimit ServeLimitConfig `yaml:"serve-limit"` - RateLimit APIRateLimitConfig `yaml:"api-rate-limit"` - Notification NotificationConfig `yaml:"notification"` - Dashboard DashboardConfig `yaml:"dashboard"` - GithubAPI GithubAPIConfig `yaml:"github-api"` - Database DatabaseConfig `yaml:"database"` - Hijack HijackConfig `yaml:"hijack"` - Storages []storage.StorageOption `yaml:"storages"` - WebdavUsers map[string]*storage.WebDavUser `yaml:"webdav-users"` - Advanced AdvancedConfig `yaml:"advanced"` -} - -func (cfg *Config) applyWebManifest(manifest map[string]any) { - if cfg.Dashboard.Enable { - manifest["name"] = cfg.Dashboard.PwaName - manifest["short_name"] = cfg.Dashboard.PwaShortName - manifest["description"] = cfg.Dashboard.PwaDesc - } -} - -var defaultConfig = Config{ - LogSlots: 7, - NoAccessLog: false, - AccessLogSlots: 16, - Byoc: false, - TrustedXForwardedFor: false, - PublicHost: "", - PublicPort: 0, - Port: 4000, - ClusterId: "${CLUSTER_ID}", - ClusterSecret: "${CLUSTER_SECRET}", - SyncInterval: 10, - OnlyGcWhenStart: false, - DownloadMaxConn: 16, - MaxReconnectCount: 10, - - Certificates: []CertificateConfig{ - { - Cert: "/path/to/cert.pem", - Key: "/path/to/key.pem", - }, - }, - - Tunneler: TunnelConfig{ - Enable: false, - TunnelProg: "./path/to/tunnel/program", - OutputRegex: `\bNATedAddr\s+(?P[0-9.]+|\[[0-9a-f:]+\]):(?P\d+)$`, - TunnelTimeout: 0, - }, - - Cache: CacheConfig{ - Type: "inmem", - newCache: func() cache.Cache { return cache.NewInMemCache() }, - }, - - ServeLimit: ServeLimitConfig{ - Enable: false, - MaxConn: 16384, - UploadRate: 1024 * 12, // 12MB - }, - - RateLimit: APIRateLimitConfig{ - Anonymous: limited.RateLimit{ - PerMin: 10, - PerHour: 120, - }, - Logged: limited.RateLimit{ - PerMin: 120, - PerHour: 6000, - }, - }, - - Notification: NotificationConfig{ - EnableEmail: false, - EmailSMTP: "smtp.example.com:25", - EmailSMTPEncryption: "tls", - EmailSender: "noreply@example.com", - EmailSenderPassword: "example-password", - EnableWebhook: true, - }, - - Dashboard: DashboardConfig{ - Enable: true, - PwaName: "GoOpenBmclApi Dashboard", - PwaShortName: "GOBA Dash", - PwaDesc: "Go-Openbmclapi Internal Dashboard", - NotifySubject: "mailto:user@example.com", - }, - - GithubAPI: GithubAPIConfig{ - UpdateCheckInterval: (utils.YAMLDuration)(time.Hour), - }, - - Database: DatabaseConfig{ - Driver: "sqlite", - DSN: filepath.Join("data", "files.db"), - }, - - Hijack: HijackConfig{ - Enable: false, - RequireAuth: false, - EnableLocalCache: false, - LocalCachePath: "hijack_cache", - AuthUsers: []UserItem{ - { - Username: "example-username", - Password: "example-password", - }, - }, - }, - - Storages: nil, - - WebdavUsers: map[string]*storage.WebDavUser{}, - - Advanced: AdvancedConfig{ - DebugLog: false, - NoHeavyCheck: false, - NoGC: false, - HeavyCheckInterval: 120, - KeepaliveTimeout: 10, - SkipFirstSync: false, - NoFastEnable: false, - WaitBeforeEnable: 0, - }, -} - -func migrateConfig(data []byte, config *Config) { +func migrateConfig(data []byte, cfg *config.Config) { var oldConfig map[string]any if err := yaml.Unmarshal(data, &oldConfig); err != nil { return } if v, ok := oldConfig["debug"].(bool); ok { - config.Advanced.DebugLog = v + cfg.Advanced.DebugLog = v } if v, ok := oldConfig["no-heavy-check"].(bool); ok { - config.Advanced.NoHeavyCheck = v + cfg.Advanced.NoHeavyCheck = v } if v, ok := oldConfig["keepalive-timeout"].(int); ok { - config.Advanced.KeepaliveTimeout = v + cfg.Advanced.KeepaliveTimeout = v + } + if oldConfig["clusters"] == nil { + id, ok1 := oldConfig["cluster-id"].(string) + secret, ok2 := oldConfig["cluster-secret"].(string) + publicHost, ok3 := oldConfig["public-host"].(string) + if ok1 && ok2 && ok3 { + cfg.Clusters = map[string]config.ClusterOptions{ + "main": { + Id: id, + Secret: secret, + PublicHosts: []string{publicHost}, + }, + } + } } } -func readConfig() (config Config) { +func readAndRewriteConfig() (cfg *config.Config, err error) { const configPath = "config.yaml" - config = defaultConfig - + cfg = config.NewDefaultConfig() data, err := os.ReadFile(configPath) notexists := false if err != nil { if !errors.Is(err, os.ErrNotExist) { - log.Errorf(Tr("error.config.read.failed"), err) - osExit(CodeClientError) + log.TrErrorf("error.config.read.failed", err) + os.Exit(1) } - log.Error(Tr("error.config.not.exists")) + log.TrErrorf("error.config.not.exists") notexists = true } else { - migrateConfig(data, &config) - if err = yaml.Unmarshal(data, &config); err != nil { - log.Errorf(Tr("error.config.parse.failed"), err) - osExit(CodeClientError) + migrateConfig(data, cfg) + if err = cfg.UnmarshalText(data); err != nil { + log.TrErrorf("error.config.parse.failed", err) + os.Exit(1) + } + if len(cfg.Clusters) == 0 { + cfg.Clusters = map[string]config.ClusterOptions{ + "main": { + Id: "${CLUSTER_ID}", + Secret: "${CLUSTER_SECRET}", + PublicHosts: []string{}, + Server: cluster.DefaultBMCLAPIServer, + SkipSignatureCheck: false, + }, + } + } + if len(cfg.Certificates) == 0 { + cfg.Certificates = []config.CertificateConfig{ + { + Cert: "/path/to/cert.pem", + Key: "/path/to/key.pem", + }, + } } - if len(config.Storages) == 0 { - config.Storages = []storage.StorageOption{ + if len(cfg.Storages) == 0 { + cfg.Storages = []storage.StorageOption{ { BasicStorageOption: storage.BasicStorageOption{ Id: "local", @@ -381,109 +121,192 @@ func readConfig() (config Config) { }, } } - if len(config.WebdavUsers) == 0 { - config.WebdavUsers["example-user"] = &storage.WebDavUser{ + if len(cfg.WebdavUsers) == 0 { + cfg.WebdavUsers["example-user"] = &storage.WebDavUser{ EndPoint: "https://webdav.example.com/path/to/endpoint/", Username: "example-username", Password: "example-password", } } - ids := make(map[string]int, len(config.Storages)) - for i, s := range config.Storages { + ids := make(map[string]int, len(cfg.Storages)) + for i, s := range cfg.Storages { if s.Id == "" { s.Id = fmt.Sprintf("storage-%d", i) - config.Storages[i].Id = s.Id + cfg.Storages[i].Id = s.Id } if j, ok := ids[s.Id]; ok { log.Errorf("Duplicated storage id %q at [%d] and [%d], please edit the config.", s.Id, i, j) - osExit(CodeClientError) + os.Exit(1) } ids[s.Id] = i } } - for _, so := range config.Storages { - switch opt := so.Data.(type) { - case *storage.WebDavStorageOption: - if alias := opt.Alias; alias != "" { - user, ok := config.WebdavUsers[alias] - if !ok { - log.Errorf(Tr("error.config.alias.user.not.exists"), alias) - osExit(CodeClientError) - } - opt.AliasUser = user - var end *url.URL - if end, err = url.Parse(opt.AliasUser.EndPoint); err != nil { - return - } - if opt.EndPoint != "" { - var full *url.URL - if full, err = end.Parse(opt.EndPoint); err != nil { - return - } - opt.FullEndPoint = full.String() - } else { - opt.FullEndPoint = opt.AliasUser.EndPoint - } - } else { - opt.FullEndPoint = opt.EndPoint - } - } - } - var buf bytes.Buffer encoder := yaml.NewEncoder(&buf) encoder.SetIndent(2) - if err = encoder.Encode(config); err != nil { - log.Errorf(Tr("error.config.encode.failed"), err) - osExit(CodeClientError) + if err = encoder.Encode(cfg); err != nil { + log.TrErrorf("error.config.encode.failed", err) + os.Exit(1) } if err = os.WriteFile(configPath, buf.Bytes(), 0600); err != nil { - log.Errorf(Tr("error.config.write.failed"), err) - osExit(CodeClientError) + log.TrErrorf("error.config.write.failed", err) + os.Exit(1) } if notexists { - log.Error(Tr("error.config.created")) - osExit(0xff) + log.TrErrorf("error.config.created") + return nil, errors.New("Please edit the config before continue!") } + return +} + +type ConfigHandler struct { + mux sync.RWMutex + r *Runner + + updateProcess []func(context.Context) error +} + +var _ api.ConfigHandler = (*ConfigHandler)(nil) + +func (c *ConfigHandler) GetConfig() *config.Config { + return c.r.Config +} - if os.Getenv("DEBUG") == "true" { - config.Advanced.DebugLog = true +func (c *ConfigHandler) update(newConfig *config.Config) error { + r := c.r + oldConfig := r.Config + c.updateProcess = c.updateProcess[:0] + + if newConfig.LogSlots != oldConfig.LogSlots || newConfig.NoAccessLog != oldConfig.NoAccessLog || newConfig.AccessLogSlots != oldConfig.AccessLogSlots || newConfig.Advanced.DebugLog != oldConfig.Advanced.DebugLog { + c.updateProcess = append(c.updateProcess, r.SetupLogger) + } + if newConfig.Host != oldConfig.Host || newConfig.Port != oldConfig.Port { + c.updateProcess = append(c.updateProcess, r.StartServer) + } + if newConfig.PublicHost != oldConfig.PublicHost || newConfig.PublicPort != oldConfig.PublicPort || newConfig.Advanced.NoFastEnable != oldConfig.Advanced.NoFastEnable || newConfig.MaxReconnectCount != oldConfig.MaxReconnectCount { + c.updateProcess = append(c.updateProcess, r.updateClustersWithGeneralConfig) + } + if newConfig.RateLimit != oldConfig.RateLimit { + c.updateProcess = append(c.updateProcess, r.updateRateLimit) } - if v := os.Getenv("CLUSTER_IP"); v != "" { - config.PublicHost = v + if newConfig.Notification != oldConfig.Notification { + // c.updateProcess = append(c.updateProcess, ) } - if v := os.Getenv("CLUSTER_PORT"); v != "" { - if n, err := strconv.Atoi(v); err != nil { - log.Errorf("Cannot parse CLUSTER_PORT %q: %v", v, err) - } else { - config.Port = (uint16)(n) + + r.Config = newConfig + r.publicHost = r.Config.PublicHost + r.publicPort = r.Config.PublicPort + return nil +} + +func (c *ConfigHandler) doUpdateProcesses(ctx context.Context) error { + for _, proc := range c.updateProcess { + if err := proc(ctx); err != nil { + return err } } - if v := os.Getenv("CLUSTER_PUBLIC_PORT"); v != "" { - if n, err := strconv.Atoi(v); err != nil { - log.Errorf("Cannot parse CLUSTER_PUBLIC_PORT %q: %v", v, err) - } else { - config.PublicPort = (uint16)(n) + c.updateProcess = c.updateProcess[:0] + return nil +} + +func (c *ConfigHandler) MarshalJSON() ([]byte, error) { + c.mux.RLock() + defer c.mux.RUnlock() + return c.marshalJSONLocked() +} + +func (c *ConfigHandler) marshalJSONLocked() ([]byte, error) { + return c.r.Config.MarshalJSON() +} + +func (c *ConfigHandler) UnmarshalJSON(data []byte) error { + c2 := c.r.Config.Clone() + if err := c2.UnmarshalJSON(data); err != nil { + return err + } + c.update(c2) + return nil +} + +func (c *ConfigHandler) UnmarshalYAML(data []byte) error { + c2 := c.r.Config.Clone() + if err := c2.UnmarshalText(data); err != nil { + return err + } + c.update(c2) + return nil +} + +func (c *ConfigHandler) MarshalJSONPath(path string) ([]byte, error) { + names := strings.Split(path, ".") + data, err := c.MarshalJSON() + if err != nil { + return nil, err + } + var m map[string]any + if err := json.Unmarshal(data, &m); err != nil { + return nil, err + } + accessed := "" + var x any = m + for _, n := range names { + mc, ok := x.(map[string]any) + if !ok { + return nil, fmt.Errorf("Unexpected type %T on path %q, expect map[string]any", x, accessed) } + accessed += n + "." + x = mc[n] + } + buf, err := json.Marshal(x) + if err != nil { + return nil, err } - if v := os.Getenv("CLUSTER_ID"); v != "" { - config.ClusterId = v + return buf, nil +} + +func (c *ConfigHandler) UnmarshalJSONPath(path string, data []byte) error { + names := strings.Split(path, ".") + var d any + if err := json.Unmarshal(data, &d); err != nil { + return err + } + accessed := "" + var m map[string]any + { + b, err := c.MarshalJSON() + if err != nil { + return err + } + if err := json.Unmarshal(b, &m); err != nil { + return err + } } - if v := os.Getenv("CLUSTER_SECRET"); v != "" { - config.ClusterSecret = v + x := m + for _, p := range names[:len(names)-1] { + accessed += p + "." + var ok bool + x, ok = x[p].(map[string]any) + if !ok { + return fmt.Errorf("Unexpected type %T on path %q, expect map[string]any", x, accessed) + } } - if byoc := os.Getenv("CLUSTER_BYOC"); byoc != "" { - config.Byoc = byoc == "true" + x[names[len(names)-1]] = d + dt, err := json.Marshal(m) + if err != nil { + return err } - return + return c.UnmarshalJSON(dt) } -type OpenbmclapiAgentSyncConfig struct { - Source string `json:"source"` - Concurrency int `json:"concurrency"` +func (c *ConfigHandler) DoReadLockedAction(callback func(api.ConfigHandler) error) error { + c.mux.RLock() + defer c.mux.RUnlock() + return callback(c) } -type OpenbmclapiAgentConfig struct { - Sync OpenbmclapiAgentSyncConfig `json:"sync"` +func (c *ConfigHandler) DoWriteLockedAction(callback func(api.ConfigHandler) error) error { + c.mux.Lock() + defer c.mux.Unlock() + return callback(c) } diff --git a/config.yaml b/config.yaml index ea91ef80..3cc54dda 100644 --- a/config.yaml +++ b/config.yaml @@ -1,18 +1,33 @@ -log-slots: 7 -no-access-log: false -access-log-slots: 16 -byoc: false -use-cert: false -trusted-x-forwarded-for: false public-host: "" public-port: 0 +host: 0.0.0.0 port: 4000 -cluster-id: ${CLUSTER_ID} -cluster-secret: ${CLUSTER_SECRET} -sync-interval: 10 +use-cert: false +trusted-x-forwarded-for: false only-gc-when-start: false +sync-interval: 10 download-max-conn: 16 max-reconnect-count: 10 +log-slots: 7 +no-access-log: false +access-log-slots: 16 +clusters: + main: + id: ${CLUSTER_ID} + secret: ${CLUSTER_SECRET} + byoc: false + public-hosts: + - "" + server: "" + skip-signature-check: false + storages: [] +storages: + - type: local + id: local-storage-0 + weight: 100 + data: + cache-path: _cache + compressor: "" certificates: - cert: /path/to/cert.pem key: /path/to/key.pem @@ -20,7 +35,6 @@ tunneler: enable: false tunnel-program: ./path/to/tunnel/program output-regex: \bNATedAddr\s+(?[0-9.]+|\[[0-9a-f:]+\]):(?\d+)$ - tunnel-timeout: 0 cache: type: inmem serve-limit: @@ -63,13 +77,6 @@ hijack: auth-users: - username: example-username password: example-password -storages: - - type: local - id: local-storage-0 - weight: 100 - data: - cache-path: _cache - compressor: "" webdav-users: example-user: endpoint: https://webdav.example.com/path/to/endpoint/ @@ -82,9 +89,6 @@ advanced: no-gc: false heavy-check-interval: 120 keepalive-timeout: 10 - skip-first-sync: false - skip-signature-check: false no-fast-enable: false wait-before-enable: 0 - do-NOT-redirect-https-to-SECURE-hostname: false do-not-open-faq-on-windows: false diff --git a/config/advanced.go b/config/advanced.go new file mode 100644 index 00000000..99fc1320 --- /dev/null +++ b/config/advanced.go @@ -0,0 +1,34 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package config + +type AdvancedConfig struct { + DebugLog bool `yaml:"debug-log"` + SocketIOLog bool `yaml:"socket-io-log"` + NoHeavyCheck bool `yaml:"no-heavy-check"` + NoGC bool `yaml:"no-gc"` + HeavyCheckInterval int `yaml:"heavy-check-interval"` + KeepaliveTimeout int `yaml:"keepalive-timeout"` + NoFastEnable bool `yaml:"no-fast-enable"` + WaitBeforeEnable int `yaml:"wait-before-enable"` + + // DoNotRedirectHTTPSToSecureHostname bool `yaml:"do-NOT-redirect-https-to-SECURE-hostname"` + DoNotOpenFAQOnWindows bool `yaml:"do-not-open-faq-on-windows"` +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 00000000..141bc9aa --- /dev/null +++ b/config/config.go @@ -0,0 +1,209 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package config + +import ( + "encoding/json" + "path/filepath" + "time" + + "gopkg.in/yaml.v3" + + "github.com/LiterMC/go-openbmclapi/cache" + "github.com/LiterMC/go-openbmclapi/limited" + "github.com/LiterMC/go-openbmclapi/storage" + "github.com/LiterMC/go-openbmclapi/utils" +) + +type Config struct { + PublicHost string `json:"public_host" yaml:"public-host"` + PublicPort uint16 `json:"public_port" yaml:"public-port"` + Host string `json:"host" yaml:"host"` + Port uint16 `json:"port" yaml:"port"` + UseCert bool `json:"use_cert" yaml:"use-cert"` + AllowUnsecureConn bool `json:"allow_unsecure_connection" yaml:"allow-unsecure-connection"` + TrustedXForwardedFor bool `json:"trusted_x_forwarded_for" yaml:"trusted-x-forwarded-for"` + + OnlyGcWhenStart bool `json:"only_gc_when_start" yaml:"only-gc-when-start"` + SyncInterval int `json:"sync_interval" yaml:"sync-interval"` + DownloadMaxConn int `json:"download_max_conn" yaml:"download-max-conn"` + MaxReconnectCount int `json:"max_reconnect_count" yaml:"max-reconnect-count"` + + LogSlots int `json:"log_slots" yaml:"log-slots"` + NoAccessLog bool `json:"no_access_log" yaml:"no-access-log"` + AccessLogSlots int `json:"access_log_slots" yaml:"access-log-slots"` + + Clusters map[string]ClusterOptions `json:"clusters" yaml:"clusters"` + Storages []storage.StorageOption `json:"storages" yaml:"storages"` + Certificates []CertificateConfig `json:"certificates" yaml:"certificates"` + Tunneler TunnelConfig `json:"tunneler" yaml:"tunneler"` + Cache CacheConfig `json:"cache" yaml:"cache"` + ServeLimit ServeLimitConfig `json:"serve_limit" yaml:"serve-limit"` + RateLimit APIRateLimitConfig `json:"api_rate_limit" yaml:"api-rate-limit"` + Notification NotificationConfig `json:"notification" yaml:"notification"` + Dashboard DashboardConfig `json:"dashboard" yaml:"dashboard"` + GithubAPI GithubAPIConfig `json:"github_api" yaml:"github-api"` + Database DatabaseConfig `json:"database" yaml:"database"` + Hijack HijackConfig `json:"hijack" yaml:"hijack"` + WebdavUsers map[string]*storage.WebDavUser `json:"webdav_users" yaml:"webdav-users"` + Advanced AdvancedConfig `json:"advanced" yaml:"advanced"` +} + +func (cfg *Config) ApplyWebManifest(manifest map[string]any) { + if cfg.Dashboard.Enable { + manifest["name"] = cfg.Dashboard.PwaName + manifest["short_name"] = cfg.Dashboard.PwaShortName + manifest["description"] = cfg.Dashboard.PwaDesc + } +} + +func NewDefaultConfig() *Config { + return &Config{ + PublicHost: "", + PublicPort: 443, + Host: "0.0.0.0", + Port: 4000, + UseCert: false, + TrustedXForwardedFor: false, + + OnlyGcWhenStart: false, + SyncInterval: 10, + DownloadMaxConn: 16, + MaxReconnectCount: 10, + + LogSlots: 7, + NoAccessLog: false, + AccessLogSlots: 16, + + Clusters: map[string]ClusterOptions{}, + + Storages: nil, + + Certificates: []CertificateConfig{}, + + Tunneler: TunnelConfig{ + Enable: false, + TunnelProg: "./path/to/tunnel/program", + OutputRegex: `\bNATedAddr\s+(?P[0-9.]+|\[[0-9a-f:]+\]):(?P\d+)$`, + }, + + Cache: CacheConfig{ + Type: "memory", + newCache: func() cache.Cache { return cache.NewInMemCache() }, + }, + + ServeLimit: ServeLimitConfig{ + Enable: false, + MaxConn: 16384, + UploadRate: 1024 * 12, // 12MB + }, + + RateLimit: APIRateLimitConfig{ + Anonymous: limited.RateLimit{ + PerMin: 10, + PerHour: 120, + }, + Logged: limited.RateLimit{ + PerMin: 120, + PerHour: 6000, + }, + }, + + Notification: NotificationConfig{ + EnableEmail: false, + EmailSMTP: "smtp.example.com:25", + EmailSMTPEncryption: "tls", + EmailSender: "noreply@example.com", + EmailSenderPassword: "example-password", + EnableWebhook: true, + }, + + Dashboard: DashboardConfig{ + Enable: true, + Username: "", + Password: "", + PwaName: "GoOpenBmclApi Dashboard", + PwaShortName: "GOBA Dash", + PwaDesc: "Go-Openbmclapi Internal Dashboard", + NotifySubject: "mailto:user@example.com", + }, + + GithubAPI: GithubAPIConfig{ + UpdateCheckInterval: (utils.YAMLDuration)(time.Hour), + Authorization: "", + }, + + Database: DatabaseConfig{ + Driver: "sqlite", + DSN: filepath.Join("data", "files.db"), + }, + + Hijack: HijackConfig{ + Enable: false, + EnableLocalCache: false, + LocalCachePath: "hijack_cache", + RequireAuth: false, + AuthUsers: []UserItem{ + { + Username: "example-username", + Password: "example-password", + }, + }, + }, + + WebdavUsers: map[string]*storage.WebDavUser{}, + + Advanced: AdvancedConfig{ + DebugLog: false, + NoHeavyCheck: false, + NoGC: false, + HeavyCheckInterval: 120, + KeepaliveTimeout: 10, + NoFastEnable: false, + WaitBeforeEnable: 0, + }, + } +} + +func (config *Config) MarshalJSON() ([]byte, error) { + type T Config + return json.Marshal((*T)(config)) +} + +func (config *Config) UnmarshalJSON(data []byte) error { + type T Config + return json.Unmarshal(data, (*T)(config)) +} + +func (config *Config) UnmarshalText(data []byte) error { + return yaml.Unmarshal(data, config) +} + +func (config *Config) Clone() *Config { + data, err := config.MarshalJSON() + if err != nil { + panic(err) + } + cloned := new(Config) + if err := cloned.UnmarshalJSON(data); err != nil { + panic(err) + } + return cloned +} diff --git a/config/dashboard.go b/config/dashboard.go new file mode 100644 index 00000000..6d35abdd --- /dev/null +++ b/config/dashboard.go @@ -0,0 +1,49 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package config + +import ( + "github.com/LiterMC/go-openbmclapi/limited" +) + +type APIRateLimitConfig struct { + Anonymous limited.RateLimit `json:"anonymous" yaml:"anonymous"` + Logged limited.RateLimit `json:"logged" yaml:"logged"` +} + +type NotificationConfig struct { + EnableEmail bool `json:"enable_email" yaml:"enable-email"` + EmailSMTP string `json:"email_smtp" yaml:"email-smtp"` + EmailSMTPEncryption string `json:"email_smtp_encryption" yaml:"email-smtp-encryption"` + EmailSender string `json:"email_sender" yaml:"email-sender"` + EmailSenderPassword string `json:"email_sender_password" yaml:"email-sender-password"` + EnableWebhook bool `json:"enable_webhook" yaml:"enable-webhook"` +} + +type DashboardConfig struct { + Enable bool `json:"enable" yaml:"enable"` + Username string `json:"username" yaml:"username"` + Password string `json:"password" yaml:"password"` + PwaName string `json:"pwa_name" yaml:"pwa-name"` + PwaShortName string `json:"pwa_short_name" yaml:"pwa-short_name"` + PwaDesc string `json:"pwa_description" yaml:"pwa-description"` + + NotifySubject string `json:"notification_subject" yaml:"notification-subject"` +} diff --git a/config/server.go b/config/server.go new file mode 100644 index 00000000..17fa0a9b --- /dev/null +++ b/config/server.go @@ -0,0 +1,161 @@ +/** + * OpenBmclAPI (Golang Edition) + * Copyright (C) 2024 Kevin Z + * All rights reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package config + +import ( + "errors" + "fmt" + "regexp" + + "gopkg.in/yaml.v3" + + "github.com/LiterMC/go-openbmclapi/cache" + "github.com/LiterMC/go-openbmclapi/utils" +) + +type ClusterOptions struct { + Id string `json:"id" yaml:"id"` + Secret string `json:"secret" yaml:"secret"` + Byoc bool `json:"byoc" yaml:"byoc"` + PublicHosts []string `json:"public_hosts" yaml:"public-hosts"` + Server string `json:"server" yaml:"server"` + SkipSignatureCheck bool `json:"skip_signature_check" yaml:"skip-signature-check"` + Storages []string `json:"storages" yaml:"storages"` +} + +type ClusterGeneralConfig struct { + PublicHost string `json:"public_host"` + PublicPort uint16 `json:"public_port"` + NoFastEnable bool `json:"no_fast_enable"` + MaxReconnectCount int `json:"max_reconnect_count"` +} + +type UserItem struct { + Username string `json:"username" yaml:"username"` + Password string `json:"password" yaml:"password"` +} + +type CertificateConfig struct { + Cert string `json:"cert" yaml:"cert"` + Key string `json:"key" yaml:"key"` +} + +type DatabaseConfig struct { + Driver string `json:"driver" yaml:"driver"` + DSN string `json:"data_source_name" yaml:"data-source-name"` +} + +type HijackConfig struct { + Enable bool `json:"enable" yaml:"enable"` + EnableLocalCache bool `json:"enable_local_cache" yaml:"enable-local-cache"` + LocalCachePath string `json:"local_cache_path" yaml:"local-cache-path"` + RequireAuth bool `json:"require_auth" yaml:"require-auth"` + AuthUsers []UserItem `json:"auth_users" yaml:"auth-users"` +} + +type CacheConfig struct { + Type string `json:"type" yaml:"type"` + Data any `json:"data" yaml:"data,omitempty"` + + newCache func() cache.Cache `json:"-" yaml:"-"` +} + +func (c *CacheConfig) NewCache() cache.Cache { + return c.newCache() +} + +func (c *CacheConfig) UnmarshalYAML(n *yaml.Node) (err error) { + var cfg struct { + Type string `yaml:"type"` + Data utils.RawYAML `yaml:"data,omitempty"` + } + if err = n.Decode(&cfg); err != nil { + return + } + c.Type = cfg.Type + c.Data = nil + switch c.Type { + case "no-cache": + c.newCache = func() cache.Cache { return cache.NoCache } + case "memory": + c.newCache = func() cache.Cache { return cache.NewInMemCache() } + case "redis": + opt := new(cache.RedisOptions) + if err = cfg.Data.Decode(opt); err != nil { + return + } + c.Data = opt + c.newCache = func() cache.Cache { return cache.NewRedisCache(opt.ToRedis()) } + default: + return fmt.Errorf("Unexpected cache type %q", c.Type) + } + return nil +} + +type ServeLimitConfig struct { + Enable bool `json:"enable" yaml:"enable"` + MaxConn int `json:"max_conn" yaml:"max-conn"` + UploadRate int `json:"upload_rate" yaml:"upload-rate"` +} + +type GithubAPIConfig struct { + UpdateCheckInterval utils.YAMLDuration `json:"update_check_interval" yaml:"update-check-interval"` + Authorization string `json:"authorization" yaml:"authorization"` +} + +type TunnelConfig struct { + Enable bool `json:"enable" yaml:"enable"` + TunnelProg string `json:"tunnel_program" yaml:"tunnel-program"` + OutputRegex string `json:"output_regex" yaml:"output-regex"` + + outputRegex *regexp.Regexp + hostOut int + portOut int +} + +func (c *TunnelConfig) UnmarshalYAML(n *yaml.Node) (err error) { + type T TunnelConfig + if err = n.Decode((*T)(c)); err != nil { + return + } + if !c.Enable { + return + } + if c.outputRegex, err = regexp.Compile(c.OutputRegex); err != nil { + return + } + c.hostOut = c.outputRegex.SubexpIndex("host") + c.portOut = c.outputRegex.SubexpIndex("port") + if c.hostOut <= 0 { + return errors.New("tunneler.output-regex: missing named `(?)` capture group") + } + if c.portOut <= 0 { + return errors.New("tunneler.output-regex: missing named `(?)` capture group") + } + return +} + +func (c *TunnelConfig) MatchTunnelOutput(line []byte) (host, port []byte, ok bool) { + res := c.outputRegex.FindSubmatch(line) + if res == nil { + return + } + return res[c.hostOut], res[c.portOut], true +} diff --git a/dashboard.go b/dashboard.go index b07b0e8f..ff7d99cb 100644 --- a/dashboard.go +++ b/dashboard.go @@ -31,6 +31,7 @@ import ( "path" "strings" + "github.com/LiterMC/go-openbmclapi/internal/build" "github.com/LiterMC/go-openbmclapi/utils" ) @@ -60,13 +61,14 @@ var dsbManifest = func() (dsbManifest map[string]any) { return }() -func (cr *Cluster) serveDashboard(rw http.ResponseWriter, req *http.Request, pth string) { +func (r *Runner) serveDashboard(rw http.ResponseWriter, req *http.Request) { if req.Method != http.MethodGet && req.Method != http.MethodHead { rw.Header().Set("Allow", http.MethodGet+", "+http.MethodHead) http.Error(rw, "405 Method Not Allowed", http.StatusMethodNotAllowed) return } acceptEncoding := utils.SplitCSV(req.Header.Get("Accept-Encoding")) + pth := strings.TrimPrefix(req.URL.Path, "/") switch pth { case "": break @@ -78,7 +80,7 @@ func (cr *Cluster) serveDashboard(rw http.ResponseWriter, req *http.Request, pth return } rw.Header().Set("Content-Type", "application/manifest+json") - http.ServeContent(rw, req, "manifest.webmanifest", startTime, bytes.NewReader(buf)) + http.ServeContent(rw, req, "manifest.webmanifest", build.StartAt, bytes.NewReader(buf)) return case "sw.js": // Must not cache service worker @@ -111,15 +113,15 @@ func (cr *Cluster) serveDashboard(rw http.ResponseWriter, req *http.Request, pth if _, err := io.Copy(gw, fd); err == nil { if err = gw.Close(); err == nil { rw.Header().Set("Content-Encoding", "gzip") - http.ServeContent(rw, req, name, startTime, bytes.NewReader(buf.Bytes())) + http.ServeContent(rw, req, name, build.StartAt, bytes.NewReader(buf.Bytes())) return } } } - http.ServeContent(rw, req, name, startTime, fd.(io.ReadSeeker)) + http.ServeContent(rw, req, name, build.StartAt, fd.(io.ReadSeeker)) return } } rw.Header().Set("Content-Type", "text/html; charset=utf-8") - http.ServeContent(rw, req, "index.html", startTime, strings.NewReader(dsbIndexHtml)) + http.ServeContent(rw, req, "index.html", build.StartAt, strings.NewReader(dsbIndexHtml)) } diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 705512d6..223d133a 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -8,13 +8,14 @@ "name": "dashboard", "version": "0.0.0", "dependencies": { + "@primeuix/themes": "^1.0.1", "@types/pako": "^2.0.3", "axios": "^1.6.2", "chart.js": "^4.4.1", "js-sha256": "^0.11.0", "pako": "^2.1.0", "primeicons": "^6.0.1", - "primevue": "^3.49.0", + "primevue": "^4.3.3", "register-service-worker": "^1.7.2", "vue": "^3.2.47", "vue-cookies": "^1.8.3", @@ -45,146 +46,72 @@ "workbox-window": "^7.0.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@antfu/utils": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.7.tgz", - "integrity": "sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==", + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", - "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.6", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", - "@babel/types": "^7.23.6", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -199,75 +126,56 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", + "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", - "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", - "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", + "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.26.8", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -275,44 +183,29 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz", - "integrity": "sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", + "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.27.0", "semver": "^6.3.1" }, "engines": { @@ -327,18 +220,20 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", - "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.0.tgz", + "integrity": "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "engines": { @@ -353,15 +248,17 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", + "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", "@babel/helper-plugin-utils": "^7.22.5", @@ -373,75 +270,44 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -451,35 +317,38 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", - "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-wrap-function": "^7.22.20" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -489,14 +358,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", + "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -505,200 +375,133 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true, + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true, + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", - "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", - "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.22.5", - "@babel/template": "^7.22.15", - "@babel/types": "^7.22.19" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", - "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", + "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", - "@babel/types": "^7.23.6" + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dev": true, + "node_modules/@babel/parser": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", + "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "@babel/types": "^7.27.0" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "bin": { - "parser": "bin/babel-parser.js" + "node": ">=6.9.0" }, - "engines": { - "node": ">=6.0.0" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", - "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -708,14 +511,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", - "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-transform-optional-chaining": "^7.23.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -725,13 +529,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", - "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -745,6 +550,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -752,76 +558,99 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", + "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.26.8" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", - "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -830,13 +659,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", - "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", + "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -845,279 +675,72 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.0.tgz", + "integrity": "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.26.5" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", - "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", - "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", - "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-remap-async-to-generator": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", - "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", - "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", - "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", - "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", - "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-split-export-declaration": "^7.22.6", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -1128,18 +751,20 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", - "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.15" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1149,12 +774,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", - "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1164,13 +790,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", - "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1180,12 +807,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", - "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1194,14 +822,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", - "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1211,13 +856,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", - "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", + "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1227,13 +872,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", - "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1243,13 +888,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", - "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", + "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1259,14 +905,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", - "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1276,13 +923,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", - "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1292,12 +939,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", - "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1307,13 +955,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", - "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1323,12 +971,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", - "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1338,13 +987,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", - "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1354,14 +1004,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", - "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1371,15 +1021,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", - "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1389,13 +1040,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", - "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1405,13 +1057,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", - "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1421,12 +1074,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", - "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1436,13 +1090,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", - "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", + "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1452,13 +1106,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", - "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1468,16 +1122,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", - "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.23.3" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1487,13 +1140,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", - "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1503,13 +1157,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", - "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1519,14 +1173,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", - "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1536,12 +1190,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", - "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1551,13 +1206,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", - "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1567,15 +1223,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", - "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-create-class-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1585,12 +1241,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", - "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1600,12 +1257,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", - "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.0.tgz", + "integrity": "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.26.5", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1615,13 +1273,31 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", - "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1631,12 +1307,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", - "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1646,13 +1323,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", - "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1662,12 +1340,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", - "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1677,12 +1356,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", - "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", + "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1692,12 +1372,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", - "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.0.tgz", + "integrity": "sha512-+LLkxA9rKJpNoGsbLnAgOCdESl73vwYn+V6b+5wHbrE7OGKVDPHIQvbFSzqE6rwqaCw2RE+zdJrlLkcf8YOA0w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.26.5" }, "engines": { "node": ">=6.9.0" @@ -1707,12 +1388,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", - "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1722,13 +1404,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", - "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1738,13 +1421,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", - "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1754,13 +1438,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", - "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1770,90 +1455,80 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.6.tgz", - "integrity": "sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", + "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.8", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-plugin-utils": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.23.3", - "@babel/plugin-syntax-import-attributes": "^7.23.3", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.4", - "@babel/plugin-transform-async-to-generator": "^7.23.3", - "@babel/plugin-transform-block-scoped-functions": "^7.23.3", - "@babel/plugin-transform-block-scoping": "^7.23.4", - "@babel/plugin-transform-class-properties": "^7.23.3", - "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.5", - "@babel/plugin-transform-computed-properties": "^7.23.3", - "@babel/plugin-transform-destructuring": "^7.23.3", - "@babel/plugin-transform-dotall-regex": "^7.23.3", - "@babel/plugin-transform-duplicate-keys": "^7.23.3", - "@babel/plugin-transform-dynamic-import": "^7.23.4", - "@babel/plugin-transform-exponentiation-operator": "^7.23.3", - "@babel/plugin-transform-export-namespace-from": "^7.23.4", - "@babel/plugin-transform-for-of": "^7.23.6", - "@babel/plugin-transform-function-name": "^7.23.3", - "@babel/plugin-transform-json-strings": "^7.23.4", - "@babel/plugin-transform-literals": "^7.23.3", - "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", - "@babel/plugin-transform-member-expression-literals": "^7.23.3", - "@babel/plugin-transform-modules-amd": "^7.23.3", - "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.3", - "@babel/plugin-transform-modules-umd": "^7.23.3", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", - "@babel/plugin-transform-new-target": "^7.23.3", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", - "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.23.4", - "@babel/plugin-transform-object-super": "^7.23.3", - "@babel/plugin-transform-optional-catch-binding": "^7.23.4", - "@babel/plugin-transform-optional-chaining": "^7.23.4", - "@babel/plugin-transform-parameters": "^7.23.3", - "@babel/plugin-transform-private-methods": "^7.23.3", - "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-property-literals": "^7.23.3", - "@babel/plugin-transform-regenerator": "^7.23.3", - "@babel/plugin-transform-reserved-words": "^7.23.3", - "@babel/plugin-transform-shorthand-properties": "^7.23.3", - "@babel/plugin-transform-spread": "^7.23.3", - "@babel/plugin-transform-sticky-regex": "^7.23.3", - "@babel/plugin-transform-template-literals": "^7.23.3", - "@babel/plugin-transform-typeof-symbol": "^7.23.3", - "@babel/plugin-transform-unicode-escapes": "^7.23.3", - "@babel/plugin-transform-unicode-property-regex": "^7.23.3", - "@babel/plugin-transform-unicode-regex": "^7.23.3", - "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.26.8", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.26.5", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.26.3", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.26.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.26.8", + "@babel/plugin-transform-typeof-symbol": "^7.26.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.6", - "babel-plugin-polyfill-corejs3": "^0.8.5", - "babel-plugin-polyfill-regenerator": "^0.5.3", - "core-js-compat": "^3.31.0", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.11.0", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.40.0", "semver": "^6.3.1" }, "engines": { @@ -1868,6 +1543,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -1877,6 +1553,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -1886,17 +1563,12 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true - }, "node_modules/@babel/runtime": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", - "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1904,34 +1576,40 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", + "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", - "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", + "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.27.0", + "@babel/parser": "^7.27.0", + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1944,19 +1622,19 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", - "dev": true, + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", + "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1966,7 +1644,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz", "integrity": "sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", @@ -1976,6 +1655,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -1992,6 +1672,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -2008,6 +1689,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -2024,6 +1706,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2040,6 +1723,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -2056,6 +1740,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2072,6 +1757,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2088,6 +1774,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2104,6 +1791,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2120,6 +1808,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2136,6 +1825,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2152,6 +1842,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2168,6 +1859,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2184,6 +1876,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2200,6 +1893,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2216,6 +1910,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -2232,6 +1927,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -2248,6 +1944,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -2264,6 +1961,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -2280,6 +1978,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2296,6 +1995,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2312,6 +2012,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2321,25 +2022,30 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -2349,6 +2055,7 @@ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -2368,22 +2075,25 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -2395,6 +2105,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -2404,78 +2115,88 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@kurkle/color": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", - "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@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" @@ -2489,6 +2210,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -2498,6 +2220,7 @@ "resolved": "https://registry.npmjs.org/@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" @@ -2506,56 +2229,208 @@ "node": ">= 8" } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz", - "integrity": "sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==", - "dev": true - }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, + "node_modules/@primeuix/styled": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.5.1.tgz", + "integrity": "sha512-5Ftw/KSauDPClQ8F2qCyCUF7cIUEY4yLNikf0rKV7Vsb8zGYNK0dahQe7CChaR6M2Kn+NA2DSBSk76ZXqj6Uog==", + "license": "MIT", "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" + "@primeuix/utils": "^0.5.3" }, "engines": { - "node": ">=6" + "node": ">=12.11.0" } }, - "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, + "node_modules/@primeuix/styles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-1.0.1.tgz", + "integrity": "sha512-R7SX001ILHIJM9hh1opbsuOFFK8dOM8GY1y99jaCFnAc5gGy3mFPJMhoexRYV1a6UZ2YbfcsQVPbIhoONI1gfg==", + "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@primeuix/styled": "^0.5.1" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, + "node_modules/@primeuix/themes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@primeuix/themes/-/themes-1.0.1.tgz", + "integrity": "sha512-RllttI3oGTZa66UQDCIA2lPnJvO/xqtNpy+0eNql6fIxdS2AUg5n7L81jTZrHNZ+31T5OBzL/SGFCDycmHTz2g==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.5.1" + } + }, + "node_modules/@primeuix/utils": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.5.3.tgz", + "integrity": "sha512-7SGh7734wcF1/uK6RzO6Z6CBjGQ97GDHfpyl2F1G/c7R0z9hkT/V72ypDo82AWcCS7Ta07oIjDpOCTkSVZuEGQ==", + "license": "MIT", + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primevue/core": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.3.3.tgz", + "integrity": "sha512-kSkN5oourG7eueoFPIqiNX3oDT/f0I5IRK3uOY/ytz+VzTZp5yuaCN0Nt42ZQpVXjDxMxDvUhIdaXVrjr58NhQ==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.5.0", + "@primeuix/utils": "^0.5.1" + }, + "engines": { + "node": ">=12.11.0" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@primevue/icons": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.3.3.tgz", + "integrity": "sha512-ouQaxHyeFB6MSfEGGbjaK5Qv9efS1xZGetZoU5jcPm090MSYLFtroP1CuK3lZZAQals06TZ6T6qcoNukSHpK5w==", + "license": "MIT", + "dependencies": { + "@primeuix/utils": "^0.5.1", + "@primevue/core": "4.3.3" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", + "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "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/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz", + "integrity": "sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "version": "18.19.86", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", + "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -2563,34 +2438,36 @@ "node_modules/@types/pako": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.3.tgz", - "integrity": "sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==" + "integrity": "sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==", + "license": "MIT" }, "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true, - "dependencies": { - "@types/node": "*" - } + "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -2625,6 +2502,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -2652,6 +2530,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" @@ -2669,6 +2548,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.62.0", "@typescript-eslint/utils": "5.62.0", @@ -2696,6 +2576,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2709,6 +2590,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", @@ -2736,6 +2618,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", @@ -2762,6 +2645,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" @@ -2775,16 +2659,18 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" }, "node_modules/@vite-pwa/assets-generator": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@vite-pwa/assets-generator/-/assets-generator-0.2.1.tgz", - "integrity": "sha512-NoFsE/XzmkF3WDr+1NjbjdP4GDBZMPQ49eFS33H8FlIH50g4AAK5+W3Y2xeRy7tKE5nB7MLYybesSqk+zD4L0Q==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@vite-pwa/assets-generator/-/assets-generator-0.2.6.tgz", + "integrity": "sha512-kK44dXltvoubEo5B+6tCGjUrOWOE1+dA4DForbFpO1rKy2wSkAVGrs8tyfN6DzTig89/QKyV8XYodgmaKyrYng==", "dev": true, + "license": "MIT", "dependencies": { "cac": "^6.7.14", "colorette": "^2.0.20", @@ -2804,10 +2690,11 @@ } }, "node_modules/@vitejs/plugin-vue": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.2.tgz", - "integrity": "sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", + "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.0.0" }, @@ -2821,6 +2708,7 @@ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", "dev": true, + "license": "MIT", "dependencies": { "@volar/source-map": "1.11.1" } @@ -2830,6 +2718,7 @@ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", "dev": true, + "license": "MIT", "dependencies": { "muggle-string": "^0.3.1" } @@ -2839,67 +2728,74 @@ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", "dev": true, + "license": "MIT", "dependencies": { "@volar/language-core": "1.11.1", "path-browserify": "^1.0.1" } }, "node_modules/@vue/compiler-core": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.11.tgz", - "integrity": "sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==", - "dependencies": { - "@babel/parser": "^7.23.5", - "@vue/shared": "3.3.11", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz", - "integrity": "sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.3.11", - "@vue/shared": "3.3.11" + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz", - "integrity": "sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==", - "dependencies": { - "@babel/parser": "^7.23.5", - "@vue/compiler-core": "3.3.11", - "@vue/compiler-dom": "3.3.11", - "@vue/compiler-ssr": "3.3.11", - "@vue/reactivity-transform": "3.3.11", - "@vue/shared": "3.3.11", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", - "magic-string": "^0.30.5", - "postcss": "^8.4.32", - "source-map-js": "^1.0.2" + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz", - "integrity": "sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.3.11", - "@vue/shared": "3.3.11" + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/devtools-api": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", - "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" }, "node_modules/@vue/eslint-config-prettier": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@vue/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz", "integrity": "sha512-Pv/lVr0bAzSIHLd9iz0KnvAr4GKyCEl+h52bc4e5yWuDVtLgFwycF7nrbWTAQAS+FU6q1geVd07lc6EWfJiWKQ==", "dev": true, + "license": "MIT", "dependencies": { "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0" @@ -2914,6 +2810,7 @@ "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-11.0.3.tgz", "integrity": "sha512-dkt6W0PX6H/4Xuxg/BlFj5xHvksjpSlVjtkQCpaYJBIEuKj2hOVU7r+TIe+ysCwRYFz/lGqvklntRkCAibsbPw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/eslint-plugin": "^5.59.1", "@typescript-eslint/parser": "^5.59.1", @@ -2934,10 +2831,11 @@ } }, "node_modules/@vue/language-core": { - "version": "1.8.25", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.25.tgz", - "integrity": "sha512-NJk/5DnAZlpvXX8BdWmHI45bWGLViUaS3R/RMrmFSvFMSbJKuEODpM4kR0F0Ofv5SFzCWuNiMhxameWpVdQsnA==", + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", "dev": true, + "license": "MIT", "dependencies": { "@volar/language-core": "~1.11.1", "@volar/source-map": "~1.11.1", @@ -2963,15 +2861,17 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2983,66 +2883,61 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.11.tgz", - "integrity": "sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==", - "dependencies": { - "@vue/shared": "3.3.11" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.11.tgz", - "integrity": "sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.23.5", - "@vue/compiler-core": "3.3.11", - "@vue/shared": "3.3.11", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.5" + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-core": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.11.tgz", - "integrity": "sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "license": "MIT", "dependencies": { - "@vue/reactivity": "3.3.11", - "@vue/shared": "3.3.11" + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" } }, "node_modules/@vue/runtime-dom": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz", - "integrity": "sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "license": "MIT", "dependencies": { - "@vue/runtime-core": "3.3.11", - "@vue/shared": "3.3.11", - "csstype": "^3.1.2" + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.11.tgz", - "integrity": "sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.3.11", - "@vue/shared": "3.3.11" + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { - "vue": "3.3.11" + "vue": "3.5.13" } }, "node_modules/@vue/shared": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.11.tgz", - "integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==" + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "license": "MIT" }, "node_modules/@vue/tsconfig": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.1.3.tgz", "integrity": "sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==", "dev": true, + "license": "MIT", "peerDependencies": { "@types/node": "*" }, @@ -3053,10 +2948,11 @@ } }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3069,6 +2965,7 @@ "resolved": "https://registry.npmjs.org/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" } @@ -3078,6 +2975,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3094,6 +2992,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3103,6 +3002,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3117,16 +3017,21 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3137,23 +3042,25 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -3162,25 +3069,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -3189,29 +3119,32 @@ } }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", - "dev": true + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz", - "integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==", + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", + "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.4", + "@babel/helper-define-polyfill-provider": "^0.6.4", "semver": "^6.3.1" }, "peerDependencies": { @@ -3223,30 +3156,33 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", + "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" + "@babel/helper-define-polyfill-provider": "^0.6.3", + "core-js-compat": "^3.40.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz", - "integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", + "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4" + "@babel/helper-define-polyfill-provider": "^0.6.4" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -3256,21 +3192,95 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "license": "MIT", "dependencies": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" } }, - "node_modules/babel-runtime/node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.2.tgz", + "integrity": "sha512-8wSeOia5B7LwD4+h465y73KOdj5QHsbbuoUfPBi+pXgFJIPuG7SsiOdJuijWMyfid49eD+WivpfY7KT8gbAzBA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -3290,13 +3300,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -3307,34 +3319,37 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", "dev": true, "funding": [ { @@ -3350,11 +3365,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -3382,6 +3398,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -3391,38 +3408,63 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3433,14 +3475,15 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001570", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", - "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "version": "1.0.30001710", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001710.tgz", + "integrity": "sha512-B5C0I0UmaGqHgo5FuqJ7hBd4L57A4dDD+Xi+XX1nXOoxGeDdY4Ko38qJYOyqznBVJEqON5p8P1x5zRR3+rsnxA==", "dev": true, "funding": [ { @@ -3455,13 +3498,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3474,27 +3519,30 @@ } }, "node_modules/chart.js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", - "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz", + "integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==", + "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" }, "engines": { - "pnpm": ">=7" + "pnpm": ">=8" } }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" @@ -3508,6 +3556,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3519,13 +3568,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -3535,12 +3586,14 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3548,11 +3601,19 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -3561,19 +3622,22 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.18.0 || >=16.10.0" } @@ -3582,22 +3646,25 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/core-js": { "version": "2.6.12", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true + "hasInstallScript": true, + "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", - "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", + "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.22.2" + "browserslist": "^4.24.4" }, "funding": { "type": "opencollective", @@ -3605,10 +3672,11 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3623,6 +3691,7 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3632,6 +3701,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -3642,29 +3712,86 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, - "node_modules/de-indent": { + "node_modules/data-view-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">=6.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decode-bmp": { @@ -3672,6 +3799,7 @@ "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", "integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==", "dev": true, + "license": "MIT", "dependencies": { "@canvas/image-data": "^1.0.0", "to-data-view": "^1.1.0" @@ -3685,6 +3813,7 @@ "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz", "integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==", "dev": true, + "license": "MIT", "dependencies": { "@canvas/image-data": "^1.0.0", "decode-bmp": "^0.2.0", @@ -3699,6 +3828,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "license": "MIT", "dependencies": { "mimic-response": "^3.1.0" }, @@ -3714,6 +3844,7 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -3722,20 +3853,35 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-properties": { @@ -3743,6 +3889,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -3756,24 +3903,27 @@ } }, "node_modules/defu": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.3.tgz", - "integrity": "sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==", - "dev": true + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } }, "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8" } @@ -3783,6 +3933,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -3795,6 +3946,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -3802,11 +3954,26 @@ "node": ">=6.0.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -3818,74 +3985,102 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.614", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz", - "integrity": "sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==", - "dev": true + "version": "1.5.132", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.132.tgz", + "integrity": "sha512-QgX9EBvWGmvSRa74zqfnG7+Eno0Ak0vftBll0Pt2/z5b3bEGYL6OUXLgKPtvx73dn3dvwrlyVkjPKRRlhLYTEg==", + "dev": true, + "license": "ISC" }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -3894,29 +4089,61 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -3931,6 +4158,7 @@ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -3963,10 +4191,11 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -3976,6 +4205,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3984,16 +4214,18 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -4043,6 +4275,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4055,6 +4288,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", "dev": true, + "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0" }, @@ -4072,24 +4306,26 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.19.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.19.2.tgz", - "integrity": "sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==", + "version": "9.33.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", + "integrity": "sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", "natural-compare": "^1.4.0", "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.13", - "semver": "^7.5.4", - "vue-eslint-parser": "^9.3.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "vue-eslint-parser": "^9.4.3", "xml-name-validator": "^4.0.0" }, "engines": { "node": "^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-scope": { @@ -4097,6 +4333,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -4110,6 +4347,7 @@ "resolved": "https://registry.npmjs.org/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" }, @@ -4122,6 +4360,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -4138,6 +4377,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4147,6 +4387,7 @@ "resolved": "https://registry.npmjs.org/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", @@ -4160,10 +4401,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -4176,6 +4418,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4185,6 +4428,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4197,6 +4441,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4206,6 +4451,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -4213,13 +4459,15 @@ "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/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" }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -4229,6 +4477,7 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, + "license": "(MIT OR WTFPL)", "engines": { "node": ">=6" } @@ -4237,31 +4486,35 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-diff": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/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.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -4272,6 +4525,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4283,19 +4537,39 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -4305,6 +4579,7 @@ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -4317,6 +4592,7 @@ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } @@ -4326,6 +4602,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -4335,6 +4612,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4343,10 +4621,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4359,6 +4638,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4375,6 +4655,7 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -4385,21 +4666,23 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -4410,21 +4693,30 @@ } }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" }, "engines": { @@ -4435,13 +4727,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -4456,7 +4750,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -4464,6 +4759,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -4476,21 +4772,24 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -4504,6 +4803,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4513,20 +4813,30 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4536,16 +4846,32 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4558,13 +4884,16 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4585,6 +4914,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -4597,6 +4927,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -4608,12 +4939,14 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -4627,6 +4960,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -4643,12 +4977,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4658,19 +4992,25 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4680,27 +5020,33 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4709,10 +5055,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4721,12 +5067,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -4736,10 +5082,10 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4752,6 +5098,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -4760,19 +5107,22 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ico-endec": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz", "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==", - "dev": true + "dev": true, + "license": "MPL-2.0" }, "node_modules/idb": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ieee754": { "version": "1.2.1", @@ -4792,22 +5142,25 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4824,6 +5177,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4832,7 +5186,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -4842,37 +5198,44 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4882,28 +5245,54 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4917,6 +5306,7 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4925,24 +5315,48 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4956,33 +5370,20 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "call-bound": "^1.0.3" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -4990,22 +5391,77 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number": { - "version": "7.0.0", + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/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-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5019,6 +5475,7 @@ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5028,18 +5485,22 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -5053,29 +5514,62 @@ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5085,12 +5579,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5100,13 +5597,27 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5115,12 +5626,33 @@ } }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5130,19 +5662,22 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -5156,17 +5691,12 @@ "node": ">=10" } }, - "node_modules/jake/node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } @@ -5174,19 +5704,22 @@ "node_modules/js-sha256": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.0.tgz", - "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==" + "integrity": "sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q==", + "license": "MIT" }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -5195,58 +5728,72 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/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/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -5259,6 +5806,7 @@ "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5268,6 +5816,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -5277,6 +5826,7 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5286,6 +5836,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -5299,6 +5850,7 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^4.0.0", @@ -5314,6 +5866,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -5328,47 +5881,56 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "yallist": "^3.0.2" } }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.4" } }, "node_modules/memorystream": { @@ -5380,28 +5942,24 @@ "node": ">= 0.10.0" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/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.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5412,6 +5970,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5420,6 +5979,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -5432,6 +5992,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5444,6 +6005,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5456,6 +6018,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5464,42 +6027,34 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mlly": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", - "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", "dev": true, - "dependencies": { - "acorn": "^8.10.0", - "pathe": "^1.1.1", - "pkg-types": "^1.0.3", - "ufo": "^1.3.0" - } + "license": "MIT" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/muggle-string": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5508,34 +6063,39 @@ } }, "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/natural-compare-lite": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-abi": { - "version": "3.52.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", - "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", + "version": "3.74.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz", + "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.3.5" }, @@ -5547,19 +6107,22 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -5572,6 +6135,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -5581,6 +6145,7 @@ "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", @@ -5606,6 +6171,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -5618,6 +6184,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -5632,6 +6199,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -5640,13 +6208,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, + "license": "MIT", "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -5663,6 +6233,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -5672,6 +6243,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5681,6 +6253,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -5690,6 +6263,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -5699,6 +6273,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^1.0.0" }, @@ -5711,6 +6286,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5720,6 +6296,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -5732,6 +6309,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -5744,6 +6322,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -5752,10 +6331,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5765,19 +6348,23 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -5792,32 +6379,53 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -5833,6 +6441,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -5846,13 +6455,15 @@ "node_modules/pako": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -5865,6 +6476,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, + "license": "MIT", "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -5877,13 +6489,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5893,6 +6507,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5902,6 +6517,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5910,33 +6526,31 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", - "dev": true - }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -5949,6 +6563,7 @@ "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true, + "license": "MIT", "bin": { "pidtree": "bin/pidtree.js" }, @@ -5961,25 +6576,25 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, - "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", - "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "funding": [ { "type": "opencollective", @@ -5994,20 +6609,22 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -6017,17 +6634,18 @@ } }, "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "dev": true, + "license": "MIT", "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", + "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", @@ -6043,10 +6661,11 @@ } }, "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", + "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", "dev": true, + "license": "MIT", "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -6059,6 +6678,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -6075,6 +6695,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -6084,6 +6705,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -6099,6 +6721,7 @@ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, + "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -6106,29 +6729,53 @@ "node": ">=6.0.0" } }, + "node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/primeicons": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz", - "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" + "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==", + "license": "MIT" }, "node_modules/primevue": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.49.0.tgz", - "integrity": "sha512-1lFTU/WK1wcjaaKqce7XldrH4MGPySXxH9Nyoj0d9QiGehePw9JUQrGhVgfjx3I/MD/VgE85wF1HihqtPJehbw==", - "peerDependencies": { - "vue": "^3.0.0" + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.3.3.tgz", + "integrity": "sha512-nooYVoEz5CdP3EhUkD6c3qTdRmpLHZh75fBynkUkl46K8y5rksHTjdSISiDijwTA5STQIOkyqLb+RM+HQ6nC1Q==", + "license": "MIT", + "dependencies": { + "@primeuix/styled": "^0.5.0", + "@primeuix/styles": "^1.0.0", + "@primeuix/utils": "^0.5.1", + "@primevue/core": "4.3.3", + "@primevue/icons": "4.3.3" + }, + "engines": { + "node": ">=12.11.0" } }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dev": true, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -6139,6 +6786,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6161,19 +6809,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "dev": true + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -6183,6 +6827,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -6198,6 +6843,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6207,6 +6853,7 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, + "license": "MIT", "dependencies": { "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", @@ -6221,6 +6868,7 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^3.0.0" }, @@ -6233,6 +6881,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -6242,17 +6891,42 @@ "node": ">= 6" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -6261,29 +6935,34 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6293,15 +6972,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -6312,27 +6992,40 @@ "node_modules/register-service-worker": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/register-service-worker/-/register-service-worker-1.7.2.tgz", - "integrity": "sha512-CiD3ZSanZqcMPRhtfct5K9f7i3OLCcBBWsJjLh1gW9RO/nS94sVzY59iS+fgYBOBqaBpf4EzfqUF3j9IG+xo8A==" + "integrity": "sha512-CiD3ZSanZqcMPRhtfct5K9f7i3OLCcBBWsJjLh1gW9RO/nS94sVzY59iS+fgYBOBqaBpf4EzfqUF3j9IG+xo8A==", + "license": "MIT" + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, "node_modules/require-from-string": { @@ -6340,23 +7033,28 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6366,15 +7064,17 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -6384,7 +7084,9 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -6396,10 +7098,11 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, + "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -6430,19 +7133,22 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -6470,61 +7176,111 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, - "node_modules/safe-regex-test": { + "node_modules/safe-push-apply": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" } }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -6536,6 +7292,7 @@ "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", "dev": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.2", @@ -6558,6 +7315,7 @@ "resolved": "https://registry.npmjs.org/sharp-ico/-/sharp-ico-0.1.5.tgz", "integrity": "sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==", "dev": true, + "license": "MIT", "dependencies": { "decode-ico": "*", "ico-endec": "*", @@ -6569,6 +7327,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -6581,28 +7340,95 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6626,7 +7452,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/simple-get": { "version": "4.0.1", @@ -6647,6 +7474,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -6658,6 +7486,7 @@ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } @@ -6666,30 +7495,44 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -6699,58 +7542,78 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" }, "node_modules/streamx": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", - "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", "dev": true, + "license": "MIT", "dependencies": { - "fast-fifo": "^1.1.0", - "queue-tick": "^1.0.1" + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { @@ -6758,39 +7621,50 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.padend": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.5.tgz", - "integrity": "sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -6800,14 +7674,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6817,28 +7696,37 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6849,6 +7737,7 @@ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "get-own-enumerable-property-symbols": "^3.0.0", "is-obj": "^1.0.1", @@ -6863,6 +7752,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -6875,6 +7765,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -6884,6 +7775,7 @@ "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -6893,6 +7785,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -6905,6 +7798,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6917,6 +7811,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6925,21 +7820,26 @@ } }, "node_modules/tar-fs": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", - "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", "dev": true, + "license": "MIT", "dependencies": { - "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" } }, "node_modules/tar-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", - "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dev": true, + "license": "MIT", "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -6951,6 +7851,7 @@ "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6960,6 +7861,7 @@ "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", "dev": true, + "license": "MIT", "dependencies": { "is-stream": "^2.0.0", "temp-dir": "^2.0.0", @@ -6973,23 +7875,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tempy/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/tempy/node_modules/type-fest": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -6998,10 +7889,11 @@ } }, "node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -7015,38 +7907,36 @@ "node": ">=10" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/to-data-view": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", "integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "engines": { - "node": ">=4" - } + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/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" }, @@ -7054,17 +7944,29 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -7080,6 +7982,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -7092,6 +7995,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -7104,6 +8008,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -7112,29 +8017,32 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -7144,16 +8052,19 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -7163,14 +8074,21 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7181,6 +8099,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "devOptional": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7189,37 +8108,35 @@ "node": ">=4.2.0" } }, - "node_modules/ufo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", - "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", - "dev": true - }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/unconfig": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-0.3.11.tgz", - "integrity": "sha512-bV/nqePAKv71v3HdVUn6UefbsDKQWRX+bJIkiSm0+twIds6WiD2bJLWWT3i214+J/B4edufZpG2w7Y63Vbwxow==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-0.3.13.tgz", + "integrity": "sha512-N9Ph5NC4+sqtcOjPfHrRcHekBCadCXWTBzp2VYYbySOHW0PfD9XLCeXshTXjkPYwLrBr9AtSeU0CZmkYECJhng==", "dev": true, + "license": "MIT", "dependencies": { - "@antfu/utils": "^0.7.6", - "defu": "^6.1.2", - "jiti": "^1.20.0", - "mlly": "^1.4.2" + "@antfu/utils": "^0.7.7", + "defu": "^6.1.4", + "jiti": "^1.21.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -7229,13 +8146,15 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7245,6 +8164,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -7254,10 +8174,11 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7267,6 +8188,7 @@ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7276,6 +8198,7 @@ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "dev": true, + "license": "MIT", "dependencies": { "crypto-random-string": "^2.0.0" }, @@ -7288,6 +8211,7 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -7297,15 +8221,16 @@ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4", "yarn": "*" } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -7321,9 +8246,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -7337,6 +8263,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -7345,23 +8272,26 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "node_modules/vite": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", - "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "version": "4.5.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.12.tgz", + "integrity": "sha512-qrMwavANtSz91nDy3zEiUHMtL09x0mniQsSMvDkNxuCBM1W5vriJ22hEmwTth6DhLSWsZnHBT0yHFAQXt6efGA==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", @@ -7417,6 +8347,7 @@ "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.17.5.tgz", "integrity": "sha512-UxRNPiJBzh4tqU/vc8G2TxmrUTzT6BqvSzhszLk62uKsf+npXdvLxGDz9C675f4BJi6MbD2tPnJhi5txlMzxbQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4", "fast-glob": "^3.3.2", @@ -7436,274 +8367,355 @@ "workbox-window": "^7.0.0" } }, - "node_modules/vite-plugin-pwa/node_modules/@apideck/better-ajv-errors": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", - "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", - "dev": true, - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/vite-plugin-pwa/node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", - "dev": true, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" + "typescript": "*" }, "peerDependenciesMeta": { - "@types/babel__core": { + "typescript": { "optional": true } } }, - "node_modules/vite-plugin-pwa/node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "node_modules/vue-cookies": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.8.6.tgz", + "integrity": "sha512-e2kYaHj1Y/zVsBSM3KWlOoVJ5o3l4QZjytNU7xdCgmkw3521CMUerqHekBGZKXXC1oRxYljBeeOK2SCel6cKuw==", + "license": "MIT" + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz", + "integrity": "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==", "dev": true, + "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" }, "engines": { - "node": ">= 10.0.0" + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "eslint": ">=6.0.0" } }, - "node_modules/vite-plugin-pwa/node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/vite-plugin-pwa/node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/vue-eslint-parser/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/vue-request": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vue-request/-/vue-request-2.0.4.tgz", + "integrity": "sha512-+Tu5rDy6ItF9UdD21Mmbjiq5Pq6NZSN9juH72hNQTMn1whHh4KZPTKWVLK2YS4nzbuEnPs+82G91AA2Fgd93mg==", + "license": "MIT", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "vue-demi": "latest" }, "engines": { - "node": ">= 8.0.0" + "node": ">=14" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^2.0.0 || >=3.0.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } } }, - "node_modules/vite-plugin-pwa/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true + "node_modules/vue-request/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } }, - "node_modules/vite-plugin-pwa/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "@vue/devtools-api": "^6.6.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" } }, - "node_modules/vite-plugin-pwa/node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, - "node_modules/vite-plugin-pwa/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/vite-plugin-pwa/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" }, - "engines": { - "node": ">= 10.13.0" + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" } }, - "node_modules/vite-plugin-pwa/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" }, - "node_modules/vite-plugin-pwa/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", "dev": true, + "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.8" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } }, - "node_modules/vite-plugin-pwa/node_modules/pretty-bytes": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", - "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "engines": { - "node": "^14.13.1 || >=16.0.0" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/vite-plugin-pwa/node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, - "bin": { - "rollup": "dist/bin/rollup" + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" }, "engines": { - "node": ">=10.0.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-pwa/node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" }, - "peerDependencies": { - "rollup": "^2.0.0" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-pwa/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { - "randombytes": "^2.1.0" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-pwa/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, + "license": "MIT", "dependencies": { - "whatwg-url": "^7.0.0" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/vite-plugin-pwa/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/vite-plugin-pwa/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true + "node_modules/workbox": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/workbox/-/workbox-0.0.0.tgz", + "integrity": "sha512-/I5JIWHK18DDGGoXOZgOkOFLsiMQZlHLnwEzw328ZMU4TA21yFCw11YEnZ1CsOnSazl0DMbFmLJ6q5hpQhP/aQ==", + "license": "MIT", + "dependencies": { + "babel-runtime": "6.x.x" + } }, - "node_modules/vite-plugin-pwa/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "node_modules/workbox-background-sync": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.3.0.tgz", + "integrity": "sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==", "dev": true, + "license": "MIT", "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "idb": "^7.0.1", + "workbox-core": "7.3.0" } }, - "node_modules/vite-plugin-pwa/node_modules/workbox-broadcast-update": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.0.0.tgz", - "integrity": "sha512-oUuh4jzZrLySOo0tC0WoKiSg90bVAcnE98uW7F8GFiSOXnhogfNDGZelPJa+6KpGBO5+Qelv04Hqx2UD+BJqNQ==", + "node_modules/workbox-broadcast-update": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.3.0.tgz", + "integrity": "sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==", "dev": true, + "license": "MIT", "dependencies": { - "workbox-core": "7.0.0" + "workbox-core": "7.3.0" } }, - "node_modules/vite-plugin-pwa/node_modules/workbox-build": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.0.0.tgz", - "integrity": "sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==", + "node_modules/workbox-build": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.3.0.tgz", + "integrity": "sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==", "dev": true, + "license": "MIT", "dependencies": { "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", + "@babel/core": "^7.24.4", "@babel/preset-env": "^7.11.0", "@babel/runtime": "^7.11.2", "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-replace": "^2.4.1", + "@rollup/plugin-terser": "^0.4.3", "@surma/rollup-plugin-off-main-thread": "^2.2.3", "ajv": "^8.6.0", "common-tags": "^1.8.0", @@ -7713,418 +8725,345 @@ "lodash": "^4.17.20", "pretty-bytes": "^5.3.0", "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", "source-map": "^0.8.0-beta.0", "stringify-object": "^3.3.0", "strip-comments": "^2.0.1", "tempy": "^0.6.0", "upath": "^1.2.0", - "workbox-background-sync": "7.0.0", - "workbox-broadcast-update": "7.0.0", - "workbox-cacheable-response": "7.0.0", - "workbox-core": "7.0.0", - "workbox-expiration": "7.0.0", - "workbox-google-analytics": "7.0.0", - "workbox-navigation-preload": "7.0.0", - "workbox-precaching": "7.0.0", - "workbox-range-requests": "7.0.0", - "workbox-recipes": "7.0.0", - "workbox-routing": "7.0.0", - "workbox-strategies": "7.0.0", - "workbox-streams": "7.0.0", - "workbox-sw": "7.0.0", - "workbox-window": "7.0.0" + "workbox-background-sync": "7.3.0", + "workbox-broadcast-update": "7.3.0", + "workbox-cacheable-response": "7.3.0", + "workbox-core": "7.3.0", + "workbox-expiration": "7.3.0", + "workbox-google-analytics": "7.3.0", + "workbox-navigation-preload": "7.3.0", + "workbox-precaching": "7.3.0", + "workbox-range-requests": "7.3.0", + "workbox-recipes": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0", + "workbox-streams": "7.3.0", + "workbox-sw": "7.3.0", + "workbox-window": "7.3.0" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/vite-plugin-pwa/node_modules/workbox-build/node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", "dev": true, + "license": "MIT", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, "engines": { - "node": ">=6" + "node": ">=10" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-cacheable-response": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.0.0.tgz", - "integrity": "sha512-0lrtyGHn/LH8kKAJVOQfSu3/80WDc9Ma8ng0p2i/5HuUndGttH+mGMSvOskjOdFImLs2XZIimErp7tSOPmu/6g==", - "dev": true, - "dependencies": { - "workbox-core": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-expiration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.0.0.tgz", - "integrity": "sha512-MLK+fogW+pC3IWU9SFE+FRStvDVutwJMR5if1g7oBJx3qwmO69BNoJQVaMXq41R0gg3MzxVfwOGKx3i9P6sOLQ==", - "dev": true, - "dependencies": { - "idb": "^7.0.1", - "workbox-core": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-google-analytics": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.0.0.tgz", - "integrity": "sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==", - "dev": true, - "dependencies": { - "workbox-background-sync": "7.0.0", - "workbox-core": "7.0.0", - "workbox-routing": "7.0.0", - "workbox-strategies": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-navigation-preload": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.0.0.tgz", - "integrity": "sha512-juWCSrxo/fiMz3RsvDspeSLGmbgC0U9tKqcUPZBCf35s64wlaLXyn2KdHHXVQrb2cqF7I0Hc9siQalainmnXJA==", - "dev": true, - "dependencies": { - "workbox-core": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-range-requests": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.0.0.tgz", - "integrity": "sha512-SxAzoVl9j/zRU9OT5+IQs7pbJBOUOlriB8Gn9YMvi38BNZRbM+RvkujHMo8FOe9IWrqqwYgDFBfv6sk76I1yaQ==", - "dev": true, - "dependencies": { - "workbox-core": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-recipes": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.0.0.tgz", - "integrity": "sha512-DntcK9wuG3rYQOONWC0PejxYYIDHyWWZB/ueTbOUDQgefaeIj1kJ7pdP3LZV2lfrj8XXXBWt+JDRSw1lLLOnww==", - "dev": true, - "dependencies": { - "workbox-cacheable-response": "7.0.0", - "workbox-core": "7.0.0", - "workbox-expiration": "7.0.0", - "workbox-precaching": "7.0.0", - "workbox-routing": "7.0.0", - "workbox-strategies": "7.0.0" + "peerDependencies": { + "ajv": ">=8" } }, - "node_modules/vite-plugin-pwa/node_modules/workbox-streams": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.0.0.tgz", - "integrity": "sha512-moVsh+5to//l6IERWceYKGiftc+prNnqOp2sgALJJFbnNVpTXzKISlTIsrWY+ogMqt+x1oMazIdHj25kBSq/HQ==", + "node_modules/workbox-build/node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", "dev": true, + "license": "MIT", "dependencies": { - "workbox-core": "7.0.0", - "workbox-routing": "7.0.0" - } - }, - "node_modules/vite-plugin-pwa/node_modules/workbox-sw": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.0.0.tgz", - "integrity": "sha512-SWfEouQfjRiZ7GNABzHUKUyj8pCoe+RwjfOIajcx6J5mtgKkN+t8UToHnpaJL5UVVOf5YhJh+OHhbVNIHe+LVA==", - "dev": true - }, - "node_modules/vue": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz", - "integrity": "sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==", - "dependencies": { - "@vue/compiler-dom": "3.3.11", - "@vue/compiler-sfc": "3.3.11", - "@vue/runtime-dom": "3.3.11", - "@vue/server-renderer": "3.3.11", - "@vue/shared": "3.3.11" + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" }, "peerDependencies": { - "typescript": "*" + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" }, "peerDependenciesMeta": { - "typescript": { + "@types/babel__core": { "optional": true } } }, - "node_modules/vue-cookies": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/vue-cookies/-/vue-cookies-1.8.3.tgz", - "integrity": "sha512-VBRsyRMVdahBgFfh389TMHPmDdr4URDJNMk4FKSCfuNITs7+jitBDhwyL4RJd3WUsfOYNNjPAkfbehyH9AFuoA==" + "node_modules/workbox-build/node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } }, - "node_modules/vue-eslint-parser": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz", - "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==", + "node_modules/workbox-build/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "lodash": "^4.17.21", - "semver": "^7.3.6" + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" }, "engines": { - "node": "^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" + "node": ">= 8.0.0" }, "peerDependencies": { - "eslint": ">=6.0.0" + "rollup": "^1.20.0||^2.0.0" } }, - "node_modules/vue-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/workbox-build/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true, + "license": "MIT" + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/vue-eslint-parser/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/workbox-build/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", "dev": true, - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, - "node_modules/vue-request": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/vue-request/-/vue-request-2.0.4.tgz", - "integrity": "sha512-+Tu5rDy6ItF9UdD21Mmbjiq5Pq6NZSN9juH72hNQTMn1whHh4KZPTKWVLK2YS4nzbuEnPs+82G91AA2Fgd93mg==", + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-build/node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "license": "MIT", "dependencies": { - "vue-demi": "latest" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^2.0.0 || >=3.0.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "sourcemap-codec": "^1.4.8" } }, - "node_modules/vue-request/node_modules/vue-demi": { - "version": "0.14.6", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", - "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", - "hasInstallScript": true, - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vue-router": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", - "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", - "dependencies": { - "@vue/devtools-api": "^6.5.0" + "node_modules/workbox-build/node_modules/rollup": { + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" }, - "funding": { - "url": "https://github.com/sponsors/posva" + "engines": { + "node": ">=10.0.0" }, - "peerDependencies": { - "vue": "^3.2.0" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/vue-template-compiler": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz", - "integrity": "sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==", + "node_modules/workbox-cacheable-response": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.3.0.tgz", + "integrity": "sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==", "dev": true, + "license": "MIT", "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" + "workbox-core": "7.3.0" } }, - "node_modules/vue-tsc": { - "version": "1.8.25", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.25.tgz", - "integrity": "sha512-lHsRhDc/Y7LINvYhZ3pv4elflFADoEOo67vfClAfF2heVHpHmVquLSjojgCSIwzA4F0Pc4vowT/psXCYcfk+iQ==", - "dev": true, - "dependencies": { - "@volar/typescript": "~1.11.1", - "@vue/language-core": "1.8.25", - "semver": "^7.5.4" - }, - "bin": { - "vue-tsc": "bin/vue-tsc.js" - }, - "peerDependencies": { - "typescript": "*" - } + "node_modules/workbox-core": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.3.0.tgz", + "integrity": "sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==", + "license": "MIT" }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/workbox-expiration": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.3.0.tgz", + "integrity": "sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==", "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" + "idb": "^7.0.1", + "workbox-core": "7.3.0" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "node_modules/workbox-google-analytics": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.3.0.tgz", + "integrity": "sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "workbox-background-sync": "7.3.0", + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" } }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "node_modules/workbox-navigation-preload": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.3.0.tgz", + "integrity": "sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "workbox-core": "7.3.0" } }, - "node_modules/workbox": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/workbox/-/workbox-0.0.0.tgz", - "integrity": "sha512-/I5JIWHK18DDGGoXOZgOkOFLsiMQZlHLnwEzw328ZMU4TA21yFCw11YEnZ1CsOnSazl0DMbFmLJ6q5hpQhP/aQ==", + "node_modules/workbox-precaching": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.3.0.tgz", + "integrity": "sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==", + "license": "MIT", "dependencies": { - "babel-runtime": "6.x.x" + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" } }, - "node_modules/workbox-background-sync": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.0.0.tgz", - "integrity": "sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==", + "node_modules/workbox-range-requests": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.3.0.tgz", + "integrity": "sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==", "dev": true, + "license": "MIT", "dependencies": { - "idb": "^7.0.1", - "workbox-core": "7.0.0" + "workbox-core": "7.3.0" } }, - "node_modules/workbox-core": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.0.0.tgz", - "integrity": "sha512-81JkAAZtfVP8darBpfRTovHg8DGAVrKFgHpOArZbdFd78VqHr5Iw65f2guwjE2NlCFbPFDoez3D3/6ZvhI/rwQ==" - }, - "node_modules/workbox-precaching": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.0.0.tgz", - "integrity": "sha512-EC0vol623LJqTJo1mkhD9DZmMP604vHqni3EohhQVwhJlTgyKyOkMrZNy5/QHfOby+39xqC01gv4LjOm4HSfnA==", + "node_modules/workbox-recipes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.3.0.tgz", + "integrity": "sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==", + "dev": true, + "license": "MIT", "dependencies": { - "workbox-core": "7.0.0", - "workbox-routing": "7.0.0", - "workbox-strategies": "7.0.0" + "workbox-cacheable-response": "7.3.0", + "workbox-core": "7.3.0", + "workbox-expiration": "7.3.0", + "workbox-precaching": "7.3.0", + "workbox-routing": "7.3.0", + "workbox-strategies": "7.3.0" } }, "node_modules/workbox-routing": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.0.0.tgz", - "integrity": "sha512-8YxLr3xvqidnbVeGyRGkaV4YdlKkn5qZ1LfEePW3dq+ydE73hUUJJuLmGEykW3fMX8x8mNdL0XrWgotcuZjIvA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.3.0.tgz", + "integrity": "sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==", + "license": "MIT", "dependencies": { - "workbox-core": "7.0.0" + "workbox-core": "7.3.0" } }, "node_modules/workbox-strategies": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.0.0.tgz", - "integrity": "sha512-dg3qJU7tR/Gcd/XXOOo7x9QoCI9nk74JopaJaYAQ+ugLi57gPsXycVdBnYbayVj34m6Y8ppPwIuecrzkpBVwbA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.3.0.tgz", + "integrity": "sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==", + "license": "MIT", "dependencies": { - "workbox-core": "7.0.0" + "workbox-core": "7.3.0" } }, + "node_modules/workbox-streams": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.3.0.tgz", + "integrity": "sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.3.0", + "workbox-routing": "7.3.0" + } + }, + "node_modules/workbox-sw": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.3.0.tgz", + "integrity": "sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==", + "dev": true, + "license": "MIT" + }, "node_modules/workbox-window": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.0.0.tgz", - "integrity": "sha512-j7P/bsAWE/a7sxqTzXo3P2ALb1reTfZdvVp6OJ/uLr/C2kZAMvjeWGm8V4htQhor7DOvYg0sSbFN2+flT5U0qA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.3.0.tgz", + "integrity": "sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==", "dev": true, + "license": "MIT", "dependencies": { "@types/trusted-types": "^2.0.2", - "workbox-core": "7.0.0" + "workbox-core": "7.3.0" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12" } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/dashboard/package.json b/dashboard/package.json index 32a742c2..71e65894 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -13,13 +13,14 @@ "type-check": "vue-tsc --noEmit" }, "dependencies": { + "@primeuix/themes": "^1.0.1", "@types/pako": "^2.0.3", "axios": "^1.6.2", "chart.js": "^4.4.1", "js-sha256": "^0.11.0", "pako": "^2.1.0", "primeicons": "^6.0.1", - "primevue": "^3.49.0", + "primevue": "^4.3.3", "register-service-worker": "^1.7.2", "vue": "^3.2.47", "vue-cookies": "^1.8.3", diff --git a/dashboard/src/App.vue b/dashboard/src/App.vue index f7961309..d4d35f6f 100644 --- a/dashboard/src/App.vue +++ b/dashboard/src/App.vue @@ -3,7 +3,9 @@ import { computed, inject, nextTick, type Ref } from 'vue' import { RouterLink, RouterView } from 'vue-router' import axios from 'axios' import Button from 'primevue/button' -import Dropdown from 'primevue/dropdown' +import ConfirmDialog from 'primevue/confirmdialog' +import ScrollTop from 'primevue/scrolltop' +import Select from 'primevue/select' import Toast from 'primevue/toast' import { useToast } from 'primevue/usetoast' import { type Lang, avaliableLangs, getLang, setLang, tr, langNameMap } from '@/lang' @@ -54,7 +56,7 @@ const selectedLang = computed({
- {{ langNameMap[slotProps.option.toString()] }} - +
- - + + @@ -102,6 +120,14 @@ const selectedLang = computed({ AGPL-3.0 License

+ + + + + @@ -115,7 +141,7 @@ const selectedLang = computed({ height: 4rem; padding-left: 2rem; padding-right: 1rem; - background-color: color-mix(in srgb, var(--primary-50) 30%, transparent); + background-color: color-mix(in srgb, var(--p-primary-50) 30%, transparent); box-shadow: #0008 0 0 1rem -0.5rem; backdrop-filter: blur(0.4rem); } @@ -135,7 +161,7 @@ const selectedLang = computed({ } .nav-login { - color: var(--primary-color); + color: var(--p-primary-color); text-decoration: none; } @@ -193,9 +219,9 @@ const selectedLang = computed({ #footer { padding: 2rem; - font-family: var(--font-family); - color: var(--primary-color-text); - background-color: var(--primary-color); + font-family: var(--p-font-family); + color: var(--p-primary-color-text); + background-color: var(--p-primary-color); } #footer > * { @@ -203,20 +229,20 @@ const selectedLang = computed({ } #footer a { - color: var(--primary-100); + color: var(--p-primary-100); text-decoration: none; transition: 0.4s color, 0.2s background-color ease; } #footer a:hover { - color: var(--highlight-text-color); - background-color: var(--highlight-bg); + color: var(--p-highlight-color); + background-color: var(--p-highlight-background); text-decoration: underline; } @media (prefers-color-scheme: dark) { #header { - background-color: color-mix(in srgb, var(--primary-50) 10%, transparent); + background-color: color-mix(in srgb, var(--p-primary-50) 10%, transparent); } } diff --git a/dashboard/src/api/v0.ts b/dashboard/src/api/v0.ts index bcbf3d4a..19e0f65f 100644 --- a/dashboard/src/api/v0.ts +++ b/dashboard/src/api/v0.ts @@ -55,6 +55,23 @@ export interface TokenRes { token: string } +export enum UserPermission { + BASIC = 1 << 0, + SUBSCRIBE = 1 << 1, + LOG = 1 << 2, + DEBUG = 1 << 3, + FULL_CONFIG = 1 << 4, + CLUSTER = 1 << 5, + STORAGE = 1 << 6, + BYPASS_LIMIT = 1 << 7, + ROOT = 1 << 31, +} + +export interface UserInfoRes { + name: string + permissions: number +} + export interface PingRes { version: string time: string @@ -94,6 +111,15 @@ async function requestToken( return res.data.token } +export async function getUserInfo(token: string): Promise { + const res = await axios.get(`/api/v0/user_info`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + return res.data +} + export async function ping(token?: string): Promise { const res = await axios.get(`/api/v0/ping`, { headers: { @@ -113,7 +139,7 @@ export async function getStatus(token?: string | null): Promise { } export async function getStat(name: string, token?: string | null): Promise { - const res = await axios.get(`/api/v0/stat/${name}`, { + const res = await axios.get(`/api/v0/stat/storage/${name}`, { headers: { Authorization: token ? `Bearer ${token}` : undefined, }, @@ -447,3 +473,210 @@ export async function getLogFileURL( u.searchParams.set('_t', tk) return u.toString() } + +export interface Config { + public_host: string + public_port: number + host: string + port: number + use_cert: boolean + allow_unsecure_connection: boolean + trusted_x_forwarded_for: boolean + + only_gc_when_start: boolean + sync_interval: number + download_max_conn: number + max_reconnect_count: number + + log_slots: number + no_access_log: boolean + access_log_slots: number + + clusters: { [name: string]: ClusterOptions } + storages: StorageOption[] + certificates: CertificateConfig[] + tunneler: TunnelConfig + cache: CacheConfig + serve_limit: ServeLimitConfig + api_rate_limit: APIRateLimitConfig + notification: NotificationConfig + dashboard: DashboardConfig + github_api: GithubAPIConfig + database: DatabaseConfig + hijack: HijackConfig + webdav_users: { [name: string]: WebDavUser } + advanced: AdvancedConfig +} + +export interface ClusterOptions { + id: string + secret: string + byoc: boolean + public_hosts: string[] + server: string + skip_signature_check: boolean + storages: string[] +} + +interface LocalStorageOption { + type: 'local' + cache_path: string + compressor: string +} + +interface MountStorageOption { + type: 'mount' + path: string + redirect_base: string + pre_gen_measures: boolean +} + +type WebDavStorageOption = { + type: 'webdav' + max_conn: number + max_upload_rate: number + max_download_rate: number + pre_gen_measures: boolean + follow_redirect: boolean + redirect_link_cache: number + alias?: string +} & WebDavUser + +export interface WebDavUser { + endpoint?: string + username?: string + password?: string +} + +export type StorageOption = { + id: string + weight: number +} & (LocalStorageOption | MountStorageOption | WebDavStorageOption) + +export interface CertificateConfig { + cert: string + key: string +} + +export interface TunnelConfig { + enable: boolean + tunnel_program: string + output_regex: string +} + +export type CacheConfig = + | { + type: 'no-cache' | 'memory' + } + | { + type: 'redis' + network: string + addr: string + client_name: string + username: string + password: string + } + +export interface ServeLimitConfig { + enable: boolean + max_conn: number + upload_rate: number +} + +export interface RateLimit { + per_minute: number + per_hour: number +} + +export interface APIRateLimitConfig { + anonymous: RateLimit + logged: RateLimit +} + +export interface NotificationConfig { + enable_email: boolean + email_smtp: string + email_smtp_encryption: string + email_sender: string + email_sender_password: string + enable_webhook: boolean +} + +export interface DashboardConfig { + enable: boolean + username: string + password: string + pwa_name: string + pwa_short_name: string + pwa_description: string + notification_subject: string +} + +export interface GithubAPIConfig { + update_check_interval: number + authorization: string +} + +export interface DatabaseConfig { + driver: string + data_source_name: string +} + +export interface UserItem { + username: string + password: string +} + +export interface HijackConfig { + enable: boolean + enable_local_cache: boolean + local_cache_path: string + require_auth: boolean + auth_users: UserItem[] +} + +export interface AdvancedConfig { + // Unsupported +} + +export async function getConfig(token: string): Promise { + const res = await axios.get(`/api/v0/config`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + return res.data +} + +export async function putConfig(token: string, config: Config): Promise { + await axios.put(`/api/v0/config`, JSON.stringify(config), { + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + }) +} + +export enum ClusterStatus { + DISCONNECTED = 0, + CONNECTING = 1, + DISABLED = 2, + ENABLING = 3, + ENABLED = 4, +} + +export interface ClusterStatusRes { + [name: string]: { + status: ClusterStatus + sync: boolean + } +} + +export async function getClusterStatus(token: string): Promise { + const res = await axios.get(`/api/v0/cluster/status`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + return res.data +} diff --git a/dashboard/src/assets/base.css b/dashboard/src/assets/base.css index 59d8317b..0a2423a3 100644 --- a/dashboard/src/assets/base.css +++ b/dashboard/src/assets/base.css @@ -7,6 +7,8 @@ :root { font-size: 16px; --dialog-width: 60rem; + --table-row-bg-a: var(--p-surface-100); + --table-row-bg-b: var(--p-surface-200); } body { @@ -26,3 +28,10 @@ body { --dialog-width: 100vw; } } + +@media (prefers-color-scheme: dark) { + :root { + --table-row-bg-a: var(--p-surface-800); + --table-row-bg-b: var(--p-surface-700); + } +} diff --git a/dashboard/src/assets/lang/en-US.json b/dashboard/src/assets/lang/en-US.json index 8cf31bd7..e3090e41 100644 --- a/dashboard/src/assets/lang/en-US.json +++ b/dashboard/src/assets/lang/en-US.json @@ -59,11 +59,92 @@ "scopes": "Scopes", "auth-header": "Auth Header", "configure": "Configure webhook" + }, + + "configure": "Configure", + "configures": { + "hostport": "Host and Port", + "sync": "Synchronize", + "logs": "Logs", + "clusters": "Clusters", + "storages": "Storages", + "tunneler": "Tunneler", + "cache": "Cache", + "serve_limit": "Serve Limit", + + "item": { + "public_host": "Public Host", + "public_port": "Public Port", + "host": "Host", + "port": "Port", + "use_cert": "Use Certification", + "trusted_x_forwarded_for": "Trust X-Forwarded-For", + + "only_gc_when_start": "Only cleanup when start", + "sync_interval": "Synchronize Interval", + "download_max_conn": "Max Download Connection", + "max_reconnect_count": "Max Reconnect Count", + + "log_slots": "Log Slots", + "enable_access_log": "Enable Access Log", + "access_log_slots": "Access Log Slots", + + "cluster": { + "id": "Cluster ID", + "secret": "Cluster Secret", + "byoc": "Custom Certificate", + "public_hosts": "Public Hostnames", + "server": "Central Server", + "skip_signature_check": "Skip Signature Check", + "storages": "Using Storages" + }, + + "storage": { + "type": "Storage Type", + "weight": "Weight", + "cache_path": "Path", + "path": "Path", + "redirect_base": "Redirect Base URL", + "pre_gen_measures": "Pre-generate mesaures", + "max_conn": "Max Connection", + "max_upload_rate": "Max Upload Rate", + "max_download_rate": "Max Download Rate", + "follow_redirect": "Follow Redirect", + "redirect_link_cache": "Redirect Link Cache Duration" + }, + + "tunneler": { + "enable": "Enable Tunneler", + "tunnel_program": "Tunnel Program", + "output_regex": "Output Regex" + }, + + "cache": { + "type": "Cache Type" + }, + + "serve_limit": { + "enable": "Enable Serve Limit", + "max_conn": "Max Connection", + "upload_rate": "Max Upload Rate" + } + }, + + "confirm": { + "remove": "Remove Confirmation", + "discard": "Discard Confirmation" + } } }, "button": { "enable": "Enable", - "disable": "Disable" + "disable": "Disable", + "save": "Save", + "saved": "Saved", + "refresh": "Refresh", + "remove": "Remove", + "cancel": "Cancel", + "discard": "Discard" }, "message": { "server": { @@ -98,6 +179,12 @@ "filelist": { "cant.fetch": "Cannot fetch filelist" } + }, + "configures": { + "confirm": { + "remove": "Are you sure you want to remove cluster {0}?", + "discard": "Are you sure to discard configure changes?" + } } }, "badge": { diff --git a/dashboard/src/assets/lang/zh-CN.json b/dashboard/src/assets/lang/zh-CN.json index b9afb45d..7cefcac3 100644 --- a/dashboard/src/assets/lang/zh-CN.json +++ b/dashboard/src/assets/lang/zh-CN.json @@ -59,11 +59,92 @@ "scopes": "域", "auth-header": "授权标头", "configure": "配置网络钩子" + }, + + "configure": "配置", + "configures": { + "hostport": "主机&端口", + "sync": "同步", + "logs": "日志", + "clusters": "节点", + "storages": "存储", + "tunneler": "打洞", + "cache": "缓存", + "serve_limit": "服务限制", + + "item": { + "public_host": "公网主机名", + "public_port": "公网端口", + "host": "主机名", + "port": "端口", + "use_cert": "使用证书", + "trusted_x_forwarded_for": "信任 X-Forwarded-For", + + "only_gc_when_start": "仅在启动时清理", + "sync_interval": "同步间隔", + "download_max_conn": "最大下载连接数", + "max_reconnect_count": "最大重试次数", + + "log_slots": "日志槽位", + "enable_access_log": "启用访问日志", + "access_log_slots": "访问日志槽位", + + "cluster": { + "id": "节点ID", + "secret": "节点密钥", + "byoc": "自定义证书", + "public_hosts": "公开主机名", + "server": "主控服务器", + "skip_signature_check": "跳过签名检查", + "storages": "使用存储" + }, + + "storage": { + "type": "存储类型", + "weight": "权重", + "cache_path": "路径", + "path": "路径", + "redirect_base": "重定向基础URL", + "pre_gen_measures": "预生成测速文件", + "max_conn": "最大连接数", + "max_upload_rate": "最大上传速率", + "max_download_rate": "最大下载速率", + "follow_redirect": "跟随重定向", + "redirect_link_cache": "重定向链接缓存时间" + }, + + "tunneler": { + "enable": "启用打洞", + "tunnel_program": "打洞程序", + "output_regex": "输出正则" + }, + + "cache": { + "type": "缓存类型" + }, + + "serve_limit": { + "enable": "启用服务限制", + "max_conn": "最大连接数", + "upload_rate": "最大上传速率" + } + }, + + "confirm": { + "remove": "移除确认", + "discard": "撤销更改?" + } } }, "button": { "enable": "启用", - "disable": "禁用" + "disable": "禁用", + "save": "保存", + "saved": "已保存", + "refresh": "刷新", + "remove": "移除", + "cancel": "取消", + "discard": "撤销" }, "message": { "server": { @@ -98,6 +179,12 @@ "filelist": { "cant.fetch": "无法获取文件列表" } + }, + "configures": { + "confirm": { + "remove": "确认删除节点 {0} 吗?", + "discard": "确认放弃更改吗?" + } } }, "badge": { diff --git a/dashboard/src/assets/main.css b/dashboard/src/assets/main.css index b4e434ac..23d9ac83 100644 --- a/dashboard/src/assets/main.css +++ b/dashboard/src/assets/main.css @@ -25,11 +25,11 @@ a.pi { } @media (max-width: 60rem) { - .p-dropdown .p-dropdown-label.p-inputtext { + .p-select .p-select-label.p-inputtext { padding-left: 0.6rem; } - .p-dropdown .p-dropdown-trigger { + .p-select .p-select-dropdown { width: 2.1rem; } } diff --git a/dashboard/src/assets/theme.css b/dashboard/src/assets/theme.css deleted file mode 100644 index 250da4c1..00000000 --- a/dashboard/src/assets/theme.css +++ /dev/null @@ -1,2 +0,0 @@ -@import 'primevue/resources/themes/lara-light-green/theme.css' not (prefers-color-scheme: dark); -@import 'primevue/resources/themes/lara-dark-green/theme.css' (prefers-color-scheme: dark); diff --git a/dashboard/src/components/FileListCard.vue b/dashboard/src/components/FileListCard.vue index f097dc79..d06c8f09 100644 --- a/dashboard/src/components/FileListCard.vue +++ b/dashboard/src/components/FileListCard.vue @@ -16,7 +16,7 @@ defineEmits<{