diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index b91f0619..00000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -*.go linguist-detectable=true -*.vue linguist-detectable=false diff --git a/.gitignore b/.gitignore index ab55219a..7c72020c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules config.toml -artemis.bin -uploads/* \ No newline at end of file +libredesk.bin +uploads/* +.env \ No newline at end of file diff --git a/Makefile b/Makefile index 09e02f3f..2352e1d5 100644 --- a/Makefile +++ b/Makefile @@ -1,49 +1,72 @@ # Build variables LAST_COMMIT := $(shell git rev-parse --short HEAD) LAST_COMMIT_DATE := $(shell git show -s --format=%ci ${LAST_COMMIT}) -VERSION := $(shell git describe --tags) +VERSION := $(shell git describe --tags) BUILDSTR := ${VERSION} (Commit: ${LAST_COMMIT_DATE} (${LAST_COMMIT}), Build: $(shell date +"%Y-%m-%d %H:%M:%S %z")) # Binary names and paths -BIN_ARTEMIS := artemis.bin +BIN_LIBREDESK := libredesk.bin FRONTEND_DIR := frontend FRONTEND_DIST := ${FRONTEND_DIR}/dist STATIC := ${FRONTEND_DIST} i18n schema.sql static GOPATH ?= $(HOME)/go STUFFBIN ?= $(GOPATH)/bin/stuffbin -# Default target -.DEFAULT_GOAL := build +# The default target to run when `make` is executed. +.DEFAULT_GOAL := build +# Install stuffbin if it doesn't exist. $(STUFFBIN): @echo "→ Installing stuffbin..." @go install github.com/knadh/stuffbin/... +# Install dependencies for both backend and frontend. .PHONY: install-deps install-deps: $(STUFFBIN) @echo "→ Installing frontend dependencies..." - @cd ${FRONTEND_DIR} && npm install + @cd ${FRONTEND_DIR} && pnpm install -# Frontend builds +# Build the frontend for production. .PHONY: frontend-build frontend-build: @echo "→ Building frontend for production..." - @cd ${FRONTEND_DIR} && bun run build + @cd ${FRONTEND_DIR} && pnpm build -# Backend builds +# Run the Go backend server in development mode. +.PHONY: run-backend +run-backend: + @echo "→ Running backend..." + @go run cmd/*.go + +# Run the JS frontend server in development mode. +.PHONY: run-frontend +run-frontend: + @echo "→ Installing frontend dependencies (if not already installed)..." + @cd ${FRONTEND_DIR} && pnpm install + @echo "→ Running frontend..." + @export VUE_APP_VERSION="${VERSION}" && cd ${FRONTEND_DIR} && pnpm dev + +# Build the backend binary. .PHONY: backend-build backend-build: $(STUFFBIN) @echo "→ Building backend..." - @CGO_ENABLED=0 go build \ + @CGO_ENABLED=0 go build -a\ -ldflags="-X 'main.buildString=${BUILDSTR}' -X 'main.buildDate=${LAST_COMMIT_DATE}' -s -w" \ - -o ${BIN_ARTEMIS} cmd/*.go + -o ${BIN_LIBREDESK} cmd/*.go -# Main build targets +# Main build target: builds both frontend and backend, then stuffs static assets into the binary. .PHONY: build build: frontend-build backend-build stuff @echo "→ Build successful. Current version: $(VERSION)" +# Stuff static assets into the binary using stuffbin. .PHONY: stuff stuff: $(STUFFBIN) @echo "→ Stuffing static assets into binary..." - @$(STUFFBIN) -a stuff -in ${BIN_ARTEMIS} -out ${BIN_ARTEMIS} ${STATIC} + @$(STUFFBIN) -a stuff -in ${BIN_LIBREDESK} -out ${BIN_LIBREDESK} ${STATIC} + +# Build the application in demo mode. +.PHONY: demo-build +demo-build: + @echo "→ Building in demo mode..." + @export VITE_DEMO_BUILD="true" && $(MAKE) build \ No newline at end of file diff --git a/README.md b/README.md index 8637dd7e..95860a93 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,39 @@ +# Libredesk -### I am pushing code on MVP branch, will be merging mvp into main soon. +Open-source, self-hosted customer support desk. Single binary app. + +> This project is currently in **alpha**. Features and APIs may change and are not yet fully tested. + +## Developer Setup + +#### Prerequisites + +- **go** +- **pnpm** +- **PostgreSQL >= 13** +- **Redis** + +1. **Clone the repository**: + + ```bash + git clone https://github.com/abhinavxd/libredesk.git + cd libredesk + ``` + +2. **Configure the Application**: + + - Copy the sample configuration file `config.toml.sample` to `config.toml`: + + ```bash + cp config.toml.sample config.toml + ``` + - Edit the `config.toml` file to configure your database and Redis connection settings. + +3. **Run in Development Mode**: + + - Backend: `make run-backend` + - Frontend: `make run-frontend` + +--- + +Visit [libredesk.io](https://libredesk.io) for more info. diff --git a/cmd/ai.go b/cmd/ai.go new file mode 100644 index 00000000..ca3b3376 --- /dev/null +++ b/cmd/ai.go @@ -0,0 +1,29 @@ +package main + +import "github.com/zerodha/fastglue" + +// handleAICompletion handles AI completion requests +func handleAICompletion(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + promptKey = string(r.RequestCtx.PostArgs().Peek("prompt_key")) + content = string(r.RequestCtx.PostArgs().Peek("content")) + ) + resp, err := app.ai.Completion(promptKey, content) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(resp) +} + +// handleGetAIPrompts returns AI prompts +func handleGetAIPrompts(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + resp, err := app.ai.GetPrompts() + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(resp) +} diff --git a/cmd/auth.go b/cmd/auth.go index adfe2780..4657f06a 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -3,28 +3,45 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/stringutil" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +var ( + oidcStateSessKey = "oidc_state" +) + // handleOIDCLogin redirects to the OIDC provider for login. func handleOIDCLogin(r *fastglue.Request) error { var ( app = r.Context.(*App) providerID, err = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) - csrfToken = string(r.RequestCtx.Request.Header.Cookie("csrf_token")) ) if err != nil { app.lo.Error("error parsing provider id", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error parsing provider id.", nil, envelope.GeneralError) } - authURL, err := app.auth.LoginURL(providerID, csrfToken) + + // Set a state and save it in the session, to prevent CSRF attacks. + state, err := stringutil.RandomAlphanumeric(32) + if err != nil { + app.lo.Error("error generating state", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error generating state.", nil, envelope.GeneralError) + } + if err = app.auth.SetSessionValues(r, map[string]interface{}{ + oidcStateSessKey: state, + }); err != nil { + app.lo.Error("error saving state in session", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error saving state in session.", nil, envelope.GeneralError) + } + + authURL, err := app.auth.LoginURL(providerID, state) if err != nil { return sendErrorEnvelope(r, err) } - return r.Redirect(authURL, fasthttp.StatusFound, nil, "") } @@ -34,30 +51,43 @@ func handleOIDCCallback(r *fastglue.Request) error { app = r.Context.(*App) code = string(r.RequestCtx.QueryArgs().Peek("code")) state = string(r.RequestCtx.QueryArgs().Peek("state")) - providerID, err = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("id"))) - csrfToken = string(r.RequestCtx.Request.Header.Cookie("csrf_token")) + providerID, err = strconv.Atoi(string(r.RequestCtx.UserValue("id").(string))) ) if err != nil { app.lo.Error("error parsing provider id", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error parsing provider id.", nil, envelope.GeneralError) } - _, claims, err := app.auth.ExchangeOIDCToken(r.RequestCtx, providerID, code, csrfToken) + // Compare the state from the session with the state from the query. + sessionState, err := app.auth.GetSessionValue(r, oidcStateSessKey) + if err != nil { + app.lo.Error("error getting state from session", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error getting state from session.", nil, envelope.GeneralError) + } + if state != sessionState { + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "Invalid state.", nil, envelope.GeneralError) + } + + _, claims, err := app.auth.ExchangeOIDCToken(r.RequestCtx, providerID, code) if err != nil { app.lo.Error("error exchanging oidc token", "error", err) - return err + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error exchanging OIDC token.", nil, envelope.GeneralError) } - // Get user by e-mail received. + // Lookup the user by email and set the session. user, err := app.user.GetByEmail(claims.Email) if err != nil { - return err + return sendErrorEnvelope(r, err) } - // Set the session. - if err := app.auth.SaveSession(user, r); err != nil { - return err + if err := app.auth.SaveSession(amodels.User{ + ID: user.ID, + Email: user.Email.String, + FirstName: user.FirstName, + LastName: user.LastName, + }, r); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error saving session.", nil, envelope.GeneralError) } - return r.Redirect(state, fasthttp.StatusFound, nil, "") + return r.Redirect("/", fasthttp.StatusFound, nil, "") } diff --git a/cmd/automation.go b/cmd/automation.go index 3f2c0981..3865ad31 100644 --- a/cmd/automation.go +++ b/cmd/automation.go @@ -3,12 +3,13 @@ package main import ( "strconv" - amodels "github.com/abhinavxd/artemis/internal/automation/models" - "github.com/abhinavxd/artemis/internal/envelope" + amodels "github.com/abhinavxd/libredesk/internal/automation/models" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +// handleGetAutomationRules gets all automation rules func handleGetAutomationRules(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -21,6 +22,7 @@ func handleGetAutomationRules(r *fastglue.Request) error { return r.SendEnvelope(out) } +// handleGetAutomationRuleByID gets an automation rule by ID func handleGetAutomationRule(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -33,6 +35,7 @@ func handleGetAutomationRule(r *fastglue.Request) error { return r.SendEnvelope(out) } +// handleToggleAutomationRule toggles an automation rule func handleToggleAutomationRule(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -41,9 +44,10 @@ func handleToggleAutomationRule(r *fastglue.Request) error { if err := app.automation.ToggleRule(id); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Rule toggled successfully") } +// handleUpdateAutomationRule updates an automation rule func handleUpdateAutomationRule(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -59,13 +63,13 @@ func handleUpdateAutomationRule(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", nil, envelope.InputError) } - err = app.automation.UpdateRule(id, rule) - if err != nil { + if err = app.automation.UpdateRule(id, rule);err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Rule updated successfully") } +// handleCreateAutomationRule creates a new automation rule func handleCreateAutomationRule(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -74,13 +78,13 @@ func handleCreateAutomationRule(r *fastglue.Request) error { if err := r.Decode(&rule, "json"); err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", nil, envelope.InputError) } - err := app.automation.CreateRule(rule) - if err != nil { + if err := app.automation.CreateRule(rule); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Rule created successfully") } +// handleDeleteAutomationRule deletes an automation rule func handleDeleteAutomationRule(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -96,5 +100,37 @@ func handleDeleteAutomationRule(r *fastglue.Request) error { if err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Rule deleted successfully") +} + +// handleUpdateAutomationRuleWeights updates the weights of the automation rules +func handleUpdateAutomationRuleWeights(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + weights = make(map[int]int) + ) + if err := r.Decode(&weights, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", nil, envelope.InputError) + } + err := app.automation.UpdateRuleWeights(weights) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("Weights updated successfully") +} + +// handleUpdateAutomationRuleExecutionMode updates the execution mode of the automation rules for a given type +func handleUpdateAutomationRuleExecutionMode(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + mode = string(r.RequestCtx.PostArgs().Peek("mode")) + ) + if mode != amodels.ExecutionModeAll && mode != amodels.ExecutionModeFirstMatch { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid execution mode", nil, envelope.InputError) + } + // Only new conversation rules can be updated as they are the only ones that have execution mode. + if err := app.automation.UpdateRuleExecutionMode(amodels.RuleTypeNewConversation, mode); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("Execution mode updated successfully") } diff --git a/cmd/business_hours.go b/cmd/business_hours.go new file mode 100644 index 00000000..3c75a587 --- /dev/null +++ b/cmd/business_hours.go @@ -0,0 +1,107 @@ +package main + +import ( + "strconv" + + businessHours "github.com/abhinavxd/libredesk/internal/business_hours" + models "github.com/abhinavxd/libredesk/internal/business_hours/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/valyala/fasthttp" + "github.com/zerodha/fastglue" +) + +// handleGetBusinessHours returns all business hours. +func handleGetBusinessHours(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + businessHours, err := app.businessHours.GetAll() + if err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, "") + } + return r.SendEnvelope(businessHours) +} + +// handleGetBusinessHour returns the business hour with the given id. +func handleGetBusinessHour(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid business hour `id`.", nil, envelope.InputError) + } + businessHour, err := app.businessHours.Get(id) + if err != nil { + if err == businessHours.ErrBusinessHoursNotFound { + return r.SendErrorEnvelope(fasthttp.StatusNotFound, err.Error(), nil, envelope.NotFoundError) + } + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error fetching business hour", nil, "") + } + return r.SendEnvelope(businessHour) +} + +// handleCreateBusinessHours creates a new business hour. +func handleCreateBusinessHours(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + businessHours = models.BusinessHours{} + ) + if err := r.Decode(&businessHours, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + + if businessHours.Name == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty business hour `Name`", nil, envelope.InputError) + } + + if err := app.businessHours.Create(businessHours.Name, businessHours.Description, businessHours.IsAlwaysOpen, businessHours.Hours, businessHours.Holidays); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} + +// handleDeleteBusinessHour deletes the business hour with the given id. +func handleDeleteBusinessHour(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid business hour `id`.", nil, envelope.InputError) + } + + err = app.businessHours.Delete(id) + if err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} + +// handleUpdateBusinessHours updates the business hour with the given id. +func handleUpdateBusinessHours(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + businessHours = models.BusinessHours{} + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid business hour `id`.", nil, envelope.InputError) + } + + if err := r.Decode(&businessHours, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + + if businessHours.Name == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty business hour `Name`", nil, envelope.InputError) + } + + if err := app.businessHours.Update(id, businessHours.Name, businessHours.Description, businessHours.IsAlwaysOpen, businessHours.Hours, businessHours.Holidays); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} diff --git a/cmd/cannedresp.go b/cmd/cannedresp.go deleted file mode 100644 index 85eb483f..00000000 --- a/cmd/cannedresp.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "strconv" - - cmodels "github.com/abhinavxd/artemis/internal/cannedresp/models" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/valyala/fasthttp" - "github.com/zerodha/fastglue" -) - -func handleGetCannedResponses(r *fastglue.Request) error { - var ( - app = r.Context.(*App) - c []cmodels.CannedResponse - ) - - c, err := app.cannedResp.GetAll() - if err != nil { - return sendErrorEnvelope(r, err) - } - return r.SendEnvelope(c) -} - -func handleCreateCannedResponse(r *fastglue.Request) error { - var ( - app = r.Context.(*App) - cannedResponse = cmodels.CannedResponse{} - ) - - if err := r.Decode(&cannedResponse, "json"); err != nil { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) - } - - if cannedResponse.Title == "" { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty canned response `Title`", nil, envelope.InputError) - } - - if cannedResponse.Content == "" { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty canned response `Content`", nil, envelope.InputError) - } - - err := app.cannedResp.Create(cannedResponse.Title, cannedResponse.Content) - if err != nil { - return sendErrorEnvelope(r, err) - } - - return r.SendEnvelope(cannedResponse) -} - -func handleDeleteCannedResponse(r *fastglue.Request) error { - var ( - app = r.Context.(*App) - ) - - id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) - if err != nil || id == 0 { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, - "Invalid canned response `id`.", nil, envelope.InputError) - } - - if err := app.cannedResp.Delete(id); err != nil { - return sendErrorEnvelope(r, err) - } - - return r.SendEnvelope(true) -} - -func handleUpdateCannedResponse(r *fastglue.Request) error { - var ( - app = r.Context.(*App) - cannedResponse = cmodels.CannedResponse{} - ) - - id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) - if err != nil || id == 0 { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, - "Invalid canned response `id`.", nil, envelope.InputError) - } - - if err := r.Decode(&cannedResponse, "json"); err != nil { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) - } - - if cannedResponse.Title == "" { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty canned response `Title`", nil, envelope.InputError) - } - - if cannedResponse.Content == "" { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty canned response `Content`", nil, envelope.InputError) - } - - if err = app.cannedResp.Update(id, cannedResponse.Title, cannedResponse.Content); err != nil { - return sendErrorEnvelope(r, err) - } - - return r.SendEnvelope(cannedResponse) -} diff --git a/cmd/conversation.go b/cmd/conversation.go index 0bad7702..cf3cca8d 100644 --- a/cmd/conversation.go +++ b/cmd/conversation.go @@ -3,12 +3,16 @@ package main import ( "encoding/json" "strconv" + "time" - "github.com/abhinavxd/artemis/internal/automation/models" - cmodels "github.com/abhinavxd/artemis/internal/conversation/models" - "github.com/abhinavxd/artemis/internal/envelope" - umodels "github.com/abhinavxd/artemis/internal/user/models" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + authzModels "github.com/abhinavxd/libredesk/internal/authz/models" + "github.com/abhinavxd/libredesk/internal/automation/models" + cmodels "github.com/abhinavxd/libredesk/internal/conversation/models" + "github.com/abhinavxd/libredesk/internal/envelope" + umodels "github.com/abhinavxd/libredesk/internal/user/models" "github.com/valyala/fasthttp" + "github.com/volatiletech/null/v9" "github.com/zerodha/fastglue" ) @@ -23,13 +27,24 @@ func handleGetAllConversations(r *fastglue.Request) error { filters = string(r.RequestCtx.QueryArgs().Peek("filters")) total = 0 ) - conversations, pageSize, err := app.conversation.GetAllConversationsList(order, orderBy, filters, page, pageSize) + + conversations, err := app.conversation.GetAllConversationsList(order, orderBy, filters, page, pageSize) if err != nil { return sendErrorEnvelope(r, err) } + if len(conversations) > 0 { total = conversations[0].Total } + + // Set deadlines for SLA if conversation has a policy + for i := range conversations { + if conversations[i].SLAPolicyID.Int != 0 { + setSLADeadlines(app, &conversations[i]) + } + conversations[i].ID = 0 + } + return r.SendEnvelope(envelope.PageResults{ Results: conversations, Total: total, @@ -43,21 +58,30 @@ func handleGetAllConversations(r *fastglue.Request) error { func handleGetAssignedConversations(r *fastglue.Request) error { var ( app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) + user = r.RequestCtx.UserValue("user").(amodels.User) order = string(r.RequestCtx.QueryArgs().Peek("order")) orderBy = string(r.RequestCtx.QueryArgs().Peek("order_by")) + filters = string(r.RequestCtx.QueryArgs().Peek("filters")) page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) - filters = string(r.RequestCtx.QueryArgs().Peek("filters")) total = 0 ) - conversations, pageSize, err := app.conversation.GetAssignedConversationsList(user.ID, order, orderBy, filters, page, pageSize) + conversations, err := app.conversation.GetAssignedConversationsList(user.ID, order, orderBy, filters, page, pageSize) if err != nil { return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, "") } if len(conversations) > 0 { total = conversations[0].Total } + + // Set deadlines for SLA if conversation has a policy + for i := range conversations { + if conversations[i].SLAPolicyID.Int != 0 { + setSLADeadlines(app, &conversations[i]) + } + conversations[i].ID = 0 + } + return r.SendEnvelope(envelope.PageResults{ Results: conversations, Total: total, @@ -71,21 +95,30 @@ func handleGetAssignedConversations(r *fastglue.Request) error { func handleGetUnassignedConversations(r *fastglue.Request) error { var ( app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) order = string(r.RequestCtx.QueryArgs().Peek("order")) orderBy = string(r.RequestCtx.QueryArgs().Peek("order_by")) + filters = string(r.RequestCtx.QueryArgs().Peek("filters")) page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) - filters = string(r.RequestCtx.QueryArgs().Peek("filters")) total = 0 ) - conversations, pageSize, err := app.conversation.GetUnassignedConversationsList(user.ID, order, orderBy, filters, page, pageSize) + + conversations, err := app.conversation.GetUnassignedConversationsList(order, orderBy, filters, page, pageSize) if err != nil { return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, "") } if len(conversations) > 0 { total = conversations[0].Total } + + // Set deadlines for SLA if conversation has a policy + for i := range conversations { + if conversations[i].SLAPolicyID.Int != 0 { + setSLADeadlines(app, &conversations[i]) + } + conversations[i].ID = 0 + } + return r.SendEnvelope(envelope.PageResults{ Results: conversations, Total: total, @@ -95,46 +128,199 @@ func handleGetUnassignedConversations(r *fastglue.Request) error { }) } -// handleGetConversation retrieves a single conversation by UUID with permission checks. -func handleGetConversation(r *fastglue.Request) error { +// handleGetViewConversations retrieves conversations for a view. +func handleGetViewConversations(r *fastglue.Request) error { var ( - app = r.Context.(*App) - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + viewID, _ = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + order = string(r.RequestCtx.QueryArgs().Peek("order")) + orderBy = string(r.RequestCtx.QueryArgs().Peek("order_by")) + page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) + pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) + total = 0 ) - conversation, err := enforceConversationAccess(app, uuid, user) + if viewID < 1 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `view_id`", nil, envelope.InputError) + } + + // Check if user has access to the view. + view, err := app.view.Get(viewID) + if err != nil { + return sendErrorEnvelope(r, err) + } + if view.UserID != auser.ID { + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "You don't have access to this view.", nil, envelope.PermissionError) + } + + user, err := app.user.Get(auser.ID) if err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(conversation) + // Prepare lists user has access to based on user permissions, internally this affects the SQL query. + lists := []string{} + for _, perm := range user.Permissions { + if perm == authzModels.PermConversationsReadAll { + // No further lists required as user has access to all conversations. + lists = []string{cmodels.AllConversations} + break + } + if perm == authzModels.PermConversationsReadUnassigned { + lists = append(lists, cmodels.UnassignedConversations) + } + if perm == authzModels.PermConversationsReadAssigned { + lists = append(lists, cmodels.AssignedConversations) + } + if perm == authzModels.PermConversationsReadTeamInbox { + lists = append(lists, cmodels.TeamUnassignedConversations) + } + } + + // No lists found, user doesn't have access to any conversations. + if len(lists) == 0 { + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "Permission denied", nil, envelope.PermissionError) + } + + conversations, err := app.conversation.GetViewConversationsList(user.ID, user.Teams.IDs(), lists, order, orderBy, string(view.Filters), page, pageSize) + if err != nil { + return sendErrorEnvelope(r, err) + } + if len(conversations) > 0 { + total = conversations[0].Total + } + + // Set deadlines for SLA if conversation has a policy + for i := range conversations { + if conversations[i].SLAPolicyID.Int != 0 { + setSLADeadlines(app, &conversations[i]) + } + conversations[i].ID = 0 + } + + return r.SendEnvelope(envelope.PageResults{ + Results: conversations, + Total: total, + PerPage: pageSize, + TotalPages: (total + pageSize - 1) / pageSize, + Page: page, + }) +} + +// handleGetTeamUnassignedConversations returns conversations assigned to a team but not to any user. +func handleGetTeamUnassignedConversations(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + teamIDStr = r.RequestCtx.UserValue("id").(string) + order = string(r.RequestCtx.QueryArgs().Peek("order")) + orderBy = string(r.RequestCtx.QueryArgs().Peek("order_by")) + filters = string(r.RequestCtx.QueryArgs().Peek("filters")) + page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) + pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) + total = 0 + ) + teamID, _ := strconv.Atoi(teamIDStr) + if teamID < 1 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `team_id`", nil, envelope.InputError) + } + + // Check if user belongs to the team. + exists, err := app.team.UserBelongsToTeam(teamID, auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + if !exists { + return sendErrorEnvelope(r, envelope.NewError(envelope.PermissionError, "You're not a member of this team, Please refresh the page and try again.", nil)) + } + + conversations, err := app.conversation.GetTeamUnassignedConversationsList(teamID, order, orderBy, filters, page, pageSize) + if err != nil { + return sendErrorEnvelope(r, err) + } + if len(conversations) > 0 { + total = conversations[0].Total + } + + // Set deadlines for SLA if conversation has a policy + for i := range conversations { + if conversations[i].SLAPolicyID.Int != 0 { + setSLADeadlines(app, &conversations[i]) + } + conversations[i].ID = 0 + } + + return r.SendEnvelope(envelope.PageResults{ + Results: conversations, + Total: total, + PerPage: pageSize, + TotalPages: (total + pageSize - 1) / pageSize, + Page: page, + }) +} + +// handleGetConversation retrieves a single conversation by it's UUID. +func handleGetConversation(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + conv, err := enforceConversationAccess(app, uuid, user) + if err != nil { + return sendErrorEnvelope(r, err) + } + + if conv.SLAPolicyID.Int != 0 { + setSLADeadlines(app, conv) + } + + prev, _ := app.conversation.GetContactConversations(conv.ContactID) + conv.PreviousConversations = filterCurrentConv(prev, conv.UUID) + conv.ID = 0 + return r.SendEnvelope(conv) } // handleUpdateConversationAssigneeLastSeen updates the assignee's last seen timestamp for a conversation. func handleUpdateConversationAssigneeLastSeen(r *fastglue.Request) error { var ( - app = r.Context.(*App) - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) - _, err := enforceConversationAccess(app, uuid, user) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + _, err = enforceConversationAccess(app, uuid, user) if err != nil { return sendErrorEnvelope(r, err) } if err = app.conversation.UpdateConversationAssigneeLastSeen(uuid); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Last seen updated successfully") } // handleGetConversationParticipants retrieves participants of a conversation. func handleGetConversationParticipants(r *fastglue.Request) error { var ( - app = r.Context.(*App) - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) - _, err := enforceConversationAccess(app, uuid, user) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + _, err = enforceConversationAccess(app, uuid, user) if err != nil { return sendErrorEnvelope(r, err) } @@ -145,17 +331,21 @@ func handleGetConversationParticipants(r *fastglue.Request) error { return r.SendEnvelope(p) } -// handleUpdateConversationUserAssignee updates the user assigned to a conversation. -func handleUpdateConversationUserAssignee(r *fastglue.Request) error { +// handleUpdateUserAssignee updates the user assigned to a conversation. +func handleUpdateUserAssignee(r *fastglue.Request) error { var ( - app = r.Context.(*App) - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) + assigneeID = r.RequestCtx.PostArgs().GetUintOrZero("assignee_id") ) + if assigneeID == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `assignee_id`", nil, envelope.InputError) + } - assigneeID, err := r.RequestCtx.PostArgs().GetUint("assignee_id") + user, err := app.user.Get(auser.ID) if err != nil { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid assignee `id`.", nil, envelope.InputError) + return sendErrorEnvelope(r, err) } _, err = enforceConversationAccess(app, uuid, user) @@ -170,21 +360,32 @@ func handleUpdateConversationUserAssignee(r *fastglue.Request) error { // Evaluate automation rules. app.automation.EvaluateConversationUpdateRules(uuid, models.EventConversationUserAssigned) - return r.SendEnvelope(true) + return r.SendEnvelope("User assigned successfully") } // handleUpdateTeamAssignee updates the team assigned to a conversation. func handleUpdateTeamAssignee(r *fastglue.Request) error { var ( - app = r.Context.(*App) - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) assigneeID, err := r.RequestCtx.PostArgs().GetUint("assignee_id") if err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid assignee `id`.", nil, envelope.InputError) } - _, err = enforceConversationAccess(app, uuid, user) + + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + _, err = app.team.Get(assigneeID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + conversation, err := enforceConversationAccess(app, uuid, user) if err != nil { return sendErrorEnvelope(r, err) } @@ -192,84 +393,156 @@ func handleUpdateTeamAssignee(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - // Evaluate automation rules. + // Evaluate automation rules on team assignment. app.automation.EvaluateConversationUpdateRules(uuid, models.EventConversationTeamAssigned) - return r.SendEnvelope(true) + + // Apply SLA policy if team has changed and the new team has an SLA policy. + if conversation.AssignedTeamID.Int != assigneeID && assigneeID != 0 { + team, err := app.team.Get(assigneeID) + if err != nil { + return sendErrorEnvelope(r, err) + } + if team.SLAPolicyID.Int != 0 { + if err := app.conversation.ApplySLA(*conversation, team.SLAPolicyID.Int, user); err != nil { + return sendErrorEnvelope(r, err) + } + } + } + return r.SendEnvelope("Team assigned successfully") } // handleUpdateConversationPriority updates the priority of a conversation. func handleUpdateConversationPriority(r *fastglue.Request) error { var ( app = r.Context.(*App) - p = r.RequestCtx.PostArgs() - priority = p.Peek("priority") uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + auser = r.RequestCtx.UserValue("user").(amodels.User) + priority = string(r.RequestCtx.PostArgs().Peek("priority")) ) - _, err := enforceConversationAccess(app, uuid, user) + if priority == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `priority`", nil, envelope.InputError) + } + conversation, err := app.conversation.GetConversation(0, uuid) if err != nil { return sendErrorEnvelope(r, err) } - if err := app.conversation.UpdateConversationPriority(uuid, priority, user); err != nil { + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + allowed, err := app.authz.EnforceConversationAccess(user, conversation) + if err != nil { + return sendErrorEnvelope(r, err) + } + if !allowed { + return sendErrorEnvelope(r, envelope.NewError(envelope.PermissionError, "Permission denied", nil)) + } + if err := app.conversation.UpdateConversationPriority(uuid, 0 /**priority_id**/, priority, user); err != nil { return sendErrorEnvelope(r, err) } // Evaluate automation rules. app.automation.EvaluateConversationUpdateRules(uuid, models.EventConversationPriorityChange) - - return r.SendEnvelope(true) + return r.SendEnvelope("Priority updated successfully") } // handleUpdateConversationStatus updates the status of a conversation. func handleUpdateConversationStatus(r *fastglue.Request) error { var ( - app = r.Context.(*App) - p = r.RequestCtx.PostArgs() - status = p.Peek("status") - uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + status = string(r.RequestCtx.PostArgs().Peek("status")) + snoozedUntil = string(r.RequestCtx.PostArgs().Peek("snoozed_until")) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) - _, err := enforceConversationAccess(app, uuid, user) + + // Validate inputs + if status == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `status`", nil, envelope.InputError) + } + if snoozedUntil == "" && status == cmodels.StatusSnoozed { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `snoozed_until`", nil, envelope.InputError) + } + if status == cmodels.StatusSnoozed { + _, err := time.ParseDuration(snoozedUntil) + if err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `snoozed_until`", nil, envelope.InputError) + } + } + + // Enforce conversation access. + user, err := app.user.Get(auser.ID) if err != nil { return sendErrorEnvelope(r, err) } - if err := app.conversation.UpdateConversationStatus(uuid, status, user); err != nil { + conversation, err := enforceConversationAccess(app, uuid, user) + if err != nil { + return sendErrorEnvelope(r, err) + } + + // Make sure a user is assigned before resolving conversation. + if status == cmodels.StatusResolved && conversation.AssignedUserID.Int == 0 { + return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, "Cannot resolve the conversation without an assigned user, Please assign a user before attempting to resolve.", nil)) + } + + // Update conversation status. + if err := app.conversation.UpdateConversationStatus(uuid, 0 /**status_id**/, status, snoozedUntil, user); err != nil { return sendErrorEnvelope(r, err) } // Evaluate automation rules. app.automation.EvaluateConversationUpdateRules(uuid, models.EventConversationStatusChange) - return r.SendEnvelope(true) + // If status is `Resolved`, send CSAT survey if enabled on inbox. + if status == cmodels.StatusResolved { + // Check if CSAT is enabled on the inbox and send CSAT survey message. + inbox, err := app.inbox.GetDBRecord(conversation.InboxID) + if err != nil { + return sendErrorEnvelope(r, err) + } + if inbox.CSATEnabled { + if err := app.conversation.SendCSATReply(user.ID, *conversation); err != nil { + return sendErrorEnvelope(r, err) + } + } + } + return r.SendEnvelope("Status updated successfully") } -// handleAddConversationTags adds tags to a conversation. -func handleAddConversationTags(r *fastglue.Request) error { +// handleUpdateConversationtags updates conversation tags. +func handleUpdateConversationtags(r *fastglue.Request) error { var ( - app = r.Context.(*App) - p = r.RequestCtx.PostArgs() - tagIDs = []int{} - tagJSON = p.Peek("tag_ids") - user = r.RequestCtx.UserValue("user").(umodels.User) - uuid = r.RequestCtx.UserValue("uuid").(string) + app = r.Context.(*App) + tagNames = []string{} + tagJSON = r.RequestCtx.PostArgs().Peek("tags") + auser = r.RequestCtx.UserValue("user").(amodels.User) + uuid = r.RequestCtx.UserValue("uuid").(string) ) - // Parse tag IDs from JSON - err := json.Unmarshal(tagJSON, &tagIDs) - if err != nil { - app.lo.Error("unmarshalling tag ids", "error", err) - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "error adding tags", nil, "") + if err := json.Unmarshal(tagJSON, &tagNames); err != nil { + app.lo.Error("error unmarshalling tags JSON", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error unmarshalling tags JSON", nil, envelope.GeneralError) } - - _, err = enforceConversationAccess(app, uuid, user) + conversation, err := app.conversation.GetConversation(0, uuid) if err != nil { return sendErrorEnvelope(r, err) } - if err := app.conversation.UpsertConversationTags(uuid, tagIDs); err != nil { + user, err := app.user.Get(auser.ID) + if err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + + if allowed, err := app.authz.EnforceConversationAccess(user, conversation); err != nil { + return sendErrorEnvelope(r, err) + } else if !allowed { + return sendErrorEnvelope(r, envelope.NewError(envelope.PermissionError, "Permission denied", nil)) + } + + if err := app.conversation.UpsertConversationTags(uuid, tagNames, user); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("Tags added successfully") } // handleDashboardCounts retrieves general dashboard counts for all users. @@ -298,7 +571,7 @@ func handleDashboardCharts(r *fastglue.Request) error { // enforceConversationAccess fetches the conversation and checks if the user has access to it. func enforceConversationAccess(app *App, uuid string, user umodels.User) (*cmodels.Conversation, error) { - conversation, err := app.conversation.GetConversation(uuid) + conversation, err := app.conversation.GetConversation(0, uuid) if err != nil { return nil, err } @@ -311,3 +584,70 @@ func enforceConversationAccess(app *App, uuid string, user umodels.User) (*cmode } return &conversation, nil } + +// setSLADeadlines gets the latest SLA deadlines for a conversation and sets them. +func setSLADeadlines(app *App, conversation *cmodels.Conversation) error { + if conversation.ID < 1 { + return nil + } + first, resolution, err := app.sla.GetLatestDeadlines(conversation.ID) + if err != nil { + app.lo.Error("error getting SLA deadlines", "id", conversation.ID, "error", err) + return err + } + conversation.FirstResponseDueAt = null.NewTime(first, first != time.Time{}) + conversation.ResolutionDueAt = null.NewTime(resolution, resolution != time.Time{}) + return nil +} + +// handleRemoveUserAssignee removes the user assigned to a conversation. +func handleRemoveUserAssignee(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + _, err = enforceConversationAccess(app, uuid, user) + if err != nil { + return sendErrorEnvelope(r, err) + } + if err = app.conversation.RemoveConversationAssignee(uuid, "user"); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(true) +} + +// handleRemoveTeamAssignee removes the team assigned to a conversation. +func handleRemoveTeamAssignee(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + _, err = enforceConversationAccess(app, uuid, user) + if err != nil { + return sendErrorEnvelope(r, err) + } + if err = app.conversation.RemoveConversationAssignee(uuid, "team"); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(true) +} + +// filterCurrentConv removes the current conversation from the list of conversations. +func filterCurrentConv(convs []cmodels.Conversation, uuid string) []cmodels.Conversation { + for i, c := range convs { + if c.UUID == uuid { + return append(convs[:i], convs[i+1:]...) + } + } + return []cmodels.Conversation{} +} diff --git a/cmd/csat.go b/cmd/csat.go new file mode 100644 index 00000000..a89234cc --- /dev/null +++ b/cmd/csat.go @@ -0,0 +1,105 @@ +package main + +import ( + "strconv" + + "github.com/zerodha/fastglue" +) + +// handleShowCSAT renders the CSAT page for a given csat. +func handleShowCSAT(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + ) + + csat, err := app.csat.Get(uuid) + if err != nil { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": "Page not found", + }, + }) + } + + if csat.ResponseTimestamp.Valid { + return app.tmpl.RenderWebPage(r.RequestCtx, "info", map[string]interface{}{ + "Data": map[string]interface{}{ + "Title": "Thank you!", + "Message": "We appreciate you taking the time to submit your feedback.", + }, + }) + } + + conversation, err := app.conversation.GetConversation(csat.ConversationID, "") + if err != nil { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": "Page not found", + }, + }) + } + + return app.tmpl.RenderWebPage(r.RequestCtx, "csat", map[string]interface{}{ + "Data": map[string]interface{}{ + "Title": "Rate your interaction with us", + "CSAT": map[string]interface{}{ + "UUID": csat.UUID, + }, + "Conversation": map[string]interface{}{ + "Subject": conversation.Subject.String, + "ReferenceNumber": conversation.ReferenceNumber, + }, + }, + }) +} + +// handleUpdateCSATResponse updates the CSAT response for a given csat. +func handleUpdateCSATResponse(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + uuid = r.RequestCtx.UserValue("uuid").(string) + rating = r.RequestCtx.FormValue("rating") + feedback = string(r.RequestCtx.FormValue("feedback")) + ) + + ratingI, err := strconv.Atoi(string(rating)) + if err != nil { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": "Invalid `rating`", + }, + }) + } + + if ratingI < 1 || ratingI > 5 { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": "Invalid `rating`", + }, + }) + } + + if uuid == "" { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": "Invalid `uuid`", + }, + }) + } + + if err := app.csat.UpdateResponse(uuid, ratingI, feedback); err != nil { + return app.tmpl.RenderWebPage(r.RequestCtx, "error", map[string]interface{}{ + "Data": map[string]interface{}{ + "ErrorMessage": err.Error(), + }, + }) + } + + return app.tmpl.RenderWebPage(r.RequestCtx, "info", map[string]interface{}{ + "Data": map[string]interface{}{ + "Title": "Thank you!", + "Message": "We appreciate you taking the time to submit your feedback.", + }, + }) +} diff --git a/cmd/handlers.go b/cmd/handlers.go index 78151361..6581d652 100644 --- a/cmd/handlers.go +++ b/cmd/handlers.go @@ -6,135 +6,172 @@ import ( "path" "path/filepath" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/ws" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/ws" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +var ( + slaReqFields = map[string][2]int{"name": {1, 255}, "description": {1, 255}, "first_response_time": {1, 255}, "resolution_time": {1, 255}} +) + // initHandlers initializes the HTTP routes and handlers for the application. func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) { // Authentication. - g.POST("/api/login", handleLogin) + g.POST("/api/v1/login", handleLogin) g.GET("/logout", handleLogout) - g.GET("/api/oidc/{id}/login", handleOIDCLogin) - g.GET("/api/oidc/finish", handleOIDCCallback) - - // Health check. - g.GET("/health", handleHealthCheck) - - // Serve media files. - g.GET("/uploads/{uuid}", auth(handleServeMedia)) - - // Settings. - g.GET("/api/settings/general", handleGetGeneralSettings) - g.PUT("/api/settings/general", authPerm(handleUpdateGeneralSettings, "settings_general", "write")) - g.GET("/api/settings/notifications/email", authPerm(handleGetEmailNotificationSettings, "settings_notifications", "read")) - g.PUT("/api/settings/notifications/email", authPerm(handleUpdateEmailNotificationSettings, "settings_notifications", "write")) - - // OpenID SSO. - g.GET("/api/oidc", handleGetAllOIDC) - g.GET("/api/oidc/{id}", authPerm(handleGetOIDC, "oidc", "read")) - g.POST("/api/oidc", authPerm(handleCreateOIDC, "oidc", "write")) - g.PUT("/api/oidc/{id}", authPerm(handleUpdateOIDC, "oidc", "write")) - g.DELETE("/api/oidc/{id}", authPerm(handleDeleteOIDC, "oidc", "delete")) - - // Conversation and message. - g.GET("/api/conversations/all", authPerm(handleGetAllConversations, "conversations", "read_all")) - g.GET("/api/conversations/unassigned", authPerm(handleGetUnassignedConversations, "conversations", "read_unassigned")) - g.GET("/api/conversations/assigned", authPerm(handleGetAssignedConversations, "conversations", "read_assigned")) - g.GET("/api/conversations/{uuid}", authPerm(handleGetConversation, "conversations", "read")) - g.GET("/api/conversations/{uuid}/participants", authPerm(handleGetConversationParticipants, "conversations", "read")) - g.PUT("/api/conversations/{uuid}/assignee/user", authPerm(handleUpdateConversationUserAssignee, "conversations", "update_user_assignee")) - g.PUT("/api/conversations/{uuid}/assignee/team", authPerm(handleUpdateTeamAssignee, "conversations", "update_team_assignee")) - g.PUT("/api/conversations/{uuid}/priority", authPerm(handleUpdateConversationPriority, "conversations", "update_priority")) - g.PUT("/api/conversations/{uuid}/status", authPerm(handleUpdateConversationStatus, "conversations", "update_status")) - g.PUT("/api/conversations/{uuid}/last-seen", authPerm(handleUpdateConversationAssigneeLastSeen, "conversations", "read")) - g.POST("/api/conversations/{uuid}/tags", authPerm(handleAddConversationTags, "conversations", "update_tags")) - g.POST("/api/conversations/{cuuid}/messages", authPerm(handleSendMessage, "messages", "write")) - g.GET("/api/conversations/{uuid}/messages", authPerm(handleGetMessages, "messages", "read")) - g.PUT("/api/conversations/{cuuid}/messages/{uuid}/retry", authPerm(handleRetryMessage, "messages", "write")) - g.GET("/api/conversations/{cuuid}/messages/{uuid}", authPerm(handleGetMessage, "messages", "read")) - - // Status and priority. - g.GET("/api/statuses", auth(handleGetStatuses)) - g.POST("/api/statuses", authPerm(handleCreateStatus, "status", "write")) - g.PUT("/api/statuses/{id}", authPerm(handleUpdateStatus, "status", "write")) - g.DELETE("/api/statuses/{id}", authPerm(handleDeleteStatus, "status", "delete")) - g.GET("/api/priorities", auth(handleGetPriorities)) - - // Tag. - g.GET("/api/tags", auth(handleGetTags)) - g.POST("/api/tags", authPerm(handleCreateTag, "tags", "write")) - g.PUT("/api/tags/{id}", authPerm(handleUpdateTag, "tags", "write")) - g.DELETE("/api/tags/{id}", authPerm(handleDeleteTag, "tags", "delete")) + g.GET("/api/v1/oidc/{id}/login", handleOIDCLogin) + g.GET("/api/v1/oidc/{id}/finish", handleOIDCCallback) // Media. - g.POST("/api/media", auth(handleMediaUpload)) + g.GET("/uploads/{uuid}", auth(handleServeMedia)) + g.POST("/api/v1/media", auth(handleMediaUpload)) - // Canned response. - g.GET("/api/canned-responses", auth(handleGetCannedResponses)) - g.POST("/api/canned-responses", authPerm(handleCreateCannedResponse, "canned_responses", "write")) - g.PUT("/api/canned-responses/{id}", authPerm(handleUpdateCannedResponse, "canned_responses", "write")) - g.DELETE("/api/canned-responses/{id}", authPerm(handleDeleteCannedResponse, "canned_responses", "delete")) + // Settings. + g.GET("/api/v1/settings/general", handleGetGeneralSettings) + g.PUT("/api/v1/settings/general", perm(handleUpdateGeneralSettings, "general_settings:manage")) + g.GET("/api/v1/settings/notifications/email", perm(handleGetEmailNotificationSettings, "notification_settings:manage")) + g.PUT("/api/v1/settings/notifications/email", perm(handleUpdateEmailNotificationSettings, "notification_settings:manage")) + + // OpenID connect single sign-on. + g.GET("/api/v1/oidc/enabled", handleGetAllEnabledOIDC) + g.GET("/api/v1/oidc", perm(handleGetAllOIDC, "oidc:manage")) + g.GET("/api/v1/oidc/{id}", perm(handleGetOIDC, "oidc:manage")) + g.POST("/api/v1/oidc", perm(handleCreateOIDC, "oidc:manage")) + g.PUT("/api/v1/oidc/{id}", perm(handleUpdateOIDC, "oidc:manage")) + g.DELETE("/api/v1/oidc/{id}", perm(handleDeleteOIDC, "oidc:manage")) + + // Conversations. + g.GET("/api/v1/conversations/all", perm(handleGetAllConversations, "conversations:read_all")) + g.GET("/api/v1/conversations/unassigned", perm(handleGetUnassignedConversations, "conversations:read_unassigned")) + g.GET("/api/v1/conversations/assigned", perm(handleGetAssignedConversations, "conversations:read_assigned")) + g.GET("/api/v1/teams/{id}/conversations/unassigned", perm(handleGetTeamUnassignedConversations, "conversations:read_team_inbox")) + g.GET("/api/v1/views/{id}/conversations", perm(handleGetViewConversations, "conversations:read")) + g.GET("/api/v1/conversations/{uuid}", perm(handleGetConversation, "conversations:read")) + g.GET("/api/v1/conversations/{uuid}/participants", perm(handleGetConversationParticipants, "conversations:read")) + g.PUT("/api/v1/conversations/{uuid}/assignee/user", perm(handleUpdateUserAssignee, "conversations:update_user_assignee")) + g.PUT("/api/v1/conversations/{uuid}/assignee/team", perm(handleUpdateTeamAssignee, "conversations:update_team_assignee")) + g.PUT("/api/v1/conversations/{uuid}/assignee/user/remove", perm(handleRemoveUserAssignee, "conversations:update_user_assignee")) + g.PUT("/api/v1/conversations/{uuid}/assignee/team/remove", perm(handleRemoveTeamAssignee, "conversations:update_team_assignee")) + g.PUT("/api/v1/conversations/{uuid}/priority", perm(handleUpdateConversationPriority, "conversations:update_priority")) + g.PUT("/api/v1/conversations/{uuid}/status", perm(handleUpdateConversationStatus, "conversations:update_status")) + g.PUT("/api/v1/conversations/{uuid}/last-seen", perm(handleUpdateConversationAssigneeLastSeen, "conversations:read")) + g.POST("/api/v1/conversations/{uuid}/tags", perm(handleUpdateConversationtags, "conversations:update_tags")) + g.GET("/api/v1/conversations/{cuuid}/messages/{uuid}", perm(handleGetMessage, "messages:read")) + g.GET("/api/v1/conversations/{uuid}/messages", perm(handleGetMessages, "messages:read")) + g.POST("/api/v1/conversations/{cuuid}/messages", perm(handleSendMessage, "messages:write")) + g.PUT("/api/v1/conversations/{cuuid}/messages/{uuid}/retry", perm(handleRetryMessage, "messages:write")) + + // Search. + g.GET("/api/v1/conversations/search", perm(handleSearchConversations, "conversations:read")) + g.GET("/api/v1/messages/search", perm(handleSearchMessages, "messages:read")) + + // Views. + g.GET("/api/v1/views/me", perm(handleGetUserViews, "view:manage")) + g.POST("/api/v1/views/me", perm(handleCreateUserView, "view:manage")) + g.PUT("/api/v1/views/me/{id}", perm(handleUpdateUserView, "view:manage")) + g.DELETE("/api/v1/views/me/{id}", perm(handleDeleteUserView, "view:manage")) + + // Status and priority. + g.GET("/api/v1/statuses", auth(handleGetStatuses)) + g.POST("/api/v1/statuses", perm(handleCreateStatus, "status:manage")) + g.PUT("/api/v1/statuses/{id}", perm(handleUpdateStatus, "status:manage")) + g.DELETE("/api/v1/statuses/{id}", perm(handleDeleteStatus, "status:manage")) + g.GET("/api/v1/priorities", auth(handleGetPriorities)) + + // Tag. + g.GET("/api/v1/tags", auth(handleGetTags)) + g.POST("/api/v1/tags", perm(handleCreateTag, "tags:manage")) + g.PUT("/api/v1/tags/{id}", perm(handleUpdateTag, "tags:manage")) + g.DELETE("/api/v1/tags/{id}", perm(handleDeleteTag, "tags:manage")) + + // Macros. + g.GET("/api/v1/macros", auth(handleGetMacros)) + g.GET("/api/v1/macros/{id}", perm(handleGetMacro, "macros:manage")) + g.POST("/api/v1/macros", perm(handleCreateMacro, "macros:manage")) + g.PUT("/api/v1/macros/{id}", perm(handleUpdateMacro, "macros:manage")) + g.DELETE("/api/v1/macros/{id}", perm(handleDeleteMacro, "macros:manage")) + g.POST("/api/v1/conversations/{uuid}/macros/{id}/apply", auth(handleApplyMacro)) // User. - g.GET("/api/users/me", auth(handleGetCurrentUser)) - g.PUT("/api/users/me", auth(handleUpdateCurrentUser)) - g.DELETE("/api/users/me/avatar", auth(handleDeleteAvatar)) - g.GET("/api/users/compact", auth(handleGetUsersCompact)) - g.GET("/api/users", authPerm(handleGetUsers, "users", "read")) - g.GET("/api/users/{id}", authPerm(handleGetUser, "users", "read")) - g.POST("/api/users", authPerm(handleCreateUser, "users", "write")) - g.PUT("/api/users/{id}", authPerm(handleUpdateUser, "users", "write")) - g.DELETE("/api/users/{id}", authPerm(handleDeleteUser, "users", "delete")) - g.POST("/api/users/reset-password", tryAuth(handleResetPassword)) - g.POST("/api/users/set-password", tryAuth(handleSetPassword)) + g.GET("/api/v1/users/me", auth(handleGetCurrentUser)) + g.PUT("/api/v1/users/me", auth(handleUpdateCurrentUser)) + g.GET("/api/v1/users/me/teams", auth(handleGetCurrentUserTeams)) + g.DELETE("/api/v1/users/me/avatar", auth(handleDeleteAvatar)) + g.GET("/api/v1/users/compact", auth(handleGetUsersCompact)) + g.GET("/api/v1/users", perm(handleGetUsers, "users:manage")) + g.GET("/api/v1/users/{id}", perm(handleGetUser, "users:manage")) + g.POST("/api/v1/users", perm(handleCreateUser, "users:manage")) + g.PUT("/api/v1/users/{id}", perm(handleUpdateUser, "users:manage")) + g.DELETE("/api/v1/users/{id}", perm(handleDeleteUser, "users:manage")) + g.POST("/api/v1/users/reset-password", tryAuth(handleResetPassword)) + g.POST("/api/v1/users/set-password", tryAuth(handleSetPassword)) // Team. - g.GET("/api/teams/compact", auth(handleGetTeamsCompact)) - g.GET("/api/teams", authPerm(handleGetTeams, "teams", "read")) - g.POST("/api/teams", authPerm(handleCreateTeam, "teams", "write")) - g.GET("/api/teams/{id}", authPerm(handleGetTeam, "teams", "read")) - g.PUT("/api/teams/{id}", authPerm(handleUpdateTeam, "teams", "write")) - g.DELETE("/api/teams/{id}", authPerm(handleDeleteTeam, "teams", "delete")) + g.GET("/api/v1/teams/compact", auth(handleGetTeamsCompact)) + g.GET("/api/v1/teams", perm(handleGetTeams, "teams:manage")) + g.GET("/api/v1/teams/{id}", perm(handleGetTeam, "teams:manage")) + g.POST("/api/v1/teams", perm(handleCreateTeam, "teams:manage")) + g.PUT("/api/v1/teams/{id}", perm(handleUpdateTeam, "teams:manage")) + g.DELETE("/api/v1/teams/{id}", perm(handleDeleteTeam, "teams:manage")) // i18n. - g.GET("/api/lang/{lang}", handleGetI18nLang) + g.GET("/api/v1/lang/{lang}", handleGetI18nLang) // Automation. - g.GET("/api/automation/rules", authPerm(handleGetAutomationRules, "automations", "read")) - g.GET("/api/automation/rules/{id}", authPerm(handleGetAutomationRule, "automations", "read")) - g.POST("/api/automation/rules", authPerm(handleCreateAutomationRule, "automations", "write")) - g.PUT("/api/automation/rules/{id}/toggle", authPerm(handleToggleAutomationRule, "automations", "write")) - g.PUT("/api/automation/rules/{id}", authPerm(handleUpdateAutomationRule, "automations", "write")) - g.DELETE("/api/automation/rules/{id}", authPerm(handleDeleteAutomationRule, "automations", "delete")) + g.GET("/api/v1/automation/rules", perm(handleGetAutomationRules, "automations:manage")) + g.GET("/api/v1/automation/rules/{id}", perm(handleGetAutomationRule, "automations:manage")) + g.POST("/api/v1/automation/rules", perm(handleCreateAutomationRule, "automations:manage")) + g.PUT("/api/v1/automation/rules/{id}/toggle", perm(handleToggleAutomationRule, "automations:manage")) + g.PUT("/api/v1/automation/rules/{id}", perm(handleUpdateAutomationRule, "automations:manage")) + g.PUT("/api/v1/automation/rules/weights", perm(handleUpdateAutomationRuleWeights, "automations:manage")) + g.PUT("/api/v1/automation/rules/execution-mode", perm(handleUpdateAutomationRuleExecutionMode, "automations:manage")) + g.DELETE("/api/v1/automation/rules/{id}", perm(handleDeleteAutomationRule, "automations:manage")) // Inbox. - g.GET("/api/inboxes", authPerm(handleGetInboxes, "inboxes", "read")) - g.GET("/api/inboxes/{id}", authPerm(handleGetInbox, "inboxes", "read")) - g.POST("/api/inboxes", authPerm(handleCreateInbox, "inboxes", "write")) - g.PUT("/api/inboxes/{id}/toggle", authPerm(handleToggleInbox, "inboxes", "write")) - g.PUT("/api/inboxes/{id}", authPerm(handleUpdateInbox, "inboxes", "write")) - g.DELETE("/api/inboxes/{id}", authPerm(handleDeleteInbox, "inboxes", "delete")) + g.GET("/api/v1/inboxes", auth(handleGetInboxes)) + g.GET("/api/v1/inboxes/{id}", perm(handleGetInbox, "inboxes:manage")) + g.POST("/api/v1/inboxes", perm(handleCreateInbox, "inboxes:manage")) + g.PUT("/api/v1/inboxes/{id}/toggle", perm(handleToggleInbox, "inboxes:manage")) + g.PUT("/api/v1/inboxes/{id}", perm(handleUpdateInbox, "inboxes:manage")) + g.DELETE("/api/v1/inboxes/{id}", perm(handleDeleteInbox, "inboxes:manage")) // Role. - g.GET("/api/roles", authPerm(handleGetRoles, "roles", "read")) - g.GET("/api/roles/{id}", authPerm(handleGetRole, "roles", "read")) - g.POST("/api/roles", authPerm(handleCreateRole, "roles", "write")) - g.PUT("/api/roles/{id}", authPerm(handleUpdateRole, "roles", "write")) - g.DELETE("/api/roles/{id}", authPerm(handleDeleteRole, "roles", "delete")) + g.GET("/api/v1/roles", perm(handleGetRoles, "roles:manage")) + g.GET("/api/v1/roles/{id}", perm(handleGetRole, "roles:manage")) + g.POST("/api/v1/roles", perm(handleCreateRole, "roles:manage")) + g.PUT("/api/v1/roles/{id}", perm(handleUpdateRole, "roles:manage")) + g.DELETE("/api/v1/roles/{id}", perm(handleDeleteRole, "roles:manage")) // Dashboard. - g.GET("/api/dashboard/global/counts", authPerm(handleDashboardCounts, "dashboard_global", "read")) - g.GET("/api/dashboard/global/charts", authPerm(handleDashboardCharts, "dashboard_global", "read")) + g.GET("/api/v1/reports/overview/counts", perm(handleDashboardCounts, "reports:manage")) + g.GET("/api/v1/reports/overview/charts", perm(handleDashboardCharts, "reports:manage")) // Template. - g.GET("/api/templates", authPerm(handleGetTemplates, "templates", "read")) - g.GET("/api/templates/{id}", authPerm(handleGetTemplate, "templates", "read")) - g.POST("/api/templates", authPerm(handleCreateTemplate, "templates", "write")) - g.PUT("/api/templates/{id}", authPerm(handleUpdateTemplate, "templates", "write")) - g.DELETE("/api/templates/{id}", authPerm(handleDeleteTemplate, "templates", "delete")) + g.GET("/api/v1/templates", perm(handleGetTemplates, "templates:manage")) + g.GET("/api/v1/templates/{id}", perm(handleGetTemplate, "templates:manage")) + g.POST("/api/v1/templates", perm(handleCreateTemplate, "templates:manage")) + g.PUT("/api/v1/templates/{id}", perm(handleUpdateTemplate, "templates:manage")) + g.DELETE("/api/v1/templates/{id}", perm(handleDeleteTemplate, "templates:manage")) + + // Business hours. + g.GET("/api/v1/business-hours", perm(handleGetBusinessHours, "business_hours:manage")) + g.GET("/api/v1/business-hours/{id}", perm(handleGetBusinessHour, "business_hours:manage")) + g.POST("/api/v1/business-hours", perm(handleCreateBusinessHours, "business_hours:manage")) + g.PUT("/api/v1/business-hours/{id}", perm(handleUpdateBusinessHours, "business_hours:manage")) + g.DELETE("/api/v1/business-hours/{id}", perm(handleDeleteBusinessHour, "business_hours:manage")) + + // SLA. + g.GET("/api/v1/sla", perm(handleGetSLAs, "sla:manage")) + g.GET("/api/v1/sla/{id}", perm(handleGetSLA, "sla:manage")) + g.POST("/api/v1/sla", perm(fastglue.ReqLenRangeParams(handleCreateSLA, slaReqFields), "sla:manage")) + g.PUT("/api/v1/sla/{id}", perm(fastglue.ReqLenRangeParams(handleUpdateSLA, slaReqFields), "sla:manage")) + g.DELETE("/api/v1/sla/{id}", perm(handleDeleteSLA, "sla:manage")) + + // AI completion. + g.GET("/api/v1/ai/prompts", auth(handleGetAIPrompts)) + g.POST("/api/v1/ai/completion", auth(handleAICompletion)) // WebSocket. g.GET("/ws", auth(func(r *fastglue.Request) error { @@ -143,15 +180,25 @@ func initHandlers(g *fastglue.Fastglue, hub *ws.Hub) { // Frontend pages. g.GET("/", notAuthPage(serveIndexPage)) - g.GET("/dashboard", authPage(serveIndexPage)) - g.GET("/conversations", authPage(serveIndexPage)) - g.GET("/conversations/{all:*}", authPage(serveIndexPage)) - g.GET("/account/profile", authPage(serveIndexPage)) + g.GET("/inboxes/{all:*}", authPage(serveIndexPage)) + g.GET("/teams/{all:*}", authPage(serveIndexPage)) + g.GET("/views/{all:*}", authPage(serveIndexPage)) g.GET("/admin/{all:*}", authPage(serveIndexPage)) + g.GET("/reports/{all:*}", authPage(serveIndexPage)) + g.GET("/account/{all:*}", authPage(serveIndexPage)) g.GET("/reset-password", notAuthPage(serveIndexPage)) g.GET("/set-password", notAuthPage(serveIndexPage)) - g.GET("/assets/{all:*}", serveStaticFiles) - g.GET("/images/{all:*}", serveStaticFiles) + // FIXME: Don't need three separate routes for the same thing. + g.GET("/assets/{all:*}", serveFrontendStaticFiles) + g.GET("/images/{all:*}", serveFrontendStaticFiles) + g.GET("/static/public/{all:*}", serveStaticFiles) + + // Public pages. + g.GET("/csat/{uuid}", handleShowCSAT) + g.POST("/csat/{uuid}", handleUpdateCSATResponse) + + // Health check. + g.GET("/health", handleHealthCheck) } // serveIndexPage serves the main index page of the application. @@ -186,6 +233,29 @@ func serveStaticFiles(r *fastglue.Request) error { // Get the requested file path. filePath := string(r.RequestCtx.Path()) + file, err := app.fs.Get(filePath) + if err != nil { + return r.SendErrorEnvelope(http.StatusNotFound, "File not found", nil, envelope.NotFoundError) + } + + // Set the appropriate Content-Type based on the file extension. + ext := filepath.Ext(filePath) + contentType := mime.TypeByExtension(ext) + if contentType == "" { + contentType = http.DetectContentType(file.ReadBytes()) + } + r.RequestCtx.Response.Header.Set("Content-Type", contentType) + r.RequestCtx.SetBody(file.ReadBytes()) + return nil +} + +// serveFrontendStaticFiles serves static assets from the embedded filesystem. +func serveFrontendStaticFiles(r *fastglue.Request) error { + app := r.Context.(*App) + + // Get the requested file path. + filePath := string(r.RequestCtx.Path()) + // Fetch and serve the file from the embedded filesystem. finalPath := filepath.Join(frontendDir, filePath) file, err := app.fs.Get(finalPath) diff --git a/cmd/i18n.go b/cmd/i18n.go index 19a5e6a2..dd3afc00 100644 --- a/cmd/i18n.go +++ b/cmd/i18n.go @@ -4,7 +4,7 @@ import ( "fmt" "net/http" - "github.com/abhinavxd/artemis/internal/envelope" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/knadh/go-i18n" "github.com/knadh/stuffbin" "github.com/zerodha/fastglue" diff --git a/cmd/inboxes.go b/cmd/inboxes.go index 9baeb0f1..bc80ac1c 100644 --- a/cmd/inboxes.go +++ b/cmd/inboxes.go @@ -3,8 +3,8 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - imodels "github.com/abhinavxd/artemis/internal/inbox/models" + "github.com/abhinavxd/libredesk/internal/envelope" + imodels "github.com/abhinavxd/libredesk/internal/inbox/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) @@ -23,7 +23,7 @@ func handleGetInbox(r *fastglue.Request) error { app = r.Context.(*App) id, _ = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) ) - inbox, err := app.inbox.GetByID(id) + inbox, err := app.inbox.GetDBRecord(id) if err != nil { return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error fetching inbox", nil, envelope.GeneralError) } @@ -54,6 +54,7 @@ func handleCreateInbox(r *fastglue.Request) error { return r.SendEnvelope(true) } +// handleUpdateInbox updates an inbox func handleUpdateInbox(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -74,7 +75,7 @@ func handleUpdateInbox(r *fastglue.Request) error { } if err := reloadInboxes(app); err != nil { - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error reloading inboxes", nil, envelope.GeneralError) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error reloading inboxes, Please restart the app if the issue persists", nil, envelope.GeneralError) } return r.SendEnvelope(inbox) diff --git a/cmd/init.go b/cmd/init.go index 5809455d..37f56448 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -12,31 +12,37 @@ import ( "html/template" - auth_ "github.com/abhinavxd/artemis/internal/auth" - "github.com/abhinavxd/artemis/internal/authz" - "github.com/abhinavxd/artemis/internal/autoassigner" - "github.com/abhinavxd/artemis/internal/automation" - "github.com/abhinavxd/artemis/internal/cannedresp" - "github.com/abhinavxd/artemis/internal/contact" - "github.com/abhinavxd/artemis/internal/conversation" - "github.com/abhinavxd/artemis/internal/conversation/priority" - "github.com/abhinavxd/artemis/internal/conversation/status" - "github.com/abhinavxd/artemis/internal/inbox" - "github.com/abhinavxd/artemis/internal/inbox/channel/email" - imodels "github.com/abhinavxd/artemis/internal/inbox/models" - "github.com/abhinavxd/artemis/internal/media" - fs "github.com/abhinavxd/artemis/internal/media/stores/localfs" - "github.com/abhinavxd/artemis/internal/media/stores/s3" - notifier "github.com/abhinavxd/artemis/internal/notification" - emailnotifier "github.com/abhinavxd/artemis/internal/notification/providers/email" - "github.com/abhinavxd/artemis/internal/oidc" - "github.com/abhinavxd/artemis/internal/role" - "github.com/abhinavxd/artemis/internal/setting" - "github.com/abhinavxd/artemis/internal/tag" - "github.com/abhinavxd/artemis/internal/team" - tmpl "github.com/abhinavxd/artemis/internal/template" - "github.com/abhinavxd/artemis/internal/user" - "github.com/abhinavxd/artemis/internal/ws" + "github.com/abhinavxd/libredesk/internal/ai" + auth_ "github.com/abhinavxd/libredesk/internal/auth" + "github.com/abhinavxd/libredesk/internal/authz" + "github.com/abhinavxd/libredesk/internal/autoassigner" + "github.com/abhinavxd/libredesk/internal/automation" + businesshours "github.com/abhinavxd/libredesk/internal/business_hours" + "github.com/abhinavxd/libredesk/internal/colorlog" + "github.com/abhinavxd/libredesk/internal/conversation" + "github.com/abhinavxd/libredesk/internal/conversation/priority" + "github.com/abhinavxd/libredesk/internal/conversation/status" + "github.com/abhinavxd/libredesk/internal/csat" + "github.com/abhinavxd/libredesk/internal/inbox" + "github.com/abhinavxd/libredesk/internal/inbox/channel/email" + imodels "github.com/abhinavxd/libredesk/internal/inbox/models" + "github.com/abhinavxd/libredesk/internal/macro" + "github.com/abhinavxd/libredesk/internal/media" + fs "github.com/abhinavxd/libredesk/internal/media/stores/localfs" + "github.com/abhinavxd/libredesk/internal/media/stores/s3" + notifier "github.com/abhinavxd/libredesk/internal/notification" + emailnotifier "github.com/abhinavxd/libredesk/internal/notification/providers/email" + "github.com/abhinavxd/libredesk/internal/oidc" + "github.com/abhinavxd/libredesk/internal/role" + "github.com/abhinavxd/libredesk/internal/search" + "github.com/abhinavxd/libredesk/internal/setting" + "github.com/abhinavxd/libredesk/internal/sla" + "github.com/abhinavxd/libredesk/internal/tag" + "github.com/abhinavxd/libredesk/internal/team" + tmpl "github.com/abhinavxd/libredesk/internal/template" + "github.com/abhinavxd/libredesk/internal/user" + "github.com/abhinavxd/libredesk/internal/view" + "github.com/abhinavxd/libredesk/internal/ws" "github.com/jmoiron/sqlx" "github.com/knadh/go-i18n" kjson "github.com/knadh/koanf/parsers/json" @@ -56,11 +62,12 @@ import ( // constants holds the app constants. type constants struct { AppBaseURL string + FaviconURL string LogoURL string SiteName string UploadProvider string AllowedUploadFileExtensions []string - MaxFileUploadSizeMB float64 + MaxFileUploadSizeMB int } // Config loads config files into koanf. @@ -103,14 +110,15 @@ func initFlags() { } // initConstants initializes the app constants. -func initConstants() constants { - return constants{ +func initConstants() *constants { + return &constants{ AppBaseURL: ko.String("app.root_url"), + FaviconURL: ko.String("app.favicon_url"), LogoURL: ko.String("app.logo_url"), SiteName: ko.String("app.site_name"), UploadProvider: ko.MustString("upload.provider"), AllowedUploadFileExtensions: ko.Strings("app.allowed_file_upload_extensions"), - MaxFileUploadSizeMB: ko.Float64("app.max_file_upload_size"), + MaxFileUploadSizeMB: ko.Int("app.max_file_upload_size"), } } @@ -119,6 +127,7 @@ func initFS() stuffbin.FileSystem { var files = []string{ "frontend/dist", "i18n", + "static", } // Get self executable path. @@ -133,7 +142,7 @@ func initFS() stuffbin.FileSystem { if err != nil { if err == stuffbin.ErrNoID { // The embed failed or the binary's already unstuffed or running in local / dev mode, use the local filesystem. - log.Println("unstuff failed, using local FS") + colorlog.Red("binary unstuff failed, using local filesystem for static files") fs, err = stuffbin.NewLocalFS("/", files...) if err != nil { log.Fatalf("error initializing local FS: %v", err) @@ -189,9 +198,24 @@ func initUser(i18n *i18n.I18n, DB *sqlx.DB) *user.Manager { } // initConversations inits conversation manager. -func initConversations(i18n *i18n.I18n, hub *ws.Hub, n *notifier.Service, db *sqlx.DB, contactStore *contact.Manager, - inboxStore *inbox.Manager, userStore *user.Manager, teamStore *team.Manager, mediaStore *media.Manager, automationEngine *automation.Engine, template *tmpl.Manager) *conversation.Manager { - c, err := conversation.New(hub, i18n, n, contactStore, inboxStore, userStore, teamStore, mediaStore, automationEngine, template, conversation.Opts{ +func initConversations( + i18n *i18n.I18n, + sla *sla.Manager, + status *status.Manager, + priority *priority.Manager, + hub *ws.Hub, + notif *notifier.Service, + db *sqlx.DB, + inboxStore *inbox.Manager, + userStore *user.Manager, + teamStore *team.Manager, + mediaStore *media.Manager, + settings *setting.Manager, + csat *csat.Manager, + automationEngine *automation.Engine, + template *tmpl.Manager, +) *conversation.Manager { + c, err := conversation.New(hub, i18n, notif, sla, status, priority, inboxStore, userStore, teamStore, mediaStore, settings, csat, automationEngine, template, conversation.Opts{ DB: db, Lo: initLogger("conversation_manager"), OutgoingMessageQueueSize: ko.MustInt("message.outgoing_queue_size"), @@ -203,8 +227,8 @@ func initConversations(i18n *i18n.I18n, hub *ws.Hub, n *notifier.Service, db *sq return c } -// initTags inits tag manager. -func initTags(db *sqlx.DB) *tag.Manager { +// initTag inits tag manager. +func initTag(db *sqlx.DB) *tag.Manager { var lo = initLogger("tag_manager") mgr, err := tag.New(tag.Opts{ DB: db, @@ -216,39 +240,86 @@ func initTags(db *sqlx.DB) *tag.Manager { return mgr } -// initCannedResponse inits canned response manager. -func initCannedResponse(db *sqlx.DB) *cannedresp.Manager { - var lo = initLogger("canned-response") - c, err := cannedresp.New(cannedresp.Opts{ +// initViews inits view manager. +func initView(db *sqlx.DB) *view.Manager { + var lo = initLogger("view_manager") + m, err := view.New(view.Opts{ DB: db, Lo: lo, }) if err != nil { - log.Fatalf("error initializing canned responses manager: %v", err) + log.Fatalf("error initializing view manager: %v", err) } - return c + return m } -func initContact(db *sqlx.DB) *contact.Manager { - var lo = initLogger("contact-manager") - m, err := contact.New(contact.Opts{ +// initMacro inits macro manager. +func initMacro(db *sqlx.DB) *macro.Manager { + var lo = initLogger("macro") + m, err := macro.New(macro.Opts{ DB: db, Lo: lo, }) if err != nil { - log.Fatalf("error initializing contact manager: %v", err) + log.Fatalf("error initializing macro manager: %v", err) + } + return m +} + +// initBusinessHours inits business hours manager. +func initBusinessHours(db *sqlx.DB) *businesshours.Manager { + var lo = initLogger("business-hours") + m, err := businesshours.New(businesshours.Opts{ + DB: db, + Lo: lo, + }) + if err != nil { + log.Fatalf("error initializing business hours manager: %v", err) + } + return m +} + +// initSLA inits SLA manager. +func initSLA(db *sqlx.DB, teamManager *team.Manager, settings *setting.Manager, businessHours *businesshours.Manager) *sla.Manager { + var lo = initLogger("sla") + m, err := sla.New(sla.Opts{ + DB: db, + Lo: lo, + }, teamManager, settings, businessHours) + if err != nil { + log.Fatalf("error initializing SLA manager: %v", err) + } + return m +} + +// initCSAT inits CSAT manager. +func initCSAT(db *sqlx.DB) *csat.Manager { + var lo = initLogger("csat") + m, err := csat.New(csat.Opts{ + DB: db, + Lo: lo, + }) + if err != nil { + log.Fatalf("error initializing CSAT manager: %v", err) } return m } // initTemplates inits template manager. -func initTemplate(db *sqlx.DB, fs stuffbin.FileSystem, consts constants) *tmpl.Manager { - lo := initLogger("template") - tpls, err := stuffbin.ParseTemplatesGlob(getTmplFuncs(consts), fs, "/static/email-templates/*.html") +func initTemplate(db *sqlx.DB, fs stuffbin.FileSystem, consts *constants) *tmpl.Manager { + var ( + lo = initLogger("template") + funcMap = getTmplFuncs(consts) + ) + tpls, err := stuffbin.ParseTemplatesGlob(funcMap, fs, "/static/email-templates/*.html") if err != nil { log.Fatalf("error parsing e-mail templates: %v", err) } - m, err := tmpl.New(lo, db, tpls) + webTpls, err := stuffbin.ParseTemplatesGlob(funcMap, fs, "/static/public/web-templates/*.html") + if err != nil { + log.Fatalf("error parsing web templates: %v", err) + } + m, err := tmpl.New(lo, db, webTpls, tpls, funcMap) if err != nil { log.Fatalf("error initializing template manager: %v", err) } @@ -256,11 +327,14 @@ func initTemplate(db *sqlx.DB, fs stuffbin.FileSystem, consts constants) *tmpl.M } // getTmplFuncs returns the template functions. -func getTmplFuncs(consts constants) template.FuncMap { +func getTmplFuncs(consts *constants) template.FuncMap { return template.FuncMap{ "RootURL": func() string { return consts.AppBaseURL }, + "FaviconURL": func() string { + return consts.FaviconURL + }, "Date": func(layout string) string { if layout == "" { layout = time.ANSIC @@ -276,6 +350,45 @@ func getTmplFuncs(consts constants) template.FuncMap { } } +// reloadSettings reloads the settings from the database into the Koanf instance. +func reloadSettings(app *App) error { + app.lo.Info("reloading settings") + j, err := app.setting.GetAllJSON() + if err != nil { + app.lo.Error("error parsing settings from DB", "error", err) + return err + } + var out map[string]interface{} + if err := json.Unmarshal(j, &out); err != nil { + app.lo.Error("error unmarshalling settings from DB", "error", err) + return err + } + if err := ko.Load(confmap.Provider(out, "."), nil); err != nil { + app.lo.Error("error loading settings into koanf", "error", err) + return err + } + newConsts := initConstants() + app.consts.Store(newConsts) + return nil +} + +// reloadTemplates reloads the templates from the filesystem. +func reloadTemplates(app *App) error { + app.lo.Info("reloading templates") + funcMap := getTmplFuncs(app.consts.Load().(*constants)) + tpls, err := stuffbin.ParseTemplatesGlob(funcMap, app.fs, "/static/email-templates/*.html") + if err != nil { + app.lo.Error("error parsing email templates", "error", err) + return err + } + webTpls, err := stuffbin.ParseTemplatesGlob(funcMap, app.fs, "/static/public/web-templates/*.html") + if err != nil { + app.lo.Error("error parsing web templates", "error", err) + return err + } + return app.tmpl.Reload(webTpls, tpls, funcMap) +} + // initTeam inits team manager. func initTeam(db *sqlx.DB) *team.Manager { var lo = initLogger("team-manager") @@ -307,7 +420,8 @@ func initMedia(db *sqlx.DB) *media.Manager { Region: ko.String("upload.s3.region"), Bucket: ko.String("upload.s3.bucket"), BucketPath: ko.String("upload.s3.bucket_path"), - BucketType: ko.String("upload.s3.bucket_type"), + // All files are private by default. + BucketType: "private", Expiry: ko.Duration("upload.s3.expiry"), }) if err != nil { @@ -348,15 +462,9 @@ func initInbox(db *sqlx.DB) *inbox.Manager { } // initAutomationEngine initializes the automation engine. -func initAutomationEngine(db *sqlx.DB, userManager *user.Manager) *automation.Engine { +func initAutomationEngine(db *sqlx.DB) *automation.Engine { var lo = initLogger("automation_engine") - - systemUser, err := userManager.GetSystemUser() - if err != nil { - log.Fatalf("error fetching system user: %v", err) - } - - engine, err := automation.New(systemUser, automation.Opts{ + engine, err := automation.New(automation.Opts{ DB: db, Lo: lo, }) @@ -407,11 +515,11 @@ func initEmailInbox(inboxRecord imodels.Inbox, store inbox.MessageStore) (inbox. // Load JSON data into Koanf. if err := ko.Load(rawbytes.Provider([]byte(inboxRecord.Config)), kjson.Parser()); err != nil { - log.Fatalf("error loading config: %v", err) + return nil, fmt.Errorf("loading config: %w", err) } if err := ko.UnmarshalWithConf("", &config, koanf.UnmarshalConf{Tag: "json"}); err != nil { - log.Fatalf("error unmarshalling `%s` %s config: %v", inboxRecord.Channel, inboxRecord.Name, err) + return nil, fmt.Errorf("unmarshalling `%s` %s config: %w", inboxRecord.Channel, inboxRecord.Name, err) } if len(config.SMTP) == 0 { @@ -435,11 +543,10 @@ func initEmailInbox(inboxRecord imodels.Inbox, store inbox.MessageStore) (inbox. }) if err != nil { - log.Fatalf("ERROR: initalizing `%s` inbox: `%s` error : %v", inboxRecord.Channel, inboxRecord.Name, err) - return nil, err + return nil, fmt.Errorf("initializing `%s` inbox: `%s` error : %w", inboxRecord.Channel, inboxRecord.Name, err) } - log.Printf("`%s` inbox successfully initalized. %d smtp servers. %d imap clients.", inboxRecord.Name, len(config.SMTP), len(config.IMAP)) + log.Printf("`%s` inbox successfully initialized. %d SMTP servers. %d IMAP clients.", inboxRecord.Name, len(config.SMTP), len(config.IMAP)) return inbox, nil } @@ -502,17 +609,14 @@ func initAuth(o *oidc.Manager, rd *redis.Client) *auth_.Auth { // reloadAuth reloads the auth providers. func reloadAuth(app *App) error { app.lo.Info("reloading auth manager") - providers, err := buildProviders(app.oidc) if err != nil { log.Fatalf("error reloading auth: %v", err) } - if err := app.auth.Reload(auth_.Config{Providers: providers}); err != nil { app.lo.Error("error reloading auth", "error", err) return err } - return nil } @@ -525,7 +629,7 @@ func buildProviders(o *oidc.Manager) ([]auth_.Provider, error) { providers := make([]auth_.Provider, 0, len(oidcConfigs)) for _, config := range oidcConfigs { - if config.Disabled { + if !config.Enabled { continue } providers = append(providers, auth_.Provider{ @@ -541,13 +645,12 @@ func buildProviders(o *oidc.Manager) ([]auth_.Provider, error) { } // initOIDC initializes open id connect config manager. -func initOIDC(db *sqlx.DB) *oidc.Manager { +func initOIDC(db *sqlx.DB, settings *setting.Manager) *oidc.Manager { lo := initLogger("oidc") o, err := oidc.New(oidc.Opts{ DB: db, Lo: lo, - }) - + }, settings) if err != nil { log.Fatalf("error initializing oidc: %v", err) } @@ -638,6 +741,32 @@ func initPriority(db *sqlx.DB) *priority.Manager { return manager } +// initAI inits AI manager. +func initAI(db *sqlx.DB) *ai.Manager { + lo := initLogger("ai") + m, err := ai.New(ai.Opts{ + DB: db, + Lo: lo, + }) + if err != nil { + log.Fatalf("error initializing AI manager: %v", err) + } + return m +} + +// initSearch inits search manager. +func initSearch(db *sqlx.DB) *search.Manager { + lo := initLogger("search") + m, err := search.New(search.Opts{ + DB: db, + Lo: lo, + }) + if err != nil { + log.Fatalf("error initializing search manager: %v", err) + } + return m +} + // initLogger initializes a logf logger. func initLogger(src string) *logf.Logger { lvl, env := ko.MustString("app.log_level"), ko.MustString("app.env") diff --git a/cmd/install.go b/cmd/install.go index 50bc78bc..e0689e0b 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -1,24 +1,25 @@ package main import ( + "context" "fmt" "log" "strings" - "github.com/abhinavxd/artemis/internal/user" + "github.com/abhinavxd/libredesk/internal/user" "github.com/jmoiron/sqlx" "github.com/knadh/stuffbin" "github.com/lib/pq" ) // install checks if the schema is already installed, prompts for confirmation, and installs the schema if needed. -func install(db *sqlx.DB, fs stuffbin.FileSystem) error { +func install(ctx context.Context, db *sqlx.DB, fs stuffbin.FileSystem) error { installed, err := checkSchema(db) if err != nil { log.Fatalf("error checking db schema: %v", err) } if installed { - fmt.Printf("\033[31m** WARNING: This will wipe your entire DB - '%s' **\033[0m\n", ko.String("db.database")) + fmt.Printf("\033[31m** WARNING: This will wipe your entire database - '%s' **\033[0m\n", ko.String("db.database")) fmt.Print("Continue (y/n)? ") var ok string fmt.Scanf("%s", &ok) @@ -35,15 +36,15 @@ func install(db *sqlx.DB, fs stuffbin.FileSystem) error { log.Println("Schema installed successfully") // Create system user. - if err := user.CreateSystemUser(db); err != nil { + if err := user.CreateSystemUser(ctx, db); err != nil { log.Fatalf("error creating system user: %v", err) } return nil } // setSystemUserPass prompts for pass and sets system user password. -func setSystemUserPass(db *sqlx.DB) { - user.ChangeSystemUserPassword(db) +func setSystemUserPass(ctx context.Context, db *sqlx.DB) { + user.ChangeSystemUserPassword(ctx, db) } // checkSchema verifies if the DB schema is already installed by querying a table. diff --git a/cmd/login.go b/cmd/login.go index 22c62359..05903c1f 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -1,12 +1,13 @@ package main import ( - "github.com/abhinavxd/artemis/internal/envelope" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) -// handleLogin logs in the user. +// handleLogin logs a user in. func handleLogin(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -14,11 +15,16 @@ func handleLogin(r *fastglue.Request) error { email = string(p.Peek("email")) password = p.Peek("password") ) - user, err := app.user.Login(email, password) + user, err := app.user.VerifyPassword(email, password) if err != nil { return sendErrorEnvelope(r, err) } - if err := app.auth.SaveSession(user, r); err != nil { + if err := app.auth.SaveSession(amodels.User{ + ID: user.ID, + Email: user.Email.String, + FirstName: user.FirstName, + LastName: user.LastName, + }, r); err != nil { app.lo.Error("error saving session", "error", err) return sendErrorEnvelope(r, envelope.NewError(envelope.GeneralError, app.i18n.T("user.errorAcquiringSession"), nil)) } @@ -44,5 +50,5 @@ func handleLogout(r *fastglue.Request) error { "no-store, no-cache, must-revalidate, post-check=0, pre-check=0") r.RequestCtx.Response.Header.Add("Pragma", "no-cache") r.RequestCtx.Response.Header.Add("Expires", "-1") - return r.RedirectURI("dashboard", fasthttp.StatusFound, nil, "") + return r.RedirectURI("/", fasthttp.StatusFound, nil, "") } diff --git a/cmd/macro.go b/cmd/macro.go new file mode 100644 index 00000000..6278230a --- /dev/null +++ b/cmd/macro.go @@ -0,0 +1,306 @@ +package main + +import ( + "encoding/json" + "fmt" + "slices" + "strconv" + + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + autoModels "github.com/abhinavxd/libredesk/internal/automation/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/macro/models" + "github.com/valyala/fasthttp" + "github.com/zerodha/fastglue" +) + +// handleGetMacros returns all macros. +func handleGetMacros(r *fastglue.Request) error { + var app = r.Context.(*App) + macros, err := app.macro.GetAll() + if err != nil { + return sendErrorEnvelope(r, err) + } + for i, m := range macros { + var actions []autoModels.RuleAction + if err := json.Unmarshal(m.Actions, &actions); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error unmarshalling macro actions", nil, envelope.GeneralError) + } + // Set display values for actions as the value field can contain DB IDs + if err := setDisplayValues(app, actions); err != nil { + app.lo.Warn("error setting display values", "error", err) + } + if macros[i].Actions, err = json.Marshal(actions); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "marshal failed", nil, envelope.GeneralError) + } + } + return r.SendEnvelope(macros) +} + +// handleGetMacro returns a macro. +func handleGetMacro(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + id, err = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + ) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, + "Invalid macro `id`.", nil, envelope.InputError) + } + + macro, err := app.macro.Get(id) + if err != nil { + return sendErrorEnvelope(r, err) + } + + var actions []autoModels.RuleAction + if err := json.Unmarshal(macro.Actions, &actions); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error unmarshalling macro actions", nil, envelope.GeneralError) + } + // Set display values for actions as the value field can contain DB IDs + if err := setDisplayValues(app, actions); err != nil { + app.lo.Warn("error setting display values", "error", err) + } + if macro.Actions, err = json.Marshal(actions); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "marshal failed", nil, envelope.GeneralError) + } + + return r.SendEnvelope(macro) +} + +// handleCreateMacro creates new macro. +func handleCreateMacro(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + macro = models.Macro{} + ) + + if err := r.Decode(¯o, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + + if err := validateMacro(macro); err != nil { + return sendErrorEnvelope(r, err) + } + + err := app.macro.Create(macro.Name, macro.MessageContent, macro.UserID, macro.TeamID, macro.Visibility, macro.Actions) + if err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(macro) +} + +// handleUpdateMacro updates a macro. +func handleUpdateMacro(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + macro = models.Macro{} + ) + + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, + "Invalid macro `id`.", nil, envelope.InputError) + } + + if err := r.Decode(¯o, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + + if err := validateMacro(macro); err != nil { + return sendErrorEnvelope(r, err) + } + + if err = app.macro.Update(id, macro.Name, macro.MessageContent, macro.UserID, macro.TeamID, macro.Visibility, macro.Actions); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(macro) +} + +// handleDeleteMacro deletes macro. +func handleDeleteMacro(r *fastglue.Request) error { + var app = r.Context.(*App) + + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, + "Invalid macro `id`.", nil, envelope.InputError) + } + + if err := app.macro.Delete(id); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope("Macro deleted successfully") +} + +// handleApplyMacro applies macro actions to a conversation. +func handleApplyMacro(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + conversationUUID = r.RequestCtx.UserValue("uuid").(string) + id, _ = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + incomingActions = []autoModels.RuleAction{} + ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + // Enforce conversation access. + conversation, err := app.conversation.GetConversation(0, conversationUUID) + if err != nil { + return sendErrorEnvelope(r, err) + } + if allowed, err := app.authz.EnforceConversationAccess(user, conversation); err != nil || !allowed { + return sendErrorEnvelope(r, envelope.NewError(envelope.PermissionError, "Permission denied", nil)) + } + + macro, err := app.macro.Get(id) + if err != nil { + return sendErrorEnvelope(r, err) + } + + // Decode incoming actions. + if err := r.Decode(&incomingActions, "json"); err != nil { + app.lo.Error("error unmashalling incoming actions", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Failed to decode incoming actions", nil, envelope.InputError) + } + + // Make sure no duplicate action types are present. + actionTypes := make(map[string]bool, len(incomingActions)) + for _, act := range incomingActions { + if actionTypes[act.Type] { + app.lo.Warn("duplicate action types found in macro apply apply request", "action", act.Type, "user_id", user.ID) + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Duplicate actions are not allowed", nil, envelope.InputError) + } + actionTypes[act.Type] = true + } + + // Validate action permissions. + for _, act := range incomingActions { + if !isMacroActionAllowed(act.Type) { + app.lo.Warn("action not allowed in macro", "action", act.Type, "user_id", user.ID) + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "Action not allowed in macro", nil, envelope.PermissionError) + } + if !hasActionPermission(act.Type, user.Permissions) { + app.lo.Warn("no permission to execute macro action", "action", act.Type, "user_id", user.ID) + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "No permission to execute this macro", nil, envelope.PermissionError) + } + } + + // Apply actions. + successCount := 0 + for _, act := range incomingActions { + if err := app.conversation.ApplyAction(act, conversation, user); err == nil { + successCount++ + } + } + + if successCount == 0 { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Failed to apply macro", nil, envelope.GeneralError) + } + + // Increment usage count. + app.macro.IncrementUsageCount(macro.ID) + + if successCount < len(incomingActions) { + return r.SendJSON(fasthttp.StatusMultiStatus, map[string]interface{}{ + "message": fmt.Sprintf("Macro executed with errors. %d actions succeeded out of %d", successCount, len(incomingActions)), + }) + } + + return r.SendJSON(fasthttp.StatusOK, map[string]interface{}{ + "message": "Macro applied successfully", + }) +} + +// hasActionPermission checks user permission for given action +func hasActionPermission(action string, userPerms []string) bool { + requiredPerm, exists := autoModels.ActionPermissions[action] + if !exists { + return false + } + return slices.Contains(userPerms, requiredPerm) +} + +// setDisplayValues sets display values for actions. +func setDisplayValues(app *App, actions []autoModels.RuleAction) error { + getters := map[string]func(int) (string, error){ + autoModels.ActionAssignTeam: func(id int) (string, error) { + t, err := app.team.Get(id) + if err != nil { + app.lo.Warn("team not found for macro action", "team_id", id) + return "", err + } + return t.Name, nil + }, + autoModels.ActionAssignUser: func(id int) (string, error) { + u, err := app.user.Get(id) + if err != nil { + app.lo.Warn("user not found for macro action", "user_id", id) + return "", err + } + return u.FullName(), nil + }, + autoModels.ActionSetPriority: func(id int) (string, error) { + p, err := app.priority.Get(id) + if err != nil { + app.lo.Warn("priority not found for macro action", "priority_id", id) + return "", err + } + return p.Name, nil + }, + autoModels.ActionSetStatus: func(id int) (string, error) { + s, err := app.status.Get(id) + if err != nil { + app.lo.Warn("status not found for macro action", "status_id", id) + return "", err + } + return s.Name, nil + }, + } + for i := range actions { + actions[i].DisplayValue = []string{} + if getter, ok := getters[actions[i].Type]; ok { + id, _ := strconv.Atoi(actions[i].Value[0]) + if name, err := getter(id); err == nil { + actions[i].DisplayValue = append(actions[i].DisplayValue, name) + } + } + } + return nil +} + +// validateMacro validates an incoming macro. +func validateMacro(macro models.Macro) error { + if macro.Name == "" { + return envelope.NewError(envelope.InputError, "Empty macro `name`", nil) + } + + var act []autoModels.RuleAction + if err := json.Unmarshal(macro.Actions, &act); err != nil { + return envelope.NewError(envelope.InputError, "Could not parse macro actions", nil) + } + for _, a := range act { + if len(a.Value) == 0 { + return envelope.NewError(envelope.InputError, fmt.Sprintf("Empty value for action: %s", a.Type), nil) + } + } + return nil +} + +// isMacroActionAllowed returns true if the action is allowed in a macro. +func isMacroActionAllowed(action string) bool { + switch action { + case autoModels.ActionSendPrivateNote, autoModels.ActionReply: + return false + case autoModels.ActionAssignTeam, autoModels.ActionAssignUser, autoModels.ActionSetStatus, autoModels.ActionSetPriority, autoModels.ActionSetTags: + return true + default: + return false + } +} diff --git a/cmd/main.go b/cmd/main.go index 12abde60..10e5c6af 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -6,28 +6,35 @@ import ( "log" "os" "os/signal" + "sync/atomic" "syscall" - auth_ "github.com/abhinavxd/artemis/internal/auth" - "github.com/abhinavxd/artemis/internal/authz" - notifier "github.com/abhinavxd/artemis/internal/notification" + "github.com/abhinavxd/libredesk/internal/ai" + auth_ "github.com/abhinavxd/libredesk/internal/auth" + "github.com/abhinavxd/libredesk/internal/authz" + businesshours "github.com/abhinavxd/libredesk/internal/business_hours" + "github.com/abhinavxd/libredesk/internal/colorlog" + "github.com/abhinavxd/libredesk/internal/csat" + "github.com/abhinavxd/libredesk/internal/macro" + notifier "github.com/abhinavxd/libredesk/internal/notification" + "github.com/abhinavxd/libredesk/internal/search" + "github.com/abhinavxd/libredesk/internal/sla" + "github.com/abhinavxd/libredesk/internal/view" - "github.com/abhinavxd/artemis/internal/automation" - "github.com/abhinavxd/artemis/internal/cannedresp" - "github.com/abhinavxd/artemis/internal/contact" - "github.com/abhinavxd/artemis/internal/conversation" - "github.com/abhinavxd/artemis/internal/conversation/priority" - "github.com/abhinavxd/artemis/internal/conversation/status" - "github.com/abhinavxd/artemis/internal/inbox" - "github.com/abhinavxd/artemis/internal/media" - "github.com/abhinavxd/artemis/internal/oidc" - "github.com/abhinavxd/artemis/internal/role" - "github.com/abhinavxd/artemis/internal/setting" - "github.com/abhinavxd/artemis/internal/tag" - "github.com/abhinavxd/artemis/internal/team" - "github.com/abhinavxd/artemis/internal/template" - "github.com/abhinavxd/artemis/internal/user" - "github.com/abhinavxd/artemis/internal/ws" + "github.com/abhinavxd/libredesk/internal/automation" + "github.com/abhinavxd/libredesk/internal/conversation" + "github.com/abhinavxd/libredesk/internal/conversation/priority" + "github.com/abhinavxd/libredesk/internal/conversation/status" + "github.com/abhinavxd/libredesk/internal/inbox" + "github.com/abhinavxd/libredesk/internal/media" + "github.com/abhinavxd/libredesk/internal/oidc" + "github.com/abhinavxd/libredesk/internal/role" + "github.com/abhinavxd/libredesk/internal/setting" + "github.com/abhinavxd/libredesk/internal/tag" + "github.com/abhinavxd/libredesk/internal/team" + "github.com/abhinavxd/libredesk/internal/template" + "github.com/abhinavxd/libredesk/internal/user" + "github.com/abhinavxd/libredesk/internal/ws" "github.com/knadh/go-i18n" "github.com/knadh/koanf/v2" "github.com/knadh/stuffbin" @@ -38,44 +45,64 @@ import ( var ( ko = koanf.New(".") - frontendDir = "frontend/dist" ctx = context.Background() - buildString string + appName = "libredesk" + frontendDir = "frontend/dist" + + // Injected at build time. + buildString = "" ) // App is the global app context which is passed and injected in the http handlers. type App struct { - consts constants - fs stuffbin.FileSystem - auth *auth_.Auth - authz *authz.Enforcer - i18n *i18n.I18n - lo *logf.Logger - oidc *oidc.Manager - media *media.Manager - setting *setting.Manager - role *role.Manager - contact *contact.Manager - user *user.Manager - team *team.Manager - status *status.Manager - priority *priority.Manager - tag *tag.Manager - inbox *inbox.Manager - tmpl *template.Manager - cannedResp *cannedresp.Manager - conversation *conversation.Manager - automation *automation.Engine - notifier *notifier.Service + fs stuffbin.FileSystem + consts atomic.Value + auth *auth_.Auth + authz *authz.Enforcer + i18n *i18n.I18n + lo *logf.Logger + oidc *oidc.Manager + media *media.Manager + setting *setting.Manager + role *role.Manager + user *user.Manager + team *team.Manager + status *status.Manager + priority *priority.Manager + tag *tag.Manager + inbox *inbox.Manager + tmpl *template.Manager + macro *macro.Manager + conversation *conversation.Manager + automation *automation.Engine + businessHours *businesshours.Manager + sla *sla.Manager + csat *csat.Manager + view *view.Manager + ai *ai.Manager + search *search.Manager + notifier *notifier.Service } func main() { // Set up signal handler. - ctx, _ = signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + defer stop() // Load command line flags into Koanf. initFlags() + // Version flag. + if ko.Bool("version") { + fmt.Println(buildString) + os.Exit(0) + } + + // Build string injected at build time. + if buildString != "" { + colorlog.Green("Build: %s", buildString) + } + // Load the config files into Koanf. initConfig(ko) @@ -85,23 +112,15 @@ func main() { // Init DB. db := initDB() - // Version flag. - if ko.Bool("version") { - fmt.Println(buildString) - os.Exit(0) - } - - log.Printf("Build: %s", buildString) - // Installer. if ko.Bool("install") { - install(db, fs) + install(ctx, db, fs) os.Exit(0) } // Set system user password. if ko.Bool("set-system-user-password") { - setSystemUserPass(db) + setSystemUserPass(ctx, db) os.Exit(0) } @@ -120,85 +139,83 @@ func main() { loadSettings(settings) var ( - automationWrk = ko.MustInt("automation.worker_count") - messageDispatchWrk = ko.MustInt("message.dispatch_workers") - messageDispatchScanInterval = ko.MustDuration("message.dispatch_scan_interval") - lo = initLogger("artemis") + autoAssignInterval = ko.MustDuration("autoassigner.autoassign_interval") + unsnoozeInterval = ko.MustDuration("conversation.unsnooze_interval") + automationWorkers = ko.MustInt("automation.worker_count") + messageOutgoingQWorkers = ko.MustDuration("message.outgoing_queue_workers") + messageIncomingQWorkers = ko.MustDuration("message.incoming_queue_workers") + messageOutgoingScanInterval = ko.MustDuration("message.message_outoing_scan_interval") + slaEvaluationInterval = ko.MustDuration("sla.evaluation_interval") + lo = initLogger(appName) wsHub = ws.NewHub() rdb = initRedis() constants = initConstants() i18n = initI18n(fs) - oidc = initOIDC(db) + csat = initCSAT(db) + oidc = initOIDC(db, settings) + status = initStatus(db) + priority = initPriority(db) auth = initAuth(oidc, rdb) template = initTemplate(db, fs, constants) media = initMedia(db) - contact = initContact(db) inbox = initInbox(db) team = initTeam(db) + businessHours = initBusinessHours(db) user = initUser(i18n, db) notifier = initNotifier(user) - automation = initAutomationEngine(db, user) - conversation = initConversations(i18n, wsHub, notifier, db, contact, inbox, user, team, media, automation, template) + automation = initAutomationEngine(db) + sla = initSLA(db, team, settings, businessHours) + conversation = initConversations(i18n, sla, status, priority, wsHub, notifier, db, inbox, user, team, media, settings, csat, automation, template) autoassigner = initAutoAssigner(team, user, conversation) ) - - // Set stores. - wsHub.SetConversationStore(conversation) automation.SetConversationStore(conversation) - // Start inbox receivers. startInboxes(ctx, inbox, conversation) - - // Start evaluating automation rules. - go automation.Run(ctx, automationWrk) - - // Start conversation auto assigner. - go autoassigner.Run(ctx) - - // Start processing incoming and outgoing messages. - go conversation.Run(ctx, messageDispatchWrk, messageDispatchScanInterval) - - // Start notifier. + go automation.Run(ctx, automationWorkers) + go autoassigner.Run(ctx, autoAssignInterval) + go conversation.Run(ctx, messageIncomingQWorkers, messageOutgoingQWorkers, messageOutgoingScanInterval) + go conversation.RunUnsnoozer(ctx, unsnoozeInterval) go notifier.Run(ctx) + go sla.Run(ctx, slaEvaluationInterval) + go media.DeleteUnlinkedMedia(ctx) - // Delete media not linked to any message. - go media.DeleteUnlinkedMessageMedia(ctx) - - // Init the app var app = &App{ - lo: lo, - auth: auth, - fs: fs, - i18n: i18n, - media: media, - setting: settings, - contact: contact, - inbox: inbox, - user: user, - team: team, - tmpl: template, - conversation: conversation, - automation: automation, - oidc: oidc, - consts: constants, - notifier: notifier, - authz: initAuthz(), - status: initStatus(db), - priority: initPriority(db), - role: initRole(db), - tag: initTags(db), - cannedResp: initCannedResponse(db), + lo: lo, + fs: fs, + sla: sla, + oidc: oidc, + i18n: i18n, + auth: auth, + media: media, + setting: settings, + inbox: inbox, + user: user, + team: team, + status: status, + priority: priority, + tmpl: template, + notifier: notifier, + consts: atomic.Value{}, + conversation: conversation, + automation: automation, + businessHours: businessHours, + authz: initAuthz(), + view: initView(db), + csat: initCSAT(db), + search: initSearch(db), + role: initRole(db), + tag: initTag(db), + macro: initMacro(db), + ai: initAI(db), } + app.consts.Store(constants) - // Init fastglue and set app in ctx. g := fastglue.NewGlue() g.SetContext(app) - - // Init HTTP handlers. initHandlers(g, wsHub) s := &fasthttp.Server{ - Name: "server", + Name: appName, ReadTimeout: ko.MustDuration("app.server.read_timeout"), WriteTimeout: ko.MustDuration("app.server.write_timeout"), MaxRequestBodySize: ko.MustInt("app.server.max_body_size"), @@ -206,24 +223,35 @@ func main() { ReadBufferSize: ko.MustInt("app.server.max_body_size"), } - log.Printf("%s🚀 server listening on %s %s\x1b[0m", "\x1b[32m", ko.String("app.server.address"), ko.String("app.server.socket")) - go func() { + colorlog.Green("Server started at %s", ko.String("app.server.address")) + if ko.String("server.socket") != "" { + colorlog.Green("Unix socket created at %s", ko.String("server.socket")) + } if err := g.ListenAndServe(ko.String("app.server.address"), ko.String("server.socket"), s); err != nil { log.Fatalf("error starting server: %v", err) } }() + // Wait for shutdown signal. <-ctx.Done() - log.Printf("%sShutting down the server. Please wait.\x1b[0m", "\x1b[31m") - // Shutdown HTTP server. + colorlog.Red("Shutting down HTTP server...") s.Shutdown() - // Shutdown services. + colorlog.Red("Shutting down inboxes...") inbox.Close() + colorlog.Red("Shutting down automation...") automation.Close() + colorlog.Red("Shutting down autoassigner...") autoassigner.Close() + colorlog.Red("Shutting down notifier...") notifier.Close() + colorlog.Red("Shutting down conversation...") conversation.Close() + colorlog.Red("Shutting down SLA...") + sla.Close() + colorlog.Red("Shutting down database...") db.Close() + colorlog.Red("Shutting down redis...") rdb.Close() + colorlog.Green("Shutdown complete.") } diff --git a/cmd/media.go b/cmd/media.go index 0c8448f9..b24c9566 100644 --- a/cmd/media.go +++ b/cmd/media.go @@ -9,19 +9,19 @@ import ( "slices" - "github.com/abhinavxd/artemis/internal/attachment" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/image" - "github.com/abhinavxd/artemis/internal/stringutil" - umodels "github.com/abhinavxd/artemis/internal/user/models" + "github.com/abhinavxd/libredesk/internal/attachment" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/image" + "github.com/abhinavxd/libredesk/internal/stringutil" "github.com/google/uuid" "github.com/valyala/fasthttp" + "github.com/volatiletech/null/v9" "github.com/zerodha/fastglue" ) const ( - thumbPrefix = "thumb_" - thumbnailSize = 150 + thumbPrefix = "thumb_" ) func handleMediaUpload(r *fastglue.Request) error { @@ -50,10 +50,10 @@ func handleMediaUpload(r *fastglue.Request) error { defer file.Close() // Inline? - var disposition = attachment.DispositionAttachment + var disposition = null.StringFrom(attachment.DispositionAttachment) inline, ok := form.Value["inline"] if ok && len(inline) > 0 && inline[0] == "true" { - disposition = attachment.DispositionInline + disposition = null.StringFrom(attachment.DispositionInline) } // Linked model? @@ -70,17 +70,18 @@ func handleMediaUpload(r *fastglue.Request) error { srcExt := strings.TrimPrefix(strings.ToLower(filepath.Ext(srcFileName)), ".") // Check file size - if bytesToMegabytes(srcFileSize) > app.consts.MaxFileUploadSizeMB { - app.lo.Error("error: uploaded file size is larger than max allowed", "size", bytesToMegabytes(srcFileSize), "max_allowed", app.consts.MaxFileUploadSizeMB) + consts := app.consts.Load().(*constants) + if bytesToMegabytes(srcFileSize) > float64(consts.MaxFileUploadSizeMB) { + app.lo.Error("error: uploaded file size is larger than max allowed", "size", bytesToMegabytes(srcFileSize), "max_allowed", consts.MaxFileUploadSizeMB) return r.SendErrorEnvelope( http.StatusRequestEntityTooLarge, - fmt.Sprintf("File size is too large. Please upload file lesser than %f MB", app.consts.MaxFileUploadSizeMB), + fmt.Sprintf("File size is too large. Please upload file lesser than %d MB", consts.MaxFileUploadSizeMB), nil, envelope.GeneralError, ) } - if !slices.Contains(app.consts.AllowedUploadFileExtensions, "*") && !slices.Contains(app.consts.AllowedUploadFileExtensions, srcExt) { + if !slices.Contains(consts.AllowedUploadFileExtensions, "*") && !slices.Contains(consts.AllowedUploadFileExtensions, srcExt) { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "File type not allowed", nil, envelope.InputError) } @@ -94,11 +95,11 @@ func handleMediaUpload(r *fastglue.Request) error { } }() - // Generate and upload thumbnail and save it's dimensions if it's an image. + // Generate and upload thumbnail and store image dimensions in the media meta. var meta = []byte("{}") if slices.Contains(image.Exts, srcExt) { file.Seek(0, 0) - thumbFile, err := image.CreateThumb(thumbnailSize, file) + thumbFile, err := image.CreateThumb(image.DefThumbSize, file) if err != nil { app.lo.Error("error creating thumb image", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error creating image thumbnail", nil, envelope.GeneralError) @@ -109,7 +110,7 @@ func handleMediaUpload(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - // Store image dimensions in the media meta. + // Store image dimensions in media meta, storing dimensions for image previews in future. file.Seek(0, 0) width, height, err := image.GetDimensions(file) if err != nil { @@ -121,7 +122,6 @@ func handleMediaUpload(r *fastglue.Request) error { "width": width, "height": height, }) - } file.Seek(0, 0) @@ -133,7 +133,7 @@ func handleMediaUpload(r *fastglue.Request) error { } // Insert in DB. - media, err := app.media.Insert(srcFileName, srcContentType, "" /**content_id**/, linkedModel, disposition, uuid.String(), 0, int(srcFileSize), meta) + media, err := app.media.Insert(disposition, srcFileName, srcContentType, "" /**content_id**/, null.NewString(linkedModel, linkedModel != ""), uuid.String(), null.Int{} /**model_id**/, int(srcFileSize), meta) if err != nil { cleanUp = true app.lo.Error("error inserting metadata into database", "error", err) @@ -145,11 +145,16 @@ func handleMediaUpload(r *fastglue.Request) error { // handleServeMedia serves uploaded media. func handleServeMedia(r *fastglue.Request) error { var ( - app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) - uuid = r.RequestCtx.UserValue("uuid").(string) + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + uuid = r.RequestCtx.UserValue("uuid").(string) ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + // Fetch media from DB. media, err := app.media.GetByUUID(strings.TrimPrefix(uuid, thumbPrefix)) if err != nil { @@ -178,8 +183,8 @@ func handleServeMedia(r *fastglue.Request) error { if !allowed { return r.SendErrorEnvelope(http.StatusUnauthorized, "Permission denied", nil, envelope.PermissionError) } - - switch app.consts.UploadProvider { + consts := app.consts.Load().(*constants) + switch consts.UploadProvider { case "fs": fasthttp.ServeFile(r.RequestCtx, filepath.Join(ko.String("upload.fs.upload_path"), uuid)) case "s3": diff --git a/cmd/messages.go b/cmd/messages.go index acf87efe..11e531f3 100644 --- a/cmd/messages.go +++ b/cmd/messages.go @@ -3,18 +3,20 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/automation/models" - "github.com/abhinavxd/artemis/internal/envelope" - medModels "github.com/abhinavxd/artemis/internal/media/models" - umodels "github.com/abhinavxd/artemis/internal/user/models" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/automation/models" + "github.com/abhinavxd/libredesk/internal/envelope" + medModels "github.com/abhinavxd/libredesk/internal/media/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) type messageReq struct { - Attachments []int `json:"attachments"` - Message string `json:"message"` - Private bool `json:"private"` + Attachments []int `json:"attachments"` + Message string `json:"message"` + Private bool `json:"private"` + CC []string `json:"cc"` + BCC []string `json:"bcc"` } // handleGetMessages returns messages for a conversation. @@ -22,14 +24,19 @@ func handleGetMessages(r *fastglue.Request) error { var ( app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + auser = r.RequestCtx.UserValue("user").(amodels.User) page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) total = 0 ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + // Check permission - _, err := enforceConversationAccess(app, uuid, user) + _, err = enforceConversationAccess(app, uuid, user) if err != nil { return sendErrorEnvelope(r, err) } @@ -44,6 +51,7 @@ func handleGetMessages(r *fastglue.Request) error { for j := range messages[i].Attachments { messages[i].Attachments[j].URL = app.media.GetURL(messages[i].Attachments[j].UUID) } + messages[i].CensorCSATContent() } return r.SendEnvelope(envelope.PageResults{ Total: total, @@ -60,25 +68,32 @@ func handleGetMessage(r *fastglue.Request) error { app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) cuuid = r.RequestCtx.UserValue("cuuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } // Check permission - _, err := enforceConversationAccess(app, cuuid, user) + _, err = enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } - messages, err := app.conversation.GetMessage(uuid) + message, err := app.conversation.GetMessage(uuid) if err != nil { return sendErrorEnvelope(r, err) } - for j := range messages.Attachments { - messages.Attachments[j].URL = app.media.GetURL(messages.Attachments[j].UUID) + // Redact CSAT survey link + message.CensorCSATContent() + + for j := range message.Attachments { + message.Attachments[j].URL = app.media.GetURL(message.Attachments[j].UUID) } - return r.SendEnvelope(messages) + return r.SendEnvelope(message) } // handleRetryMessage changes message status so it can be retried for sending. @@ -87,11 +102,16 @@ func handleRetryMessage(r *fastglue.Request) error { app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) cuuid = r.RequestCtx.UserValue("cuuid").(string) - user = r.RequestCtx.UserValue("user").(umodels.User) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + // Check permission - _, err := enforceConversationAccess(app, cuuid, user) + _, err = enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } @@ -106,48 +126,54 @@ func handleRetryMessage(r *fastglue.Request) error { // handleSendMessage sends a message in a conversation. func handleSendMessage(r *fastglue.Request) error { var ( - app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) - cuuid = r.RequestCtx.UserValue("cuuid").(string) - req = messageReq{} + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + cuuid = r.RequestCtx.UserValue("cuuid").(string) media = []medModels.Media{} + req = messageReq{} ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + // Check permission - _, err := enforceConversationAccess(app, cuuid, user) + _, err = enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } if err := r.Decode(&req, "json"); err != nil { - app.lo.Error("error unmarshalling media ids", "error", err) - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "error decoding request", nil, "") + app.lo.Error("error unmarshalling message request", "error", err) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "error decoding request", nil, envelope.GeneralError) } for _, id := range req.Attachments { m, err := app.media.Get(id) if err != nil { app.lo.Error("error fetching media", "error", err) - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error fetching media", nil, "") + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error fetching media", nil, envelope.GeneralError) } media = append(media, m) } - // Private note. if req.Private { if err := app.conversation.SendPrivateNote(media, user.ID, cuuid, req.Message); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + } else { + if err := app.conversation.SendReply(media, user.ID, cuuid, req.Message, req.CC, req.BCC, map[string]interface{}{}); err != nil { + return sendErrorEnvelope(r, err) + } + // Evaluate automation rules. + app.automation.EvaluateConversationUpdateRules(cuuid, models.EventConversationMessageOutgoing) } - // Reply. - if err := app.conversation.SendReply(media, user.ID, cuuid, req.Message); err != nil { + // Reopen if snoozed/closed/resolved regardless of automation rules - this is the default behavior + if err := app.conversation.ReOpenConversation(cuuid, user); err != nil { return sendErrorEnvelope(r, err) } - // Evaluate automation rules. - app.automation.EvaluateConversationUpdateRules(cuuid, models.EventConversationMessageOutgoing) - - return r.SendEnvelope(true) + return r.SendEnvelope("Message sent successfully") } diff --git a/cmd/middlewares.go b/cmd/middlewares.go index e65a24ff..378e2875 100644 --- a/cmd/middlewares.go +++ b/cmd/middlewares.go @@ -2,8 +2,10 @@ package main import ( "net/http" + "strings" - "github.com/abhinavxd/artemis/internal/envelope" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) @@ -27,7 +29,12 @@ func tryAuth(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler { } // Set user in context if found. - r.RequestCtx.SetUserValue("user", user) + r.RequestCtx.SetUserValue("user", amodels.User{ + ID: user.ID, + Email: user.Email.String, + FirstName: user.FirstName, + LastName: user.LastName, + }) return handler(r) } @@ -52,14 +59,19 @@ func auth(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler { if err != nil { return sendErrorEnvelope(r, err) } - r.RequestCtx.SetUserValue("user", user) + r.RequestCtx.SetUserValue("user", amodels.User{ + ID: user.ID, + Email: user.Email.String, + FirstName: user.FirstName, + LastName: user.LastName, + }) return handler(r) } } -// authPerm does session validation, CSRF, and permission enforcement. -func authPerm(handler fastglue.FastRequestHandler, object, action string) fastglue.FastRequestHandler { +// perm does session validation, CSRF, and permission enforcement. +func perm(handler fastglue.FastRequestHandler, perm string) fastglue.FastRequestHandler { return func(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -73,30 +85,39 @@ func authPerm(handler fastglue.FastRequestHandler, object, action string) fastgl } // Validate session and fetch user. - userSession, err := app.auth.ValidateSession(r) - if err != nil || userSession.ID <= 0 { + sessUser, err := app.auth.ValidateSession(r) + if err != nil || sessUser.ID <= 0 { app.lo.Error("error validating session", "error", err) return r.SendErrorEnvelope(http.StatusUnauthorized, "Invalid or expired session", nil, envelope.PermissionError) } - user, err := app.user.Get(userSession.ID) + // Get user from DB. + user, err := app.user.Get(sessUser.ID) if err != nil { return sendErrorEnvelope(r, err) } - // Permission enforcement. - if object != "" && action != "" { - ok, err := app.authz.Enforce(user, object, action) - if err != nil { - return r.SendErrorEnvelope(http.StatusInternalServerError, "Error checking permissions", nil, envelope.GeneralError) - } - if !ok { - return r.SendErrorEnvelope(http.StatusForbidden, "Permission denied", nil, envelope.PermissionError) - } + // Split the permission string into object and action and enforce it. + parts := strings.Split(perm, ":") + if len(parts) != 2 { + return r.SendErrorEnvelope(http.StatusInternalServerError, "Invalid permission format", nil, envelope.GeneralError) + } + object, action := parts[0], parts[1] + ok, err := app.authz.Enforce(user, object, action) + if err != nil { + return r.SendErrorEnvelope(http.StatusInternalServerError, "Error checking permissions", nil, envelope.GeneralError) + } + if !ok { + return r.SendErrorEnvelope(http.StatusForbidden, "Permission denied", nil, envelope.PermissionError) } // Set user in the request context. - r.RequestCtx.SetUserValue("user", user) + r.RequestCtx.SetUserValue("user", amodels.User{ + ID: user.ID, + Email: user.Email.String, + FirstName: user.FirstName, + LastName: user.LastName, + }) return handler(r) } @@ -127,7 +148,7 @@ func authPage(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler { } } -// notAuthPage allows access only if the user is not authenticated; otherwise, redirects to the dashboard. +// notAuthPage allows access only if the user is not authenticated; otherwise, redirects to the user inbox. func notAuthPage(handler fastglue.FastRequestHandler) fastglue.FastRequestHandler { return func(r *fastglue.Request) error { app := r.Context.(*App) @@ -142,7 +163,7 @@ func notAuthPage(handler fastglue.FastRequestHandler) fastglue.FastRequestHandle if user.ID != 0 { nextURI := string(r.RequestCtx.QueryArgs().Peek("next")) if nextURI == "" { - nextURI = "/dashboard" + nextURI = "/inboxes/assigned" } return r.RedirectURI(nextURI, fasthttp.StatusFound, nil, "") } diff --git a/cmd/oidc.go b/cmd/oidc.go index dacf8c4c..2dcfdbd9 100644 --- a/cmd/oidc.go +++ b/cmd/oidc.go @@ -1,18 +1,23 @@ package main import ( - "fmt" "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/oidc/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/oidc/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) -const ( - redirectURI = "/api/oidc/finish?id=%d" -) +// handleGetAllEnabledOIDC returns all enabled OIDC records +func handleGetAllEnabledOIDC(r *fastglue.Request) error { + app := r.Context.(*App) + out, err := app.oidc.GetAllEnabled() + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(out) +} // handleGetAllOIDC returns all OIDC records func handleGetAllOIDC(r *fastglue.Request) error { @@ -26,21 +31,16 @@ func handleGetAllOIDC(r *fastglue.Request) error { // handleGetOIDC returns an OIDC record by id. func handleGetOIDC(r *fastglue.Request) error { - app := r.Context.(*App) - + var app = r.Context.(*App) id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) if err != nil || id <= 0 { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid OIDC `id`", nil, envelope.InputError) } - - o, err := app.oidc.Get(id) + o, err := app.oidc.Get(id, false) if err != nil { return sendErrorEnvelope(r, err) } - - o.RedirectURI = fmt.Sprintf("%s%s", app.consts.AppBaseURL, fmt.Sprintf(redirectURI, o.ID)) - return r.SendEnvelope(o) } @@ -61,7 +61,7 @@ func handleCreateOIDC(r *fastglue.Request) error { if err := reloadAuth(app); err != nil { return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error reloading auth", nil, envelope.GeneralError) } - return r.SendEnvelope(true) + return r.SendEnvelope("OIDC created successfully") } func handleUpdateOIDC(r *fastglue.Request) error { @@ -86,9 +86,9 @@ func handleUpdateOIDC(r *fastglue.Request) error { // Reload the auth manager to update the OIDC providers. if err := reloadAuth(app); err != nil { - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error reloading auth", nil, envelope.GeneralError) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, envelope.GeneralError) } - return r.SendEnvelope(true) + return r.SendEnvelope("OIDC updated successfully") } func handleDeleteOIDC(r *fastglue.Request) error { @@ -107,7 +107,7 @@ func handleDeleteOIDC(r *fastglue.Request) error { // Reload the auth manager to update the OIDC providers. if err := reloadAuth(app); err != nil { - return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error reloading auth", nil, envelope.GeneralError) + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, envelope.GeneralError) } - return r.SendEnvelope(true) + return r.SendEnvelope("OIDC deleted successfully") } diff --git a/cmd/roles.go b/cmd/roles.go index 12e9a3b8..328175a3 100644 --- a/cmd/roles.go +++ b/cmd/roles.go @@ -3,8 +3,8 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/role/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/role/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) diff --git a/cmd/search.go b/cmd/search.go new file mode 100644 index 00000000..e3f322b0 --- /dev/null +++ b/cmd/search.go @@ -0,0 +1,46 @@ +package main + +import ( + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/zerodha/fastglue" +) + +const ( + minSearchQueryLength = 3 +) + +// handleSearchConversations searches conversations based on the query. +func handleSearchConversations(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + q = string(r.RequestCtx.QueryArgs().Peek("query")) + ) + + if len(q) < minSearchQueryLength { + return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, "Query length should be at least 3 characters", nil)) + } + + conversations, err := app.search.Conversations(q) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(conversations) +} + +// handleSearchMessages searches messages based on the query. +func handleSearchMessages(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + q = string(r.RequestCtx.QueryArgs().Peek("query")) + ) + + if len(q) < minSearchQueryLength { + return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, "Query length should be at least 3 characters", nil)) + } + + messages, err := app.search.Messages(q) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(messages) +} diff --git a/cmd/settings.go b/cmd/settings.go index 28b3b908..a7088999 100644 --- a/cmd/settings.go +++ b/cmd/settings.go @@ -4,13 +4,14 @@ import ( "encoding/json" "strings" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/setting/models" - "github.com/abhinavxd/artemis/internal/stringutil" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/setting/models" + "github.com/abhinavxd/libredesk/internal/stringutil" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +// handleGetGeneralSettings fetches general settings. func handleGetGeneralSettings(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -22,6 +23,7 @@ func handleGetGeneralSettings(r *fastglue.Request) error { return r.SendEnvelope(out) } +// handleUpdateGeneralSettings updates general settings. func handleUpdateGeneralSettings(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -35,9 +37,17 @@ func handleUpdateGeneralSettings(r *fastglue.Request) error { if err := app.setting.Update(req); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + // Reload the settings and templates. + if err := reloadSettings(app); err != nil { + return envelope.NewError(envelope.GeneralError, "Could not reload settings, Please restart the app.", nil) + } + if err := reloadTemplates(app); err != nil { + return envelope.NewError(envelope.GeneralError, "Could not reload settings, Please restart the app.", nil) + } + return r.SendEnvelope("Settings updated successfully") } +// handleGetEmailNotificationSettings fetches email notification settings. func handleGetEmailNotificationSettings(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -59,6 +69,7 @@ func handleGetEmailNotificationSettings(r *fastglue.Request) error { return r.SendEnvelope(notif) } +// handleUpdateEmailNotificationSettings updates email notification settings. func handleUpdateEmailNotificationSettings(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -86,5 +97,5 @@ func handleUpdateEmailNotificationSettings(r *fastglue.Request) error { if err := app.setting.Update(req); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Settings updated successfully, Please restart the app for changes to take effect.") } diff --git a/cmd/sla.go b/cmd/sla.go new file mode 100644 index 00000000..b1ec60dc --- /dev/null +++ b/cmd/sla.go @@ -0,0 +1,103 @@ +package main + +import ( + "strconv" + "time" + + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/valyala/fasthttp" + "github.com/zerodha/fastglue" +) + +func handleGetSLAs(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + slas, err := app.sla.GetAll() + if err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, "") + } + return r.SendEnvelope(slas) +} + +func handleGetSLA(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid SLA `id`.", nil, envelope.InputError) + } + + sla, err := app.sla.Get(id) + if err != nil { + return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, err.Error(), nil, "") + } + return r.SendEnvelope(sla) +} + +func handleCreateSLA(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + name = string(r.RequestCtx.PostArgs().Peek("name")) + desc = string(r.RequestCtx.PostArgs().Peek("description")) + firstRespTime = string(r.RequestCtx.PostArgs().Peek("first_response_time")) + resTime = string(r.RequestCtx.PostArgs().Peek("resolution_time")) + ) + // Validate time duration strings + if _, err := time.ParseDuration(firstRespTime); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `first_response_time` duration.", nil, envelope.InputError) + } + if _, err := time.ParseDuration(resTime); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `resolution_time` duration.", nil, envelope.InputError) + } + if err := app.sla.Create(name, desc, firstRespTime, resTime); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("SLA created successfully.") +} + +func handleDeleteSLA(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid SLA `id`.", nil, envelope.InputError) + } + + if err = app.sla.Delete(id); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} + +func handleUpdateSLA(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + name = string(r.RequestCtx.PostArgs().Peek("name")) + desc = string(r.RequestCtx.PostArgs().Peek("description")) + firstRespTime = string(r.RequestCtx.PostArgs().Peek("first_response_time")) + resTime = string(r.RequestCtx.PostArgs().Peek("resolution_time")) + ) + + // Validate time duration strings + if _, err := time.ParseDuration(firstRespTime); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `first_response_time` duration.", nil, envelope.InputError) + } + if _, err := time.ParseDuration(resTime); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `resolution_time` duration.", nil, envelope.InputError) + } + + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid SLA `id`.", nil, envelope.InputError) + } + + if err := app.sla.Update(id, name, desc, firstRespTime, resTime); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} diff --git a/cmd/statuses.go b/cmd/statuses.go index 9b724a77..04851e58 100644 --- a/cmd/statuses.go +++ b/cmd/statuses.go @@ -3,8 +3,8 @@ package main import ( "strconv" - cmodels "github.com/abhinavxd/artemis/internal/conversation/models" - "github.com/abhinavxd/artemis/internal/envelope" + cmodels "github.com/abhinavxd/libredesk/internal/conversation/models" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) @@ -20,10 +20,9 @@ func handleGetStatuses(r *fastglue.Request) error { return r.SendEnvelope(out) } - func handleCreateStatus(r *fastglue.Request) error { var ( - app = r.Context.(*App) + app = r.Context.(*App) status = cmodels.Status{} ) if err := r.Decode(&status, "json"); err != nil { @@ -66,7 +65,7 @@ func handleDeleteStatus(r *fastglue.Request) error { func handleUpdateStatus(r *fastglue.Request) error { var ( - app = r.Context.(*App) + app = r.Context.(*App) status = cmodels.Status{} ) id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) diff --git a/cmd/tags.go b/cmd/tags.go index a8574ce0..c1a91009 100644 --- a/cmd/tags.go +++ b/cmd/tags.go @@ -3,8 +3,8 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - tmodels "github.com/abhinavxd/artemis/internal/tag/models" + "github.com/abhinavxd/libredesk/internal/envelope" + tmodels "github.com/abhinavxd/libredesk/internal/tag/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) diff --git a/cmd/teams.go b/cmd/teams.go index 0ceaa54b..b8b66cef 100644 --- a/cmd/teams.go +++ b/cmd/teams.go @@ -1,15 +1,15 @@ package main import ( - "fmt" "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/team/models" + "github.com/abhinavxd/libredesk/internal/envelope" "github.com/valyala/fasthttp" + "github.com/volatiletech/null/v9" "github.com/zerodha/fastglue" ) +// handleGetTeams returns a list of all teams. func handleGetTeams(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -21,6 +21,7 @@ func handleGetTeams(r *fastglue.Request) error { return r.SendEnvelope(teams) } +// handleGetTeamsCompact returns a list of all teams in a compact format. func handleGetTeamsCompact(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -32,59 +33,60 @@ func handleGetTeamsCompact(r *fastglue.Request) error { return r.SendEnvelope(teams) } +// handleGetTeam returns a single team. func handleGetTeam(r *fastglue.Request) error { var ( - app = r.Context.(*App) + app = r.Context.(*App) + id, _ = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) ) - id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) - if err != nil || id == 0 { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, - "Invalid team `id`.", nil, envelope.InputError) + if id < 1 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid team `id`.", nil, envelope.InputError) } - team, err := app.team.GetTeam(id) + team, err := app.team.Get(id) if err != nil { return sendErrorEnvelope(r, err) } return r.SendEnvelope(team) } +// handleCreateTeam creates a new team. func handleCreateTeam(r *fastglue.Request) error { var ( - app = r.Context.(*App) - req = models.Team{} + app = r.Context.(*App) + name = string(r.RequestCtx.PostArgs().Peek("name")) + timezone = string(r.RequestCtx.PostArgs().Peek("timezone")) + emoji = string(r.RequestCtx.PostArgs().Peek("emoji")) + conversationAssignmentType = string(r.RequestCtx.PostArgs().Peek("conversation_assignment_type")) + businessHrsID, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("business_hours_id"))) + slaPolicyID, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("sla_policy_id"))) + maxAutoAssignedConversations, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("max_auto_assigned_conversations"))) ) - - if _, err := fastglue.ScanArgs(r.RequestCtx.PostArgs(), &req, `json`); err != nil { - app.lo.Error("error scanning args", "error", err) - return envelope.NewError(envelope.InputError, - fmt.Sprintf("Invalid request (%s)", err.Error()), nil) - } - err := app.team.CreateTeam(req) - if err != nil { + if err := app.team.Create(name, timezone, conversationAssignmentType, null.NewInt(businessHrsID, businessHrsID != 0), null.NewInt(slaPolicyID, slaPolicyID != 0), emoji, maxAutoAssignedConversations); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Team created successfully.") } +// handleUpdateTeam updates an existing team. func handleUpdateTeam(r *fastglue.Request) error { var ( - app = r.Context.(*App) - req = models.Team{} + app = r.Context.(*App) + name = string(r.RequestCtx.PostArgs().Peek("name")) + timezone = string(r.RequestCtx.PostArgs().Peek("timezone")) + emoji = string(r.RequestCtx.PostArgs().Peek("emoji")) + conversationAssignmentType = string(r.RequestCtx.PostArgs().Peek("conversation_assignment_type")) + id, _ = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + businessHrsID, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("business_hours_id"))) + slaPolicyID, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("sla_policy_id"))) + maxAutoAssignedConversations, _ = strconv.Atoi(string(r.RequestCtx.PostArgs().Peek("max_auto_assigned_conversations"))) ) - id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) - if err != nil || id == 0 { - return r.SendErrorEnvelope(fasthttp.StatusBadRequest, - "Invalid team `id`.", nil, envelope.InputError) + if id < 1 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid team `id`", nil, envelope.InputError) } - - if err := r.Decode(&req, "json"); err != nil { - return envelope.NewError(envelope.InputError, "Bad request", nil) - } - err = app.team.UpdateTeam(id, req) - if err != nil { + if err := app.team.Update(id, name, timezone, conversationAssignmentType, null.NewInt(businessHrsID, businessHrsID != 0), null.NewInt(slaPolicyID, slaPolicyID != 0), emoji, maxAutoAssignedConversations); err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Team updated successfully.") } // handleDeleteTeam deletes a team @@ -97,9 +99,9 @@ func handleDeleteTeam(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid team `id`.", nil, envelope.InputError) } - err = app.team.DeleteTeam(id) + err = app.team.Delete(id) if err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) -} \ No newline at end of file + return r.SendEnvelope("Team deleted successfully.") +} diff --git a/cmd/templates.go b/cmd/templates.go index 5cf0b855..9bdb270d 100644 --- a/cmd/templates.go +++ b/cmd/templates.go @@ -3,23 +3,29 @@ package main import ( "strconv" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/template/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/template/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +// handleGetTemplates returns all templates. func handleGetTemplates(r *fastglue.Request) error { var ( app = r.Context.(*App) + typ = string(r.RequestCtx.QueryArgs().Peek("type")) ) - t, err := app.tmpl.GetAll() + if typ == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid `type`.", nil, envelope.InputError) + } + t, err := app.tmpl.GetAll(typ) if err != nil { return sendErrorEnvelope(r, err) } return r.SendEnvelope(t) } +// handleGetTemplate returns a template by id. func handleGetTemplate(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -36,6 +42,7 @@ func handleGetTemplate(r *fastglue.Request) error { return r.SendEnvelope(t) } +// handleCreateTemplate creates a new template. func handleCreateTemplate(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -44,14 +51,13 @@ func handleCreateTemplate(r *fastglue.Request) error { if err := r.Decode(&req, "json"); err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Bad request", nil, envelope.GeneralError) } - - err := app.tmpl.Create(req) - if err != nil { + if err := app.tmpl.Create(req); err != nil { return sendErrorEnvelope(r, err) } return r.SendEnvelope(true) } +// handleUpdateTemplate updates a template. func handleUpdateTemplate(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -62,17 +68,16 @@ func handleUpdateTemplate(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid template `id`.", nil, envelope.InputError) } - if err := r.Decode(&req, "json"); err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Bad request", nil, envelope.GeneralError) } - if err = app.tmpl.Update(id, req); err != nil { return sendErrorEnvelope(r, err) } return r.SendEnvelope(true) } +// handleDeleteTemplate deletes a template. func handleDeleteTemplate(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -83,11 +88,9 @@ func handleDeleteTemplate(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid template `id`.", nil, envelope.InputError) } - if err := r.Decode(&req, "json"); err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Bad request", nil, envelope.GeneralError) } - if err = app.tmpl.Delete(id); err != nil { return sendErrorEnvelope(r, err) } diff --git a/cmd/users.go b/cmd/users.go index ad012410..df4d8cd3 100644 --- a/cmd/users.go +++ b/cmd/users.go @@ -8,14 +8,16 @@ import ( "strconv" "strings" - "github.com/abhinavxd/artemis/internal/envelope" - "github.com/abhinavxd/artemis/internal/image" - mmodels "github.com/abhinavxd/artemis/internal/media/models" - notifier "github.com/abhinavxd/artemis/internal/notification" - "github.com/abhinavxd/artemis/internal/stringutil" - tmpl "github.com/abhinavxd/artemis/internal/template" - umodels "github.com/abhinavxd/artemis/internal/user/models" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" + "github.com/abhinavxd/libredesk/internal/image" + mmodels "github.com/abhinavxd/libredesk/internal/media/models" + notifier "github.com/abhinavxd/libredesk/internal/notification" + "github.com/abhinavxd/libredesk/internal/stringutil" + tmpl "github.com/abhinavxd/libredesk/internal/template" + "github.com/abhinavxd/libredesk/internal/user/models" "github.com/valyala/fasthttp" + "github.com/volatiletech/null/v9" "github.com/zerodha/fastglue" ) @@ -23,6 +25,7 @@ const ( maxAvatarSizeMB = 5 ) +// handleGetUsers returns all users. func handleGetUsers(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -34,6 +37,7 @@ func handleGetUsers(r *fastglue.Request) error { return r.SendEnvelope(agents) } +// handleGetUsersCompact returns all users in a compact format. func handleGetUsersCompact(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -45,6 +49,7 @@ func handleGetUsersCompact(r *fastglue.Request) error { return r.SendEnvelope(agents) } +// handleGetUser returns a user. func handleGetUser(r *fastglue.Request) error { var ( app = r.Context.(*App) @@ -61,11 +66,34 @@ func handleGetUser(r *fastglue.Request) error { return r.SendEnvelope(user) } +// handleGetCurrentUserTeams returns the teams of a user. +func handleGetCurrentUserTeams(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + teams, err := app.team.GetUserTeams(user.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(teams) +} + +// handleUpdateCurrentUser updates the current user. func handleUpdateCurrentUser(r *fastglue.Request) error { var ( - app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } // Get current user. currentUser, err := app.user.Get(user.ID) @@ -114,7 +142,12 @@ func handleUpdateCurrentUser(r *fastglue.Request) error { // Reset ptr. file.Seek(0, 0) - media, err := app.media.UploadAndInsert(srcFileName, srcContentType, "", mmodels.ModelUser, user.ID, file, int(srcFileSize), "", []byte("{}")) + linkedModel := null.StringFrom(mmodels.ModelUser) + linkedID := null.IntFrom(user.ID) + disposition := null.NewString("", false) + contentID := "" + meta := []byte("{}") + media, err := app.media.UploadAndInsert(srcFileName, srcContentType, contentID, linkedModel, linkedID, file, int(srcFileSize), disposition, meta) if err != nil { app.lo.Error("error uploading file", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error uploading file", nil, envelope.GeneralError) @@ -136,26 +169,33 @@ func handleUpdateCurrentUser(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } } - - return r.SendEnvelope(true) + return r.SendEnvelope("User updated successfully.") } // handleCreateUser creates a new user. func handleCreateUser(r *fastglue.Request) error { var ( app = r.Context.(*App) - user = umodels.User{} + user = models.User{} ) if err := r.Decode(&user, "json"); err != nil { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) } - if user.Email == "" { + if user.Email.String == "" { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty `email`", nil, envelope.InputError) } - err := app.user.Create(&user) - if err != nil { + if user.Roles == nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Please select at least one role", nil, envelope.InputError) + } + + if user.FirstName == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty `first_name`", nil, envelope.InputError) + } + + // Right now, only agents can be created. + if err := app.user.CreateAgent(&user); err != nil { return sendErrorEnvelope(r, err) } @@ -172,13 +212,13 @@ func handleCreateUser(r *fastglue.Request) error { } // Render template and send email. - content, err := app.tmpl.Render(tmpl.TmplWelcome, map[string]interface{}{ + content, err := app.tmpl.RenderTemplate(tmpl.TmplWelcome, map[string]interface{}{ "ResetToken": resetToken, "Email": user.Email, }) if err != nil { app.lo.Error("error rendering template", "error", err) - return r.SendEnvelope(true) + return r.SendEnvelope("User created successfully, but error rendering welcome email.") } if err := app.notifier.Send(notifier.Message{ @@ -188,17 +228,17 @@ func handleCreateUser(r *fastglue.Request) error { Provider: notifier.ProviderEmail, }); err != nil { app.lo.Error("error sending notification message", "error", err) - return r.SendEnvelope(true) + return r.SendEnvelope("User created successfully, but error sending welcome email.") } } - return r.SendEnvelope(true) + return r.SendEnvelope("User created successfully.") } // handleUpdateUser updates a user. func handleUpdateUser(r *fastglue.Request) error { var ( app = r.Context.(*App) - user = umodels.User{} + user = models.User{} ) id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) if err != nil || id == 0 { @@ -210,9 +250,20 @@ func handleUpdateUser(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) } + if user.Email.String == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty `email`", nil, envelope.InputError) + } + + if user.Roles == nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Please select at least one role", nil, envelope.InputError) + } + + if user.FirstName == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty `first_name`", nil, envelope.InputError) + } + // Update user. - err = app.user.Update(id, user) - if err != nil { + if err = app.user.Update(id, user); err != nil { return sendErrorEnvelope(r, err) } @@ -221,23 +272,22 @@ func handleUpdateUser(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("User updated successfully.") } -// handleDeleteUser deletes a user. +// handleDeleteUser soft deletes a user. func handleDeleteUser(r *fastglue.Request) error { var ( - app = r.Context.(*App) + app = r.Context.(*App) + id, err = strconv.Atoi(r.RequestCtx.UserValue("id").(string)) ) - id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) if err != nil || id == 0 { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Invalid user `id`.", nil, envelope.InputError) } // Soft delete user. - err = app.user.SoftDelete(id) - if err != nil { + if err = app.user.SoftDelete(id); err != nil { return sendErrorEnvelope(r, err) } @@ -246,16 +296,16 @@ func handleDeleteUser(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("User deleted successfully.") } // handleGetCurrentUser returns the current logged in user. func handleGetCurrentUser(r *fastglue.Request) error { var ( - app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) - u, err := app.user.Get(user.ID) + u, err := app.user.Get(auser.ID) if err != nil { return sendErrorEnvelope(r, err) } @@ -265,12 +315,12 @@ func handleGetCurrentUser(r *fastglue.Request) error { // handleDeleteAvatar deletes a user avatar. func handleDeleteAvatar(r *fastglue.Request) error { var ( - app = r.Context.(*App) - user = r.RequestCtx.UserValue("user").(umodels.User) + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) ) // Get user - user, err := app.user.Get(user.ID) + user, err := app.user.Get(auser.ID) if err != nil { return sendErrorEnvelope(r, err) } @@ -290,19 +340,18 @@ func handleDeleteAvatar(r *fastglue.Request) error { if err != nil { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Avatar deleted successfully.") } // handleResetPassword generates a reset password token and sends an email to the user. func handleResetPassword(r *fastglue.Request) error { var ( - app = r.Context.(*App) - p = r.RequestCtx.PostArgs() - user, ok = r.RequestCtx.UserValue("user").(umodels.User) - email = string(p.Peek("email")) + app = r.Context.(*App) + p = r.RequestCtx.PostArgs() + auser, ok = r.RequestCtx.UserValue("user").(amodels.User) + email = string(p.Peek("email")) ) - - if ok && user.ID > 0 { + if ok && auser.ID > 0 { return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "User is already logged in", nil, envelope.InputError) } @@ -321,7 +370,7 @@ func handleResetPassword(r *fastglue.Request) error { } // Send email. - content, err := app.tmpl.Render(tmpl.TmplResetPassword, + content, err := app.tmpl.RenderTemplate(tmpl.TmplResetPassword, map[string]string{ "ResetToken": token, }) @@ -340,14 +389,14 @@ func handleResetPassword(r *fastglue.Request) error { return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, "Error sending notification message", nil, envelope.GeneralError) } - return r.SendEnvelope(true) + return r.SendEnvelope("Reset password email sent successfully.") } // handleSetPassword resets the password with the provided token. func handleSetPassword(r *fastglue.Request) error { var ( app = r.Context.(*App) - user, ok = r.RequestCtx.UserValue("user").(umodels.User) + user, ok = r.RequestCtx.UserValue("user").(amodels.User) p = r.RequestCtx.PostArgs() password = string(p.Peek("password")) token = string(p.Peek("token")) @@ -365,5 +414,5 @@ func handleSetPassword(r *fastglue.Request) error { return sendErrorEnvelope(r, err) } - return r.SendEnvelope(true) + return r.SendEnvelope("Password reset successfully.") } diff --git a/cmd/views.go b/cmd/views.go new file mode 100644 index 00000000..d802af33 --- /dev/null +++ b/cmd/views.go @@ -0,0 +1,139 @@ +package main + +import ( + "strconv" + + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/envelope" + vmodels "github.com/abhinavxd/libredesk/internal/view/models" + "github.com/valyala/fasthttp" + "github.com/zerodha/fastglue" +) + +// handleGetUserViews returns all views for a user. +func handleGetUserViews(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + v, err := app.view.GetUsersViews(user.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope(v) +} + +// handleCreateUserView creates a view for a user. +func handleCreateUserView(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + view = vmodels.View{} + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + if err := r.Decode(&view, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + if view.Name == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty view `Name`", nil, envelope.InputError) + } + + if string(view.Filters) == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty view `Filter`", nil, envelope.InputError) + } + + if err := app.view.Create(view.Name, view.Filters, user.ID); err != nil { + return sendErrorEnvelope(r, err) + } + return r.SendEnvelope("View created successfully") +} + +// handleGetUserView deletes a view for a user. +func handleDeleteUserView(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, + "Invalid view `id`.", nil, envelope.InputError) + } + + if id <= 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty view `ID`", nil, envelope.InputError) + } + + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + view, err := app.view.Get(id) + if err != nil { + return sendErrorEnvelope(r, err) + } + + if view.UserID != user.ID { + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "Forbidden", nil, envelope.PermissionError) + } + + if err = app.view.Delete(id); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope("View deleted successfully") +} + +// handleUpdateUserView updates a view for a user. +func handleUpdateUserView(r *fastglue.Request) error { + var ( + app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + view = vmodels.View{} + ) + id, err := strconv.Atoi(r.RequestCtx.UserValue("id").(string)) + if err != nil || id == 0 { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, + "Invalid view `id`.", nil, envelope.InputError) + } + + if err := r.Decode(&view, "json"); err != nil { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "decode failed", err.Error(), envelope.InputError) + } + + user, err := app.user.Get(auser.ID) + if err != nil { + return sendErrorEnvelope(r, err) + } + + if view.Name == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty view `Name`", nil, envelope.InputError) + } + + if string(view.Filters) == "" { + return r.SendErrorEnvelope(fasthttp.StatusBadRequest, "Empty view `Filter`", nil, envelope.InputError) + } + + v, err := app.view.Get(id) + if err != nil { + return sendErrorEnvelope(r, err) + } + + if v.UserID != user.ID { + return r.SendErrorEnvelope(fasthttp.StatusForbidden, "Forbidden", nil, envelope.PermissionError) + } + + if err = app.view.Update(id, view.Name, view.Filters); err != nil { + return sendErrorEnvelope(r, err) + } + + return r.SendEnvelope(true) +} diff --git a/cmd/websocket.go b/cmd/websocket.go index 01bb844b..27d03828 100644 --- a/cmd/websocket.go +++ b/cmd/websocket.go @@ -3,45 +3,48 @@ package main import ( "fmt" - umodels "github.com/abhinavxd/artemis/internal/user/models" - "github.com/abhinavxd/artemis/internal/ws" - wsmodels "github.com/abhinavxd/artemis/internal/ws/models" + amodels "github.com/abhinavxd/libredesk/internal/auth/models" + "github.com/abhinavxd/libredesk/internal/ws" + wsmodels "github.com/abhinavxd/libredesk/internal/ws/models" "github.com/fasthttp/websocket" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) +// ErrHandler is a custom error handler. func ErrHandler(ctx *fasthttp.RequestCtx, status int, reason error) { fmt.Printf("error status %d: %s", status, reason) } +// upgrader is a websocket upgrader. var upgrader = websocket.FastHTTPUpgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, + ReadBufferSize: 8192, + WriteBufferSize: 8192, CheckOrigin: func(ctx *fasthttp.RequestCtx) bool { return true }, Error: ErrHandler, } +// handleWS handles the websocket connection. func handleWS(r *fastglue.Request, hub *ws.Hub) error { var ( - user = r.RequestCtx.UserValue("user").(umodels.User) - app = r.Context.(*App) + auser = r.RequestCtx.UserValue("user").(amodels.User) + app = r.Context.(*App) ) err := upgrader.Upgrade(r.RequestCtx, func(conn *websocket.Conn) { c := ws.Client{ - ID: user.ID, + ID: auser.ID, Hub: hub, Conn: conn, - Send: make(chan wsmodels.WSMessage, 1000), + Send: make(chan wsmodels.WSMessage, 10000), } hub.AddClient(&c) go c.Listen() c.Serve() }) if err != nil { - app.lo.Error("error upgrading tcp connection", "error", err) + app.lo.Error("error upgrading tcp connection", "user_id", auser.ID, "error", err) } return nil } diff --git a/config.sample.toml b/config.sample.toml index 02d229ae..5aa588bd 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -12,7 +12,7 @@ write_timeout = "5s" max_body_size = 10000000 keepalive_timeout = "10s" -# File upload. +# File upload provider. [upload] provider = "fs" @@ -23,14 +23,12 @@ upload_path = '/home/ubuntu/uploads' # S3 provider. [upload.s3] url = "" -public_url = "" access_key = "" secret_key = "" region = "ap-south-1" bucket = "bucket" bucket_path = "" -bucket_type = "private" -expiry = "15m" +expiry = "6h" # Postgres. [db] @@ -38,11 +36,11 @@ host = "127.0.0.1" port = 5432 user = "postgres" password = "postgres" -database = "database" +database = "libredesk" ssl_mode = "disable" -max_open = 10 -max_idle = 10 -max_lifetime = "10s" +max_open = 30 +max_idle = 30 +max_lifetime = "300s" # Redis. [redis] @@ -51,14 +49,24 @@ password = "" db = 0 [message] -dispatch_workers = 10 -dispatch_scan_interval = "50ms" +outgoing_queue_workers = 10 +incoming_queue_workers = 10 +message_outoing_scan_interval = "50ms" incoming_queue_size = 5000 outgoing_queue_size = 5000 [notification] concurrency = 2 -queue_size = 100 +queue_size = 2000 [automation] worker_count = 10 + +[autoassigner] +autoassign_interval = "5m" + +[conversation] +unsnooze_interval = "5m" + +[sla] +evaluation_interval = "5m" \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md index f6e5a379..66a31e6f 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,4 +1,4 @@ -# frontend-tailwind +# Libredesk frontend This template should help get you started developing with Vue 3 in Vite. diff --git a/frontend/index.html b/frontend/index.html index 54ad17ef..038b5f39 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7,7 +7,7 @@ diff --git a/frontend/package.json b/frontend/package.json index 369d5b05..f2dbf32c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,10 +1,10 @@ { - "name": "frontend-tailwind", + "name": "libredesk", "version": "0.0.0", "private": true, "type": "module", "scripts": { - "dev": "bunx --bun vite", + "dev": "pnpm exec vite", "build": "vite build", "preview": "vite preview", "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", @@ -22,7 +22,6 @@ "@tanstack/vue-table": "^8.19.2", "@tiptap/extension-image": "^2.5.9", "@tiptap/extension-link": "^2.9.1", - "@tiptap/extension-list-item": "^2.4.0", "@tiptap/extension-ordered-list": "^2.4.0", "@tiptap/extension-placeholder": "^2.4.0", "@tiptap/pm": "^2.4.0", @@ -35,8 +34,9 @@ "@vue/reactivity": "^3.4.15", "@vue/runtime-core": "^3.4.15", "@vueup/vue-quill": "^1.2.0", - "@vueuse/core": "^11.2.0", + "@vueuse/core": "^12.4.0", "add": "^2.0.6", + "axios": "^1.7.9", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "codeflask": "^1.4.1", @@ -59,10 +59,12 @@ "vue-letter": "^0.2.0", "vue-picture-cropper": "^0.7.0", "vue-router": "^4.2.5", + "vue-sonner": "^1.3.0", + "vue3-emoji-picker": "^1.1.8", + "vuedraggable": "^4.1.0", "zod": "^3.23.8" }, "devDependencies": { - "@iconify/vue": "^4.1.2", "@rushstack/eslint-patch": "^1.3.3", "@vitejs/plugin-vue": "^5.0.3", "@vue/eslint-config-prettier": "^8.0.0", @@ -78,5 +80,5 @@ "tailwindcss": "latest", "vite": "^5.4.9" }, - "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" + "packageManager": "pnpm@9.15.3+sha512.1f79bc245a66eb0b07c5d4d83131240774642caaa86ef7d0434ab47c0d16f66b04e21e0c086eb61e62c77efc4d7f7ec071afad3796af64892fae66509173893a" } diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 00000000..9336695e --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,8250 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@formkit/auto-animate': + specifier: ^0.8.2 + version: 0.8.2 + '@internationalized/date': + specifier: ^3.5.5 + version: 3.6.0 + '@radix-icons/vue': + specifier: ^1.0.0 + version: 1.0.0(vue@3.5.13(typescript@5.7.3)) + '@tailwindcss/typography': + specifier: ^0.5.10 + version: 0.5.16(tailwindcss@3.4.17) + '@tanstack/vue-table': + specifier: ^8.19.2 + version: 8.20.5(vue@3.5.13(typescript@5.7.3)) + '@tiptap/extension-image': + specifier: ^2.5.9 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-link': + specifier: ^2.9.1 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-ordered-list': + specifier: ^2.4.0 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-placeholder': + specifier: ^2.4.0 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/pm': + specifier: ^2.4.0 + version: 2.11.2 + '@tiptap/starter-kit': + specifier: ^2.4.0 + version: 2.11.2 + '@tiptap/suggestion': + specifier: ^2.4.0 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/vue-3': + specifier: ^2.4.0 + version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(vue@3.5.13(typescript@5.7.3)) + '@unovis/ts': + specifier: ^1.4.4 + version: 1.5.0 + '@unovis/vue': + specifier: ^1.4.4 + version: 1.5.0(@unovis/ts@1.5.0)(vue@3.5.13(typescript@5.7.3)) + '@vee-validate/zod': + specifier: ^4.13.2 + version: 4.15.0(vue@3.5.13(typescript@5.7.3))(zod@3.24.1) + '@vue/reactivity': + specifier: ^3.4.15 + version: 3.5.13 + '@vue/runtime-core': + specifier: ^3.4.15 + version: 3.5.13 + '@vueup/vue-quill': + specifier: ^1.2.0 + version: 1.2.0(vue@3.5.13(typescript@5.7.3)) + '@vueuse/core': + specifier: ^12.4.0 + version: 12.4.0(typescript@5.7.3) + add: + specifier: ^2.0.6 + version: 2.0.6 + axios: + specifier: ^1.7.9 + version: 1.7.9(debug@4.4.0) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + codeflask: + specifier: ^1.4.1 + version: 1.4.1 + date-fns: + specifier: ^3.6.0 + version: 3.6.0 + install: + specifier: ^0.13.0 + version: 0.13.0 + lucide-vue-next: + specifier: ^0.378.0 + version: 0.378.0(vue@3.5.13(typescript@5.7.3)) + mitt: + specifier: ^3.0.1 + version: 3.0.1 + npm: + specifier: ^10.4.0 + version: 10.9.2 + npx: + specifier: ^10.2.2 + version: 10.2.2 + pinia: + specifier: ^2.1.7 + version: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)) + qs: + specifier: ^6.12.1 + version: 6.13.1 + radix-vue: + specifier: latest + version: 1.9.12(vue@3.5.13(typescript@5.7.3)) + shadcn-vue: + specifier: latest + version: 0.11.3(@vitest/ui@2.1.8)(eslint@8.57.1)(vitest@2.1.8)(vue@3.5.13(typescript@5.7.3)) + tailwind-merge: + specifier: ^2.3.0 + version: 2.6.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.17) + textarea: + specifier: ^0.3.0 + version: 0.3.0 + vee-validate: + specifier: ^4.13.2 + version: 4.15.0(vue@3.5.13(typescript@5.7.3)) + vue: + specifier: ^3.4.37 + version: 3.5.13(typescript@5.7.3) + vue-i18n: + specifier: '9' + version: 9.14.2(vue@3.5.13(typescript@5.7.3)) + vue-letter: + specifier: ^0.2.0 + version: 0.2.0 + vue-picture-cropper: + specifier: ^0.7.0 + version: 0.7.0(vue@3.5.13(typescript@5.7.3)) + vue-router: + specifier: ^4.2.5 + version: 4.5.0(vue@3.5.13(typescript@5.7.3)) + vue-sonner: + specifier: ^1.3.0 + version: 1.3.0 + vue3-emoji-picker: + specifier: ^1.1.8 + version: 1.1.8(typescript@5.7.3) + vuedraggable: + specifier: ^4.1.0 + version: 4.1.0(vue@3.5.13(typescript@5.7.3)) + zod: + specifier: ^3.23.8 + version: 3.24.1 + devDependencies: + '@rushstack/eslint-patch': + specifier: ^1.3.3 + version: 1.10.5 + '@vitejs/plugin-vue': + specifier: ^5.0.3 + version: 5.2.1(vite@5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0))(vue@3.5.13(typescript@5.7.3)) + '@vue/eslint-config-prettier': + specifier: ^8.0.0 + version: 8.0.0(eslint@8.57.1)(prettier@3.4.2) + autoprefixer: + specifier: latest + version: 10.4.20(postcss@8.4.49) + cypress: + specifier: ^13.6.3 + version: 13.17.0 + eslint: + specifier: ^8.49.0 + version: 8.57.1 + eslint-plugin-cypress: + specifier: ^2.15.1 + version: 2.15.2(eslint@8.57.1) + eslint-plugin-vue: + specifier: ^9.17.0 + version: 9.32.0(eslint@8.57.1) + postcss: + specifier: ^8.4.38 + version: 8.4.49 + prettier: + specifier: ^3.0.3 + version: 3.4.2 + sass: + specifier: ^1.70.0 + version: 1.83.1 + start-server-and-test: + specifier: ^2.0.3 + version: 2.0.9 + tailwindcss: + specifier: latest + version: 3.4.17 + vite: + specifier: ^5.4.9 + version: 5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.5': + resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.5': + resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.25.9': + resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.26.5': + resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.25.9': + resolution: {integrity: sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-member-expression-to-functions@7.25.9': + resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.25.9': + resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.26.5': + resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.26.5': + resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.5': + resolution: {integrity: sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@8.0.0-alpha.12': + resolution: {integrity: sha512-AzWmrp4uJ+DcXVH0uoUpJVhRqxNirC0BbXsZ82AQuVod41CoaV5G+cwcvtYusrIIxv7BIJb6ce0dQ9L0wAl1iA==} + engines: {node: ^18.20.0 || ^20.10.0 || >=21.0.0} + hasBin: true + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.26.3': + resolution: {integrity: sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.26.5': + resolution: {integrity: sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.26.0': + resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.26.0': + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.26.5': + resolution: {integrity: sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.5': + resolution: {integrity: sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==} + engines: {node: '>=6.9.0'} + + '@bassist/utils@0.4.0': + resolution: {integrity: sha512-aoFTl0jUjm8/tDZodP41wnEkvB+C5O9NFCuYN/ztL6jSUSsuBkXq90/1ifBm1XhV/zySHgLYlU1+tgo3XtQ+nA==} + + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + + '@cypress/request@3.0.7': + resolution: {integrity: sha512-LzxlLEMbBOPYB85uXrDqvD4MgcenjRBLIns3zyhx7vTPj/0u2eQhzXvPiGcaJrV38Q9dbkExWp6cOHPJ+EtFYg==} + engines: {node: '>= 6'} + + '@cypress/xvfb@1.2.4': + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/css@11.13.5': + resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@floating-ui/vue@1.1.6': + resolution: {integrity: sha512-XFlUzGHGv12zbgHNk5FN2mUB7ROul3oG2ENdTpWdE+qMFxyNxWSRmsoyhiEnpmabNm6WnUvR1OvJfUfN4ojC1A==} + + '@formkit/auto-animate@0.8.2': + resolution: {integrity: sha512-SwPWfeRa5veb1hOIBMdzI+73te5puUBHmqqaF1Bu7FjvxlYSz/kJcZKSa9Cg60zL0uRNeJL2SbRxV6Jp6Q1nFQ==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@internationalized/date@3.6.0': + resolution: {integrity: sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ==} + + '@internationalized/number@3.6.0': + resolution: {integrity: sha512-PtrRcJVy7nw++wn4W2OuePQQfTqDzfusSuY1QTtui4wa7r+rGVtR75pO8CyKvHvzyQYi3Q1uO5sY0AsB4e65Bw==} + + '@intlify/core-base@9.14.2': + resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==} + engines: {node: '>= 16'} + + '@intlify/message-compiler@9.14.2': + resolution: {integrity: sha512-YsKKuV4Qv4wrLNsvgWbTf0E40uRv+Qiw1BeLQ0LAxifQuhiMe+hfTIzOMdWj/ZpnTDj4RSZtkXjJM7JDiiB5LQ==} + engines: {node: '>= 16'} + + '@intlify/shared@9.14.2': + resolution: {integrity: sha512-uRAHAxYPeF+G5DBIboKpPgC/Waecd4Jz8ihtkpJQD5ycb5PwXp0k/+hBGl5dAjwF7w+l74kz/PKA8r8OK//RUw==} + engines: {node: '>= 16'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@juggle/resize-observer@3.4.0': + resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + + '@mapbox/geojson-rewind@0.5.2': + resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} + hasBin: true + + '@mapbox/jsonlint-lines-primitives@2.0.2': + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + + '@mapbox/mapbox-gl-supported@2.0.1': + resolution: {integrity: sha512-HP6XvfNIzfoMVfyGjBckjiAOQK9WfX0ywdLubuPMPv+Vqf5fj0uCbgBQYpiqcWZT6cbyyRnTSXDheT1ugvF6UQ==} + + '@mapbox/point-geometry@0.1.0': + resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + + '@mapbox/tiny-sdf@2.0.6': + resolution: {integrity: sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==} + + '@mapbox/unitbezier@0.0.1': + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + + '@mapbox/vector-tile@1.3.1': + resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + + '@mapbox/whoots-js@3.1.0': + resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} + engines: {node: '>=6.0.0'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@parcel/watcher-android-arm64@2.5.0': + resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.0': + resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.0': + resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.0': + resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.0': + resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.0': + resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.0': + resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.0': + resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.0': + resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.0': + resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.0': + resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} + engines: {node: '>= 10.0.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@radix-icons/vue@1.0.0': + resolution: {integrity: sha512-gKWWk9tTK/laDRRNe5KLLR8A0qUwx4q4+DN8Fq48hJ904u78R82ayAO3TrxbNLgyn2D0h6rRiGdLzQWj7rPcvA==} + peerDependencies: + vue: '>= 3' + + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + + '@rollup/rollup-android-arm-eabi@4.30.1': + resolution: {integrity: sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.30.1': + resolution: {integrity: sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.30.1': + resolution: {integrity: sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.30.1': + resolution: {integrity: sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.30.1': + resolution: {integrity: sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.30.1': + resolution: {integrity: sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.30.1': + resolution: {integrity: sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.30.1': + resolution: {integrity: sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.30.1': + resolution: {integrity: sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.30.1': + resolution: {integrity: sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.30.1': + resolution: {integrity: sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': + resolution: {integrity: sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.30.1': + resolution: {integrity: sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.30.1': + resolution: {integrity: sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.30.1': + resolution: {integrity: sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.30.1': + resolution: {integrity: sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.30.1': + resolution: {integrity: sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.30.1': + resolution: {integrity: sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.30.1': + resolution: {integrity: sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==} + cpu: [x64] + os: [win32] + + '@rushstack/eslint-patch@1.10.5': + resolution: {integrity: sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A==} + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/typography@0.5.16': + resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tanstack/table-core@8.20.5': + resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==} + engines: {node: '>=12'} + + '@tanstack/virtual-core@3.11.2': + resolution: {integrity: sha512-vTtpNt7mKCiZ1pwU9hfKPhpdVO2sVzFQsxoVBGtOSHxlrRRzYr8iQ2TlwbAcRYCcEiZ9ECAM8kBzH0v2+VzfKw==} + + '@tanstack/vue-table@8.20.5': + resolution: {integrity: sha512-2xixT3BEgSDw+jOSqPt6ylO/eutDI107t2WdFMVYIZZ45UmTHLySqNriNs0+dMaKR56K5z3t+97P6VuVnI2L+Q==} + engines: {node: '>=12'} + peerDependencies: + vue: '>=3.2' + + '@tanstack/vue-virtual@3.11.2': + resolution: {integrity: sha512-y0b1p1FTlzxcSt/ZdGWY1AZ52ddwSU69pvFRYAELUSdLLxV8QOPe9dyT/KATO43UCb3DAwiyzi96h2IoYstBOQ==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + + '@tiptap/core@2.11.2': + resolution: {integrity: sha512-Z437c/sQg31yrRVgLJVkQuih+7Og5tjRx6FE/zE47QgEayqQ9yXH0LrTAbPiY6IfY1X+f2A0h3e5Y/WGD6rC3Q==} + peerDependencies: + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-blockquote@2.11.2': + resolution: {integrity: sha512-5XeU1o5UfjMCFX3AwgeErwDKlpUr5YPhta2tQqNsQUQ7QvumIdK/3apNT15/d8pySAjdAphDWEd/CZ2di5hq6A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bold@2.11.2': + resolution: {integrity: sha512-pSls6UnKiPMm2c0m1viuZ0aFexxUmTRm17vDA2Gy5PhRm5qSsnHlSxyEuEcKNOi/rIx+oJehvG1oO4uI+kmCKg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bubble-menu@2.11.2': + resolution: {integrity: sha512-G+m7JLhe6SGcDugm8q3RXVLVnCm4t67FGNlOLRzq25VNgD7FDNwjgISp04W+qcJa0+Z5cbQt/4naUji5QEH97A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-bullet-list@2.11.2': + resolution: {integrity: sha512-zqZYT7lmmivEDEO+6w5bl5kV3UP1L2dw5mksyMGtxpvoDgbFHZ85+ron6SeHee8C7vJc6aIptc1p6NxIS5/l0A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-code-block@2.11.2': + resolution: {integrity: sha512-O6gVfql3uFZNq9yaUDa98VgV58BqaUSeOUnhZwLzpB/4VlqzTyW6/kvFxhKcSp7f+GmrMQaV4PXRs+tZcq6EFw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-code@2.11.2': + resolution: {integrity: sha512-G8vvb17QAYQij3haz9RoDvArK1LSOZHqGzQ2dJ3/d0W5oqOyUrTnseN66fRZjWhBT3pns0VL2erwe/NBIqLOIw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-document@2.11.2': + resolution: {integrity: sha512-/EZhIAN1x7DYgGM0xv7y7wo5ceBmHb0+rOIPuBerVFeTn+VcC3tST/Q64bdvcxgNe2E59Ti0CUdYEA51wc2u5Q==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-dropcursor@2.11.2': + resolution: {integrity: sha512-HbXC9cMVZUY3kyKwbDtVH452CY1qlyLbIvTaN0+dxkFgcVeQZZtfIxU7DwMmqCDmDnsh0CdDqUgUvcXS2UQTwA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-floating-menu@2.11.2': + resolution: {integrity: sha512-DoFGgguE24rxPkZTD7sH3GFi9E3JKQGeGw0sFTwXx1ZFnyCtqbLcPOfT4THlvUEcixt68Mk48M1NTFVOGn/dyA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-gapcursor@2.11.2': + resolution: {integrity: sha512-ssJOrcc8dzlo5/Qq3+EixASDHTj3mqCyAv7Ohed1QYEYr+TsSpsTbjR0eMLjWHlgbt24TXL2Wr0ldjYCU8T1ZA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-hard-break@2.11.2': + resolution: {integrity: sha512-FNcXemfuwkiP4drZ9m90BC6GD4nyikfYHYEUyYuVd74Mm6w5vXpueWXus3mUcdT78xTs1XpQVibDorilLu7X8w==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-heading@2.11.2': + resolution: {integrity: sha512-y/wAEXYB0a8y5WmSYGCIXAhus1ydudn0pokKIzT/OD00XutAVh14qOB5h/+m8iXwGU/UYMP7SUCtK82txZqwKA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-history@2.11.2': + resolution: {integrity: sha512-BamS6YjKsETgP7msmm0oIpqmNSLJWbivm3XurR3uSUqJZYrQo1Fv+No4HAR7eAACxoOnYGcDmYsrombRVs9lxw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-horizontal-rule@2.11.2': + resolution: {integrity: sha512-R7MkTQzxkBy0bXJfq6L+6ax01/hmTEUvPPoyjwDSfU1Ktc1ihBJGUdTNtohT1KoQGQYt2d9khBohVspsXoCmFw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-image@2.11.2': + resolution: {integrity: sha512-Ag+Arj6sclTqhvR+v5I2UD5e2lsWTcXLj0aS2aEsfGpytltk6rcLj6iDjx/SmJrE1BN8ognJsdzmFdZF/rNLpg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-italic@2.11.2': + resolution: {integrity: sha512-652oTa+iDiR7sMtmePSy+303HSNJxvxmV/6IvQoMdffJU0oPiWcWnCCL0qrWgtHh15dplj36EtB/znENWbvVOw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-link@2.11.2': + resolution: {integrity: sha512-Mbre+JotLMUg9jdWWrwIReiRVMkA2kMzmtD2Aqy/n5P+wuI84898qIZSkhPEzDOGzp0mluUO/iGsz0NdTto/JQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-list-item@2.11.2': + resolution: {integrity: sha512-cxysDCvw45bem53qLZtTCkle1pttO4Y/FGqYm1hl66ol3cZsuLbjpOb4aDB6wRhyd701Ws6MjOYM+cZsmtTNpw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-ordered-list@2.11.2': + resolution: {integrity: sha512-TR8OqwKkQ0OCp40V9hcRJUcO1PSzCYWXy0mvW351lOYO8D6uE+1ouVkEV9qjXBC30sVCnQykSp/FR9UjsIuiVw==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-paragraph@2.11.2': + resolution: {integrity: sha512-iydTjeZbPJuqctOaAx7QebLPvz9J/hBxPptuhe4GZmqInknAk7+SFJagYeGNb14wfXKOvDZ9DMqv6mBiqSA90Q==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-placeholder@2.11.2': + resolution: {integrity: sha512-7rv6nylqX57Q+K+AH794Kg9U7OrLyujhXXqQvd9iZdBP7bTCNUlFu0cGlIyHdM/eWJjoUblZs0VLV2IApk4xjQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-strike@2.11.2': + resolution: {integrity: sha512-n/rznmhqFlENGSlFY9t3pWnWzSmvDpUj3sjVhdpYteis+OCzabN9+c5KdQTBPMjtwRuRleQiKWnHmxvif0heEg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text-style@2.11.2': + resolution: {integrity: sha512-RAa7BTwEOJRZN3EB2lg03KXyu7JC/Ce96cerh3D0Fo78yrtKOArPaiVHoTki6ZEIG43ccHEit1PPjMYxivPPeg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text@2.11.2': + resolution: {integrity: sha512-fJZeKYM5jeJ7NpS3FWLnC/NAvg+mZNbcTaRgXMo5ljBCgiMcYHhYg9p/RHk4SeICZBBpR9WSSZXHMACd9CbJiA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/pm@2.11.2': + resolution: {integrity: sha512-lNOMFRcD0mGy7Hf8tFMHW/fnglvq3dA0grs0QrSY4cHyYbH9BHtQjLMDceczXdXbXZq7nEqC40UBWNnqtaclpw==} + + '@tiptap/starter-kit@2.11.2': + resolution: {integrity: sha512-FUIblP9BSmBzskf/aX7AIcUK5XP5Gi/VqUqm5evCkzlR1FrggLoy+vY+CX0me4oE/WYk4KAgIRXkE9tcbwotQA==} + + '@tiptap/suggestion@2.11.2': + resolution: {integrity: sha512-jA06veq7Ko7+yeyy4pymTGdqHfWNydDIioPCR0yddbon+3+aLP2hE31J+/1/8FmhSoE0qJsEki3/RU7pKTLgrg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/vue-3@2.11.2': + resolution: {integrity: sha512-lbWbT3PimpvKv8+dX2rf5OxjeLGzu/gq0sOi7uNoHMm+nEHa3ztaJSwvx/6WflU59Pt1dyFMvQPTx9zMbx6umQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + vue: ^3.0.0 + + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-collection@1.0.13': + resolution: {integrity: sha512-v0Rgw3IZebRyamcwVmtTDCZ8OmQcj4siaYjNc7wGMZT7PmdSHawGsCOQMxyLvZ7lWjfohYLK0oXtilMOMgfY8A==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@1.0.11': + resolution: {integrity: sha512-4pQMp8ldf7UaB/gR8Fvvy69psNHkTpD/pVw3vmEi8iZAB9EPMBruB1JvHO4BIq9QkUUd2lV1F5YXpMNj7JPBpw==} + + '@types/d3-path@3.1.0': + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-sankey@0.11.2': + resolution: {integrity: sha512-U6SrTWUERSlOhnpSrgvMX64WblX1AxX6nEjI2t3mLK2USpQrnbwYYK+AS9SwiE7wgYmOsSSKoSdr8aoKBH0HgQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.8': + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@1.3.12': + resolution: {integrity: sha512-8oMzcd4+poSLGgV0R1Q1rOlx/xdmozS4Xab7np0eamFFUYq71AU9pOCJEFnkXW2aI/oXdVYJzw6pssbSut7Z9Q==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/dagre@0.7.52': + resolution: {integrity: sha512-XKJdy+OClLk3hketHi9Qg6gTfe1F3y+UFnHxKA2rn9Dw+oXa4Gb378Ztz9HlMgZKSxpPmn4BNVh9wgkpvrK1uw==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/geojson@7946.0.15': + resolution: {integrity: sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==} + + '@types/leaflet@1.7.6': + resolution: {integrity: sha512-Emkz3V08QnlelSbpT46OEAx+TBZYTOX2r1yM7W+hWg5+djHtQ1GbEXBDRLaqQDOYcDI51Ss0ayoqoKD4CtLUDA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/mapbox__point-geometry@0.1.4': + resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==} + + '@types/mapbox__vector-tile@1.3.4': + resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/node@22.10.5': + resolution: {integrity: sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/pbf@3.0.5': + resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} + + '@types/prismjs@1.26.5': + resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} + + '@types/sinonjs__fake-timers@8.1.1': + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + + '@types/sizzle@2.3.9': + resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} + + '@types/supercluster@5.0.3': + resolution: {integrity: sha512-XMSqQEr7YDuNtFwSgaHHOjsbi0ZGL62V9Js4CW45RBuRYlNWSW/KDqN+RFFE7HdHcGhJPtN0klKvw06r9Kg7rg==} + + '@types/three@0.135.0': + resolution: {integrity: sha512-l7WLhIHjhHMtlpyTSltPPAKLpiMwgMD1hXHj59AVUpYRoZP7Fd9NNOSRSvZBCPLpTHPYojgQvSJCoza9zoL7bg==} + + '@types/throttle-debounce@5.0.2': + resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==} + + '@types/topojson-client@3.1.5': + resolution: {integrity: sha512-C79rySTyPxnQNNguTZNI1Ct4D7IXgvyAs3p9HPecnl6mNrJ5+UhvGNYcZfpROYV2lMHI48kJPxwR+F9C6c7nmw==} + + '@types/topojson-server@3.0.4': + resolution: {integrity: sha512-5+ieK8ePfP+K2VH6Vgs1VCt+fO1U8XZHj0UsF+NktaF0DavAo1q3IvCBXgokk/xmtvoPltSUs6vxuR/zMdOE1g==} + + '@types/topojson-simplify@3.0.3': + resolution: {integrity: sha512-sBO5UZ0O2dB0bNwo0vut2yLHhj3neUGi9uL7/ROdm8Gs6dtt4jcB9OGDKr+M2isZwQM2RuzVmifnMZpxj4IGNw==} + + '@types/topojson-specification@1.0.5': + resolution: {integrity: sha512-C7KvcQh+C2nr6Y2Ub4YfgvWvWCgP2nOQMtfhlnwsRL4pYmmwzBS7HclGiS87eQfDOU/DLQpX6GEscviaz4yLIQ==} + + '@types/topojson@3.2.6': + resolution: {integrity: sha512-ppfdlxjxofWJ66XdLgIlER/85RvpGyfOf8jrWf+3kVIjEatFxEZYD/Ea83jO672Xu1HRzd/ghwlbcZIUNHTskw==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@ungap/structured-clone@1.2.1': + resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} + + '@unovis/dagre-layout@0.8.8-2': + resolution: {integrity: sha512-ZfDvfcYtzzhZhgKZty8XDi+zQIotfRqfNVF5M3dFQ9d9C5MTaRdbeBnPUkNrmlLJGgQ42HMOE2ajZLfm2VlRhg==} + + '@unovis/graphlibrary@2.2.0-2': + resolution: {integrity: sha512-HeEzpd/vDyWiIJt0rnh+2ICXUIuF2N0+Z9OJJiKg0DB+eFUcD+bk+9QPhYHwkFwfxdjDA9fHi1DZ/O/bbV58Nw==} + + '@unovis/ts@1.5.0': + resolution: {integrity: sha512-dMRlhBKwazkGxg65xXl4KHvmqX0+2C5qJsUqTFjcg/59G9RCjej9uFF4qsk0x3zY/FnAvK4AjKQYygQfBWzd+w==} + + '@unovis/vue@1.5.0': + resolution: {integrity: sha512-ZHdHPTpefhggJZEWJJI/q7N0mJbRj1TgItt4uzObXzrq0TadxrzSstXMUw4cPgbJcfi8d622YDQhRpr4tApKBw==} + peerDependencies: + '@unovis/ts': 1.5.0 + vue: ^3 + + '@unovue/detypes@0.8.4': + resolution: {integrity: sha512-xbXzPFqdlQHS/kTMFGPPTl+dsGUL92ojrB/z8wQ9TKjuC9N1+sgnVivp7R5a0hMr2B47FjJVtz3yegXyu4MSOA==} + engines: {node: '>=18'} + hasBin: true + + '@vee-validate/zod@4.15.0': + resolution: {integrity: sha512-MpvIKiyg9X5yD8bJW0no2AU7wtR2T5mrvD9tuPRiie951sU2n6QKgMV38qKKOiqFBCxsMSjIuLLLV3V5kVE4nQ==} + peerDependencies: + zod: ^3.24.0 + + '@vitejs/plugin-vue@5.2.1': + resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@vitest/expect@2.1.8': + resolution: {integrity: sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==} + + '@vitest/mocker@2.1.8': + resolution: {integrity: sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.8': + resolution: {integrity: sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==} + + '@vitest/runner@2.1.8': + resolution: {integrity: sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==} + + '@vitest/snapshot@2.1.8': + resolution: {integrity: sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==} + + '@vitest/spy@2.1.8': + resolution: {integrity: sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==} + + '@vitest/ui@2.1.8': + resolution: {integrity: sha512-5zPJ1fs0ixSVSs5+5V2XJjXLmNzjugHRyV11RqxYVR+oMcogZ9qTuSfKW+OcTV0JeFNznI83BNylzH6SSNJ1+w==} + peerDependencies: + vitest: 2.1.8 + + '@vitest/utils@2.1.8': + resolution: {integrity: sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==} + + '@vue/compiler-core@3.5.13': + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + + '@vue/compiler-dom@3.5.13': + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + + '@vue/compiler-sfc@3.5.13': + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + + '@vue/compiler-ssr@3.5.13': + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-api@7.7.0': + resolution: {integrity: sha512-bHEv6kT85BHtyGgDhE07bAUMAy7zpv6nnR004nSTd0wWMrAOtcrYoXO5iyr20Hkf5jR8obQOfS3byW+I3l2CCA==} + + '@vue/devtools-kit@7.7.0': + resolution: {integrity: sha512-5cvZ+6SA88zKC8XiuxUfqpdTwVjJbvYnQZY5NReh7qlSGPvVDjjzyEtW+gdzLXNSd8tStgOjAdMCpvDQamUXtA==} + + '@vue/devtools-shared@7.7.0': + resolution: {integrity: sha512-jtlQY26R5thQxW9YQTpXbI0HoK0Wf9Rd4ekidOkRvSy7ChfK0kIU6vvcBtjj87/EcpeOSK49fZAicaFNJcoTcQ==} + + '@vue/eslint-config-prettier@8.0.0': + resolution: {integrity: sha512-55dPqtC4PM/yBjhAr+yEw6+7KzzdkBuLmnhBrDfp4I48+wy+Giqqj9yUr5T2uD/BkBROjjmqnLZmXRdOx/VtQg==} + peerDependencies: + eslint: '>= 8.0.0' + prettier: '>= 3.0.0' + + '@vue/reactivity@3.5.13': + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + + '@vue/runtime-core@3.5.13': + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + + '@vue/runtime-dom@3.5.13': + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + + '@vue/server-renderer@3.5.13': + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + + '@vue/shared@3.5.13': + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + '@vuedx/template-ast-types@0.7.1': + resolution: {integrity: sha512-Mqugk/F0lFN2u9bhimH6G1kSu2hhLi2WoqgCVxrMvgxm2kDc30DtdvVGRq+UgEmKVP61OudcMtZqkUoGQeFBUQ==} + + '@vueup/vue-quill@1.2.0': + resolution: {integrity: sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==} + peerDependencies: + vue: ^3.2.41 + + '@vueuse/core@10.11.1': + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + + '@vueuse/core@12.4.0': + resolution: {integrity: sha512-XnjQYcJwCsyXyIafyA6SvyN/OBtfPnjvJmbxNxQjCcyWD198urwm5TYvIUUyAxEAN0K7HJggOgT15cOlWFyLeA==} + + '@vueuse/metadata@10.11.1': + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + + '@vueuse/metadata@12.4.0': + resolution: {integrity: sha512-AhPuHs/qtYrKHUlEoNO6zCXufu8OgbR8S/n2oMw1OQuBQJ3+HOLQ+EpvXs+feOlZMa0p8QVvDWNlmcJJY8rW2g==} + + '@vueuse/shared@10.11.1': + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + + '@vueuse/shared@12.4.0': + resolution: {integrity: sha512-9yLgbHVIF12OSCojnjTIoZL1+UA10+O4E1aD6Hpfo/DKVm5o3SZIwz6CupqGy3+IcKI8d6Jnl26EQj/YucnW0Q==} + + '@withtypes/mime@0.1.2': + resolution: {integrity: sha512-PB9BfZGzwblUONJY0LiOwsHCA6uV3DIPj/w9ReekdHxPOl0VdUFgI5s4avKycuuq9Gf5Nz2ZPA2O36GAUzlMPA==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + add@2.0.6: + resolution: {integrity: sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==} + + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + + asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types@0.14.2: + resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} + engines: {node: '>=4'} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + + aws4@1.13.2: + resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + + axios@1.7.9: + resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==} + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + birpc@0.2.19: + resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} + + blob-util@2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.24.4: + resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + c12@2.0.1: + resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cachedir@2.4.0: + resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} + engines: {node: '>=6'} + + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001692: + resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==} + + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + ci-info@4.1.0: + resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==} + engines: {node: '>=8'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-progress@3.12.0: + resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==} + engines: {node: '>=4'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + + clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + codeflask@1.4.1: + resolution: {integrity: sha512-4vb2IbE/iwvP0Uubhd2ixVeysm3KNC2pl7SoDaisxq1juhZzvap3qbaX7B2CtpQVvv5V9sjcQK8hO0eTcY0V9Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.3.3: + resolution: {integrity: sha512-Qil5KwghMzlqd51UXM0b6fyaGHtOC22scxrwrz4A2882LyUMwQjnvaedN1HAeXzphspQ6CpHkzMAWxBTUruDLg==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cropperjs@1.6.2: + resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-select@5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + + css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + + css@3.0.0: + resolution: {integrity: sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==} + + csscolorparser@1.0.3: + resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + cypress@13.17.0: + resolution: {integrity: sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==} + engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} + hasBin: true + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-collection@1.0.7: + resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo-projection@4.0.0: + resolution: {integrity: sha512-p0bK60CEzph1iqmnxut7d/1kyTmm3UWtPlwdkM31AU+LW+BXazd5zJdoCn7VFxNCHXRngPHRnsNn5uGjLRGndg==} + engines: {node: '>=12'} + hasBin: true + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate-path@2.3.0: + resolution: {integrity: sha512-tZYtGXxBmbgHsIc9Wms6LS5u4w6KbP8C09a4/ZYc4KLMYYqub57rRBUgpUr2CIarIrJEpdAWWxWQvofgaMpbKQ==} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + deep-diff@1.0.2: + resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-equal@1.1.2: + resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} + engines: {node: '>= 0.4'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + earcut@2.2.4: + resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + + electron-to-chromium@1.5.80: + resolution: {integrity: sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==} + + elkjs@0.8.2: + resolution: {integrity: sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.6.0: + resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@8.10.0: + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-cypress@2.15.2: + resolution: {integrity: sha512-CtcFEQTDKyftpI22FVGpx8bkpKyYXBlNge6zSo0pl5/qJvBAnzaD76Vu2AsP16d6mTj478Ldn2mhgrWV+Xr0vQ==} + peerDependencies: + eslint: '>= 3.2.1' + + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-vue@9.32.0: + resolution: {integrity: sha512-b/Y05HYmnB/32wqVcjxjHZzNpwxj1onBOvqW89W+V+XNG1dRuaFbNd3vT9CLbr2LXjEoq+3vn8DanWf7XU22Ug==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + + eventemitter2@6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + + eventemitter3@2.0.3: + resolution: {integrity: sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==} + + execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + executable@4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + + expect-type@1.1.0: + resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==} + engines: {node: '>=12.0.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.1.2: + resolution: {integrity: sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==} + + fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.5: + resolution: {integrity: sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==} + + fastq@1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fdir@6.4.2: + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + geojson-vt@3.2.1: + resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} + + geojson@0.5.0: + resolution: {integrity: sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==} + engines: {node: '>= 0.10'} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + getos@3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + + getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + + giget@1.2.3: + resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==} + hasBin: true + + gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@11.0.1: + resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} + engines: {node: 20 || >=22} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + gonzales-pe@4.3.0: + resolution: {integrity: sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==} + engines: {node: '>=0.6.0'} + hasBin: true + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + http-signature@1.4.0: + resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==} + engines: {node: '>=0.10'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + immutable@5.0.3: + resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + + install@0.13.0: + resolution: {integrity: sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==} + engines: {node: '>= 0.10'} + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.0.2: + resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} + engines: {node: 20 || >=22} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + + kdbush@3.0.0: + resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + + leaflet@1.7.1: + resolution: {integrity: sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==} + + lettersanitizer@1.0.6: + resolution: {integrity: sha512-2vj0tUtBRjlmTCFsgVlFmfi04p049Zwv/4eBGWBUOKropEoL+q+jTQQfFyDu50j7gL76pycMvrqD0uV0vxX2zg==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.2.0: + resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==} + + listr2@3.14.0: + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + + lodash.sortedlastindex@4.1.0: + resolution: {integrity: sha512-s8xEQdsp2Tu5zUqVdFSe9C0kR8YlnAJYLqMdkh+pIRBRxF6/apWseLdHl3/+jv2I61dhPwtI/Ff+EqvCpc+N8w==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + + log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.0.2: + resolution: {integrity: sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-vue-next@0.378.0: + resolution: {integrity: sha512-tz2IUhdOf1q0x1mPOTZEJZYfXVLreQorO2ax4M+CxGOTgCNgXH3cljIWWfJ4jUvxn5rbkFlGPbl9EIfIelZBRA==} + peerDependencies: + vue: '>=3.0.1' + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + + maplibre-gl@2.4.0: + resolution: {integrity: sha512-csNFylzntPmHWidczfgCZpvbTSmhaWvLRj9e1ezUDBEPizGgshgm3ea1T5TCNEEBq0roauu7BPuRZjA3wO4KqA==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.7.3: + resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@5.0.9: + resolution: {integrity: sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==} + engines: {node: ^18 || >=20} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + + node-html-parser@6.1.13: + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm@10.9.2: + resolution: {integrity: sha512-iriPEPIkoMYUy3F6f3wwSZAU93E0Eg6cHwIR6jzzOXWSy+SD/rOODEs74cVONHKSx2obXtuUoyidVEhISrisgQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/package-json' + - '@npmcli/promise-spawn' + - '@npmcli/redact' + - '@npmcli/run-script' + - '@sigstore/tuf' + - abbrev + - archy + - cacache + - chalk + - ci-info + - cli-columns + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmhook + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - normalize-package-data + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + - write-file-atomic + + npx@10.2.2: + resolution: {integrity: sha512-eImmySusyeWphzs5iNh791XbZnZG0FSNvM4KSah34pdQQIDsdTDhIwg1sjN3AIVcjGLpbQ/YcfqHPshKZQK1fA==} + deprecated: This package is now part of the npm CLI. + hasBin: true + bundledDependencies: + - npm + - libnpx + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nypm@0.3.12: + resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-inspect@1.13.3: + resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + engines: {node: '>= 0.4'} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + + ohash@1.1.4: + resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ora@8.1.1: + resolution: {integrity: sha512-YWielGi1XzG1UTvOaCFaNgEnuhZVMSHYkW/FQ7UX8O26PtlpdM84c0f7wLPlkvx2RfiQmnzd61d/MGxmpQeJPw==} + engines: {node: '>=18'} + + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + + ospath@1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parchment@1.1.4: + resolution: {integrity: sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-unit@1.0.1: + resolution: {integrity: sha512-hrqldJHokR3Qj88EIlV/kAyAi/G5R2+R56TBANxNMy0uPlYcttx0jnMW6Yx5KsKPSbC3KddM/7qQm3+0wEXKxg==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + + pbf@3.3.0: + resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==} + hasBin: true + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pinia@2.3.0: + resolution: {integrity: sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==} + peerDependencies: + typescript: '>=4.4.4' + vue: ^2.7.0 || ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-types@1.3.0: + resolution: {integrity: sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg==} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.0.1: + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-less@6.0.0: + resolution: {integrity: sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==} + engines: {node: '>=12'} + peerDependencies: + postcss: ^8.3.5 + + postcss-load-config@4.0.2: + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-sass@0.5.0: + resolution: {integrity: sha512-qtu8awh1NMF3o9j/x9j3EZnd+BlF66X6NZYl12BdKoG2Z4hmydOt/dZj2Nq+g0kfk2pQy3jeYFBmvG9DBwynGQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-styl@0.12.3: + resolution: {integrity: sha512-8I7Cd8sxiEITIp32xBK4K/Aj1ukX6vuWnx8oY/oAH35NfQI4OZaY5nd68Yx8HeN5S49uhQ6DL0rNk0ZBu/TaLg==} + engines: {node: ^8.10.0 || ^10.13.0 || ^11.10.1 || >=12.13.0} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + potpack@1.0.2: + resolution: {integrity: sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + + prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prosemirror-changeset@2.2.1: + resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.6.2: + resolution: {integrity: sha512-0nDHH++qcf/BuPLYvmqZTUUsPJUCPBUXt0J1ErTcDIS369CTp773itzLGIgIXG4LJXOlwYCr44+Mh4ii6MP1QA==} + + prosemirror-dropcursor@1.8.1: + resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + + prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + + prosemirror-inputrules@1.4.0: + resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + + prosemirror-keymap@1.2.2: + resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + + prosemirror-markdown@1.13.1: + resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} + + prosemirror-menu@1.2.4: + resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + + prosemirror-model@1.24.1: + resolution: {integrity: sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==} + + prosemirror-schema-basic@1.2.3: + resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} + + prosemirror-schema-list@1.5.0: + resolution: {integrity: sha512-gg1tAfH1sqpECdhIHOA/aLg2VH3ROKBWQ4m8Qp9mBKrOxQRW61zc+gMCI8nh22gnBzd1t2u1/NPLmO3nAa3ssg==} + + prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + + prosemirror-tables@1.6.2: + resolution: {integrity: sha512-97dKocVLrEVTQjZ4GBLdrrMw7Gv3no8H8yMwf5IRM9OoHrzbWpcH5jJxYgNQIRCtdIqwDctT1HdMHrGTiwp1dQ==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.10.2: + resolution: {integrity: sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==} + + prosemirror-view@1.37.1: + resolution: {integrity: sha512-MEAnjOdXU1InxEmhjgmEzQAikaS6lF3hD64MveTPpjOGNTl87iRLA1HupC/DEV6YuK7m4Q9DHFNTjwIVtqz5NA==} + + protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + + proxy-from-env@1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.13.1: + resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quickselect@2.0.0: + resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + + quill-delta@3.6.3: + resolution: {integrity: sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==} + engines: {node: '>=0.10'} + + quill-delta@4.2.2: + resolution: {integrity: sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==} + + quill@1.3.7: + resolution: {integrity: sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==} + + radix-vue@1.9.12: + resolution: {integrity: sha512-zkr66Jqxbej4+oR6O/pZRzyM/VZi66ndbyIBZQjJKAXa1lIoYReZJse6W1EEDZKXknD7rXhpS+jM9Sr23lIqfg==} + peerDependencies: + vue: '>= 3.2.0' + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + + recast@0.23.9: + resolution: {integrity: sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==} + engines: {node: '>= 4'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + request-progress@3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup@4.30.1: + resolution: {integrity: sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sass@1.83.1: + resolution: {integrity: sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==} + engines: {node: '>=14.0.0'} + hasBin: true + + sax@1.2.4: + resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + shadcn-vue@0.11.3: + resolution: {integrity: sha512-iPRKQRdVB21lUBPBrKyTJk6qNrT2HhOBeg1taqy94+/OpuCTAO84NskFl6v7Ln8LB2PXUH45qUtJP2x+SHKyqw==} + hasBin: true + peerDependencies: + '@vitest/ui': '*' + vitest: '*' + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + sortablejs@1.14.0: + resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-resolve@0.6.0: + resolution: {integrity: sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + start-server-and-test@2.0.9: + resolution: {integrity: sha512-DDceIvc4wdpr+z3Aqkot2QMho8TcUBh5qH0wEHDpEexBTzlheOcmh53d3dExABY4J5C7qS2UbSXqRWLtxpbWIQ==} + engines: {node: '>=16'} + hasBin: true + + std-env@3.8.0: + resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + + stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + striptags@3.2.0: + resolution: {integrity: sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==} + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + stylus@0.57.0: + resolution: {integrity: sha512-yOI6G8WYfr0q8v8rRvE91wbxFU+rJPo760Va4MF6K0I6BZjO4r+xSynkvyPBP9tV1CIEUeRsiidjIs2rzb1CnQ==} + hasBin: true + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supercluster@7.1.5: + resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==} + + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.9.2: + resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + engines: {node: ^14.18.0 || >=16.0.0} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.17: + resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} + engines: {node: '>=14.0.0'} + hasBin: true + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + textarea@0.3.0: + resolution: {integrity: sha512-mLIr1WYhuoPNuq7Tz8kf0g/VFr0q1BnwScX820WITbyq7MTPbmxK1oVyeoYCzCFjBAcE2MNIBpIBDV1Ctyqxrg==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + three@0.135.0: + resolution: {integrity: sha512-kuEpuuxRzLv0MDsXai9huCxOSQPZ4vje6y0gn80SRmQvgz6/+rI0NAvCRAw56zYaWKMGMfqKWsxF9Qa2Z9xymQ==} + + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + throttleit@1.0.1: + resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.10: + resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + engines: {node: '>=12.0.0'} + + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyqueue@2.0.3: + resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + tldts-core@6.1.71: + resolution: {integrity: sha512-LRbChn2YRpic1KxY+ldL1pGXN/oVvKfCVufwfVzEQdFYNo39uF7AJa/WXdo+gYO7PTvdfkCPCed6Hkvz/kR7jg==} + + tldts@6.1.71: + resolution: {integrity: sha512-LQIHmHnuzfZgZWAf2HzL83TIIrD8NhhI0DVxqo9/FdOd4ilec+NTNZOlDZf7EwrTNoutccbsHjvWHYXLAtvxjw==} + hasBin: true + + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + + to-px@1.1.0: + resolution: {integrity: sha512-bfg3GLYrGoEzrGoE05TAL/Uw+H/qrf2ptr9V3W7U0lkjjyYnIfgxmVLUfhQ1hZpIQwin81uxhDjvUkDYsC0xWw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + topojson-client@3.1.0: + resolution: {integrity: sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==} + hasBin: true + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tough-cookie@5.1.0: + resolution: {integrity: sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==} + engines: {node: '>=16'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.32.0: + resolution: {integrity: sha512-rfgpoi08xagF3JSdtJlCwMq9DGNDE0IMh3Mkpc1wUypg9vPi786AiqeBBKcqvIkq42azsBM85N490fyZjeUftw==} + engines: {node: '>=16'} + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + + update-browserslist-db@1.1.2: + resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + vee-validate@4.15.0: + resolution: {integrity: sha512-PGJh1QCFwCBjbHu5aN6vB8macYVWrajbDvgo1Y/8fz9n/RVIkLmZCJDpUgu7+mUmCOPMxeyq7vXUOhbwAqdXcA==} + peerDependencies: + vue: ^3.4.26 + + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + + vite-node@2.1.8: + resolution: {integrity: sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.8: + resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.8 + '@vitest/ui': 2.1.8 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vt-pbf@3.1.3: + resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-eslint-parser@9.4.3: + resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + + vue-i18n@9.14.2: + resolution: {integrity: sha512-JK9Pm80OqssGJU2Y6F7DcM8RFHqVG4WkuCqOZTVsXkEzZME7ABejAUqUdA931zEBedc4thBgSUWxeQh4uocJAQ==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + + vue-letter@0.2.0: + resolution: {integrity: sha512-p4qHpw89GKidKyGcg4J4IjUcMQuVaTJq83c6UE4616claaLF9rj2Bg/Hq19uDCmokd+SvzEwxq6/ctfaaednkw==} + + vue-metamorph@3.2.0: + resolution: {integrity: sha512-dCWwwh7OngblFqUvD/pilS++TVnTHY1Nft2Tp02mHYv8ZrxFHN3NDMOKOoIg8lo7WR3TKxi3+bD/rmnN9tS2yw==} + hasBin: true + + vue-picture-cropper@0.7.0: + resolution: {integrity: sha512-NF7+Dgso6d0GB16E5d/BbrcTIHm1VWz8dS3IjLhoBl+ZeC+yDA46CyJphQuO32SisaPmrKHN8VbiE2LgAfhnkQ==} + peerDependencies: + vue: '>=3.2.13' + + vue-router@4.5.0: + resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} + peerDependencies: + vue: ^3.2.0 + + vue-sonner@1.3.0: + resolution: {integrity: sha512-jAodBy4Mri8rQjVZGQAPs4ZYymc1ywPiwfa81qU0fFl+Suk7U8NaOxIDdI1oBGLeQJqRZi/oxNIuhCLqsBmOwg==} + + vue3-emoji-picker@1.1.8: + resolution: {integrity: sha512-k9tVHeQEBVLzVCLYAkFaI1nib3FJFQwdPhWD5khJkhks3ktg3g12z5wPGOSDpIuSLNtelRGvq1qdmZuJu5khfA==} + engines: {node: '>=16.0.0'} + + vue@3.5.13: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + vuedraggable@4.1.0: + resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} + peerDependencies: + vue: ^3.0.1 + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + wait-on@8.0.1: + resolution: {integrity: sha512-1wWQOyR2LVVtaqrcIL2+OM+x7bkpmzVROa0Nf6FryXkS+er5Sa1kzFGjzZRqLnHa3n1rACFLeTwUqE1ETL9Mig==} + engines: {node: '>=12.0.0'} + hasBin: true + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yaml@2.7.0: + resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} + engines: {node: '>= 14'} + hasBin: true + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.26.2': + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.26.5': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/helper-compilation-targets': 7.26.5 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + convert-source-map: 2.0.0 + debug: 4.4.0(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.26.5': + dependencies: + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.25.9': + dependencies: + '@babel/types': 7.26.5 + + '@babel/helper-compilation-targets@7.26.5': + dependencies: + '@babel/compat-data': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@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/core@7.26.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/traverse': 7.26.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-member-expression-to-functions@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.25.9': + dependencies: + '@babel/types': 7.26.5 + + '@babel/helper-plugin-utils@7.26.5': {} + + '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-member-expression-to-functions': 7.25.9 + '@babel/helper-optimise-call-expression': 7.25.9 + '@babel/traverse': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.25.9': + dependencies: + '@babel/traverse': 7.26.5 + '@babel/types': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + + '@babel/parser@7.26.5': + dependencies: + '@babel/types': 7.26.5 + + '@babel/parser@8.0.0-alpha.12': {} + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + + '@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.26.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/helper-create-class-features-plugin': 7.25.9(@babel/core@7.26.0) + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/helper-validator-option': 7.25.9 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.0) + '@babel/plugin-transform-typescript': 7.26.5(@babel/core@7.26.0) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.26.0': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.5 + '@babel/types': 7.26.5 + + '@babel/traverse@7.26.5': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.5 + '@babel/parser': 7.26.5 + '@babel/template': 7.25.9 + '@babel/types': 7.26.5 + debug: 4.4.0(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.5': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@bassist/utils@0.4.0': + dependencies: + '@withtypes/mime': 0.1.2 + + '@colors/colors@1.5.0': + optional: true + + '@cypress/request@3.0.7': + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 4.0.1 + http-signature: 1.4.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.13.1 + safe-buffer: 5.2.1 + tough-cookie: 5.1.0 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + + '@cypress/xvfb@1.2.4(supports-color@8.1.1)': + dependencies: + debug: 3.2.7(supports-color@8.1.1) + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/runtime': 7.26.0 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/css@11.13.5': + dependencies: + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + transitivePeerDependencies: + - supports-color + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.1.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.0(supports-color@8.1.1) + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/utils@0.2.9': {} + + '@floating-ui/vue@1.1.6(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@floating-ui/dom': 1.6.13 + '@floating-ui/utils': 0.2.9 + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@formkit/auto-animate@0.8.2': {} + + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.0(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@internationalized/date@3.6.0': + dependencies: + '@swc/helpers': 0.5.15 + + '@internationalized/number@3.6.0': + dependencies: + '@swc/helpers': 0.5.15 + + '@intlify/core-base@9.14.2': + dependencies: + '@intlify/message-compiler': 9.14.2 + '@intlify/shared': 9.14.2 + + '@intlify/message-compiler@9.14.2': + dependencies: + '@intlify/shared': 9.14.2 + source-map-js: 1.2.1 + + '@intlify/shared@9.14.2': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@juggle/resize-observer@3.4.0': {} + + '@mapbox/geojson-rewind@0.5.2': + dependencies: + get-stream: 6.0.1 + minimist: 1.2.8 + + '@mapbox/jsonlint-lines-primitives@2.0.2': {} + + '@mapbox/mapbox-gl-supported@2.0.1': {} + + '@mapbox/point-geometry@0.1.0': {} + + '@mapbox/tiny-sdf@2.0.6': {} + + '@mapbox/unitbezier@0.0.1': {} + + '@mapbox/vector-tile@1.3.1': + dependencies: + '@mapbox/point-geometry': 0.1.0 + + '@mapbox/whoots-js@3.1.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + '@parcel/watcher-android-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-x64@2.5.0': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.0': + optional: true + + '@parcel/watcher-win32-arm64@2.5.0': + optional: true + + '@parcel/watcher-win32-ia32@2.5.0': + optional: true + + '@parcel/watcher-win32-x64@2.5.0': + optional: true + + '@parcel/watcher@2.5.0': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 + optional: true + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.1': {} + + '@polka/url@1.0.0-next.28': {} + + '@popperjs/core@2.11.8': {} + + '@radix-icons/vue@1.0.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + vue: 3.5.13(typescript@5.7.3) + + '@remirror/core-constants@3.0.0': {} + + '@rollup/rollup-android-arm-eabi@4.30.1': + optional: true + + '@rollup/rollup-android-arm64@4.30.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.30.1': + optional: true + + '@rollup/rollup-darwin-x64@4.30.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.30.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.30.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.30.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.30.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.30.1': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.30.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.30.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.30.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.30.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.30.1': + optional: true + + '@rushstack/eslint-patch@1.10.5': {} + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.17 + + '@tanstack/table-core@8.20.5': {} + + '@tanstack/virtual-core@3.11.2': {} + + '@tanstack/vue-table@8.20.5(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@tanstack/table-core': 8.20.5 + vue: 3.5.13(typescript@5.7.3) + + '@tanstack/vue-virtual@3.11.2(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@tanstack/virtual-core': 3.11.2 + vue: 3.5.13(typescript@5.7.3) + + '@tiptap/core@2.11.2(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-blockquote@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-bold@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-bubble-menu@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + tippy.js: 6.3.7 + + '@tiptap/extension-bullet-list@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-code-block@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-code@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-document@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-dropcursor@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-floating-menu@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + tippy.js: 6.3.7 + + '@tiptap/extension-gapcursor@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-hard-break@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-heading@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-history@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-horizontal-rule@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-image@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-italic@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-link@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + linkifyjs: 4.2.0 + + '@tiptap/extension-list-item@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-ordered-list@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-paragraph@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-placeholder@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/extension-strike@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-text-style@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/extension-text@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + + '@tiptap/pm@2.11.2': + dependencies: + prosemirror-changeset: 2.2.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.6.2 + prosemirror-dropcursor: 1.8.1 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.1 + prosemirror-inputrules: 1.4.0 + prosemirror-keymap: 1.2.2 + prosemirror-markdown: 1.13.1 + prosemirror-menu: 1.2.4 + prosemirror-model: 1.24.1 + prosemirror-schema-basic: 1.2.3 + prosemirror-schema-list: 1.5.0 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.6.2 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.1) + prosemirror-transform: 1.10.2 + prosemirror-view: 1.37.1 + + '@tiptap/starter-kit@2.11.2': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/extension-blockquote': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-bold': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-bullet-list': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-code': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-code-block': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-document': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-dropcursor': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-gapcursor': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-hard-break': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-heading': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-history': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-horizontal-rule': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-italic': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-list-item': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-ordered-list': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-paragraph': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-strike': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-text': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/extension-text-style': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2)) + '@tiptap/pm': 2.11.2 + + '@tiptap/suggestion@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + + '@tiptap/vue-3@2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2)(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@tiptap/core': 2.11.2(@tiptap/pm@2.11.2) + '@tiptap/extension-bubble-menu': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/extension-floating-menu': 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))(@tiptap/pm@2.11.2) + '@tiptap/pm': 2.11.2 + vue: 3.5.13(typescript@5.7.3) + + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-collection@1.0.13': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.15 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.15 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@1.0.11': {} + + '@types/d3-path@3.1.0': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-sankey@0.11.2': + dependencies: + '@types/d3-shape': 1.3.12 + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.8': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@1.3.12': + dependencies: + '@types/d3-path': 1.0.11 + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.0 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.0 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.8 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/dagre@0.7.52': {} + + '@types/estree@1.0.6': {} + + '@types/geojson@7946.0.15': {} + + '@types/leaflet@1.7.6': + dependencies: + '@types/geojson': 7946.0.15 + + '@types/linkify-it@5.0.0': {} + + '@types/mapbox__point-geometry@0.1.4': {} + + '@types/mapbox__vector-tile@1.3.4': + dependencies: + '@types/geojson': 7946.0.15 + '@types/mapbox__point-geometry': 0.1.4 + '@types/pbf': 3.0.5 + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + + '@types/node@22.10.5': + dependencies: + undici-types: 6.20.0 + optional: true + + '@types/parse-json@4.0.2': {} + + '@types/pbf@3.0.5': {} + + '@types/prismjs@1.26.5': {} + + '@types/sinonjs__fake-timers@8.1.1': {} + + '@types/sizzle@2.3.9': {} + + '@types/supercluster@5.0.3': + dependencies: + '@types/geojson': 7946.0.15 + + '@types/three@0.135.0': {} + + '@types/throttle-debounce@5.0.2': {} + + '@types/topojson-client@3.1.5': + dependencies: + '@types/geojson': 7946.0.15 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-server@3.0.4': + dependencies: + '@types/geojson': 7946.0.15 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-simplify@3.0.3': + dependencies: + '@types/geojson': 7946.0.15 + '@types/topojson-specification': 1.0.5 + + '@types/topojson-specification@1.0.5': + dependencies: + '@types/geojson': 7946.0.15 + + '@types/topojson@3.2.6': + dependencies: + '@types/geojson': 7946.0.15 + '@types/topojson-client': 3.1.5 + '@types/topojson-server': 3.0.4 + '@types/topojson-simplify': 3.0.3 + '@types/topojson-specification': 1.0.5 + + '@types/web-bluetooth@0.0.20': {} + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 22.10.5 + optional: true + + '@ungap/structured-clone@1.2.1': {} + + '@unovis/dagre-layout@0.8.8-2': + dependencies: + '@unovis/graphlibrary': 2.2.0-2 + lodash-es: 4.17.21 + + '@unovis/graphlibrary@2.2.0-2': + dependencies: + lodash-es: 4.17.21 + + '@unovis/ts@1.5.0': + dependencies: + '@emotion/css': 11.13.5 + '@juggle/resize-observer': 3.4.0 + '@types/d3': 7.4.3 + '@types/d3-collection': 1.0.13 + '@types/d3-sankey': 0.11.2 + '@types/dagre': 0.7.52 + '@types/geojson': 7946.0.15 + '@types/leaflet': 1.7.6 + '@types/supercluster': 5.0.3 + '@types/three': 0.135.0 + '@types/throttle-debounce': 5.0.2 + '@types/topojson': 3.2.6 + '@types/topojson-client': 3.1.5 + '@types/topojson-specification': 1.0.5 + '@unovis/dagre-layout': 0.8.8-2 + '@unovis/graphlibrary': 2.2.0-2 + d3: 7.9.0 + d3-collection: 1.0.7 + d3-geo-projection: 4.0.0 + d3-interpolate-path: 2.3.0 + d3-sankey: 0.12.3 + elkjs: 0.8.2 + geojson: 0.5.0 + leaflet: 1.7.1 + maplibre-gl: 2.4.0 + striptags: 3.2.0 + supercluster: 7.1.5 + three: 0.135.0 + throttle-debounce: 5.0.2 + to-px: 1.1.0 + topojson-client: 3.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@unovis/vue@1.5.0(@unovis/ts@1.5.0)(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@unovis/ts': 1.5.0 + vue: 3.5.13(typescript@5.7.3) + + '@unovue/detypes@0.8.4': + dependencies: + '@babel/core': 7.26.0 + '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vuedx/template-ast-types': 0.7.1 + fast-glob: 3.3.3 + prettier: 3.4.2 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@vee-validate/zod@4.15.0(vue@3.5.13(typescript@5.7.3))(zod@3.24.1)': + dependencies: + type-fest: 4.32.0 + vee-validate: 4.15.0(vue@3.5.13(typescript@5.7.3)) + zod: 3.24.1 + transitivePeerDependencies: + - vue + + '@vitejs/plugin-vue@5.2.1(vite@5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0))(vue@3.5.13(typescript@5.7.3))': + dependencies: + vite: 5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + vue: 3.5.13(typescript@5.7.3) + + '@vitest/expect@2.1.8': + dependencies: + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.8(vite@5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0))': + dependencies: + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + + '@vitest/pretty-format@2.1.8': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.8': + dependencies: + '@vitest/utils': 2.1.8 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + magic-string: 0.30.17 + pathe: 1.1.2 + + '@vitest/spy@2.1.8': + dependencies: + tinyspy: 3.0.2 + + '@vitest/ui@2.1.8(vitest@2.1.8)': + dependencies: + '@vitest/utils': 2.1.8 + fflate: 0.8.2 + flatted: 3.3.2 + pathe: 1.1.2 + sirv: 3.0.0 + tinyglobby: 0.2.10 + tinyrainbow: 1.2.0 + vitest: 2.1.8(@types/node@22.10.5)(@vitest/ui@2.1.8)(sass@1.83.1)(stylus@0.57.0) + + '@vitest/utils@2.1.8': + dependencies: + '@vitest/pretty-format': 2.1.8 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + + '@vue/compiler-core@3.5.13': + dependencies: + '@babel/parser': 7.26.5 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.13': + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/compiler-sfc@3.5.13': + dependencies: + '@babel/parser': 7.26.5 + '@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.17 + postcss: 8.4.49 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.13': + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-api@7.7.0': + dependencies: + '@vue/devtools-kit': 7.7.0 + + '@vue/devtools-kit@7.7.0': + dependencies: + '@vue/devtools-shared': 7.7.0 + birpc: 0.2.19 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.2 + + '@vue/devtools-shared@7.7.0': + dependencies: + rfdc: 1.4.1 + + '@vue/eslint-config-prettier@8.0.0(eslint@8.57.1)(prettier@3.4.2)': + dependencies: + eslint: 8.57.1 + eslint-config-prettier: 8.10.0(eslint@8.57.1) + eslint-plugin-prettier: 5.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2) + prettier: 3.4.2 + transitivePeerDependencies: + - '@types/eslint' + + '@vue/reactivity@3.5.13': + dependencies: + '@vue/shared': 3.5.13 + + '@vue/runtime-core@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + '@vue/runtime-dom@3.5.13': + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13(typescript@5.7.3) + + '@vue/shared@3.5.13': {} + + '@vuedx/template-ast-types@0.7.1': + dependencies: + '@vue/compiler-core': 3.5.13 + + '@vueup/vue-quill@1.2.0(vue@3.5.13(typescript@5.7.3))': + dependencies: + quill: 1.3.7 + quill-delta: 4.2.2 + vue: 3.5.13(typescript@5.7.3) + + '@vueuse/core@10.11.1(vue@3.5.13(typescript@5.7.3))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.13(typescript@5.7.3)) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/core@12.4.0(typescript@5.7.3)': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 12.4.0 + '@vueuse/shared': 12.4.0(typescript@5.7.3) + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - typescript + + '@vueuse/metadata@10.11.1': {} + + '@vueuse/metadata@12.4.0': {} + + '@vueuse/shared@10.11.1(vue@3.5.13(typescript@5.7.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/shared@12.4.0(typescript@5.7.3)': + dependencies: + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - typescript + + '@withtypes/mime@0.1.2': + dependencies: + mime: 3.0.0 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + add@2.0.6: {} + + agent-base@7.1.3: {} + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arch@2.2.0: {} + + arg@5.0.2: {} + + argparse@2.0.1: {} + + aria-hidden@1.2.4: + dependencies: + tslib: 2.8.1 + + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + + assert-plus@1.0.0: {} + + assertion-error@2.0.1: {} + + ast-types@0.14.2: + dependencies: + tslib: 2.8.1 + + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + + astral-regex@2.0.0: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + atob@2.1.2: {} + + autoprefixer@10.4.20(postcss@8.4.49): + dependencies: + browserslist: 4.24.4 + caniuse-lite: 1.0.30001692 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + + aws-sign2@0.7.0: {} + + aws4@1.13.2: {} + + axios@1.7.9(debug@4.4.0): + dependencies: + follow-redirects: 1.15.9(debug@4.4.0) + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.26.0 + cosmiconfig: 7.1.0 + resolve: 1.22.10 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 + + binary-extensions@2.3.0: {} + + birpc@0.2.19: {} + + blob-util@2.0.2: {} + + bluebird@3.7.2: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.24.4: + dependencies: + caniuse-lite: 1.0.30001692 + electron-to-chromium: 1.5.80 + node-releases: 2.0.19 + update-browserslist-db: 1.1.2(browserslist@4.24.4) + + buffer-crc32@0.2.13: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + c12@2.0.1: + dependencies: + chokidar: 4.0.3 + confbox: 0.1.8 + defu: 6.1.4 + dotenv: 16.4.7 + giget: 1.2.3 + jiti: 2.4.2 + mlly: 1.7.3 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.3.0 + rc9: 2.1.2 + + cac@6.7.14: {} + + cachedir@2.4.0: {} + + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + get-intrinsic: 1.2.7 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001692: {} + + caseless@0.12.0: {} + + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.4.1: {} + + check-error@2.1.1: {} + + check-more-types@2.24.0: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.3: + dependencies: + readdirp: 4.0.2 + + chownr@2.0.0: {} + + ci-info@4.1.0: {} + + citty@0.1.6: + dependencies: + consola: 3.3.3 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-progress@3.12.0: + dependencies: + string-width: 4.2.3 + + cli-spinners@2.9.2: {} + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + + clone@2.1.2: {} + + clsx@2.1.1: {} + + codeflask@1.4.1: + dependencies: + '@types/prismjs': 1.26.5 + prismjs: 1.29.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@12.1.0: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@6.2.1: {} + + commander@7.2.0: {} + + common-tags@1.8.2: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + consola@3.3.3: {} + + convert-source-map@1.9.0: {} + + convert-source-map@2.0.0: {} + + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + core-util-is@1.0.2: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + crelt@1.0.6: {} + + cropperjs@1.6.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-select@5.1.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.1.0: {} + + css@3.0.0: + dependencies: + inherits: 2.0.4 + source-map: 0.6.1 + source-map-resolve: 0.6.0 + + csscolorparser@1.0.3: {} + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + cypress@13.17.0: + dependencies: + '@cypress/request': 3.0.7 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.9 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.4.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + ci-info: 4.1.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.5 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.13 + debug: 4.4.0(supports-color@8.1.1) + enquirer: 2.4.1 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.4.1) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.6.3 + supports-color: 8.1.1 + tmp: 0.2.3 + tree-kill: 1.2.2 + untildify: 4.0.0 + yauzl: 2.10.0 + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-collection@1.0.7: {} + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo-projection@4.0.0: + dependencies: + commander: 7.2.0 + d3-array: 3.2.4 + d3-geo: 3.1.1 + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate-path@2.3.0: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dashdash@1.14.1: + dependencies: + assert-plus: 1.0.0 + + date-fns@3.6.0: {} + + dayjs@1.11.13: {} + + debug@3.2.7(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + debug@4.4.0(supports-color@8.1.1): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 8.1.1 + + decode-uri-component@0.2.2: {} + + deep-diff@1.0.2: {} + + deep-eql@5.0.2: {} + + deep-equal@1.1.2: + dependencies: + is-arguments: 1.2.0 + is-date-object: 1.1.0 + is-regex: 1.2.1 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.4 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + defu@6.1.4: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + delayed-stream@1.0.0: {} + + destr@2.0.3: {} + + detect-libc@1.0.3: + optional: true + + didyoumean@1.2.2: {} + + diff@7.0.0: {} + + dlv@1.1.3: {} + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dotenv@16.4.7: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.2: {} + + earcut@2.2.4: {} + + eastasianwidth@0.2.0: {} + + ecc-jsbn@0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + + electron-to-chromium@1.5.80: {} + + elkjs@0.8.2: {} + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + entities@4.5.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.6.0: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@8.10.0(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + + eslint-plugin-cypress@2.15.2(eslint@8.57.1): + dependencies: + eslint: 8.57.1 + globals: 13.24.0 + + eslint-plugin-prettier@5.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.4.2): + dependencies: + eslint: 8.57.1 + prettier: 3.4.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.2 + optionalDependencies: + eslint-config-prettier: 8.10.0(eslint@8.57.1) + + eslint-plugin-vue@9.32.0(eslint@8.57.1): + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + eslint: 8.57.1 + globals: 13.24.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.1.2 + semver: 7.6.3 + vue-eslint-parser: 9.4.3(eslint@8.57.1) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@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.1 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + esutils@2.0.3: {} + + event-stream@3.3.4: + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + + eventemitter2@6.4.7: {} + + eventemitter3@2.0.3: {} + + execa@4.1.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + executable@4.1.1: + dependencies: + pify: 2.3.0 + + expect-type@1.1.0: {} + + extend@3.0.2: {} + + extract-zip@2.0.1(supports-color@8.1.1): + dependencies: + debug: 4.4.0(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.3.0: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.1.2: {} + + fast-diff@1.2.0: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.5: {} + + fastq@1.18.0: + dependencies: + reusify: 1.0.4 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fdir@6.4.2(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fflate@0.8.2: {} + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-root@1.1.0: {} + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.3.2: {} + + follow-redirects@1.15.9(debug@4.4.0): + optionalDependencies: + debug: 4.4.0(supports-color@8.1.1) + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + forever-agent@0.6.1: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + fraction.js@4.3.7: {} + + from@0.1.7: {} + + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + geojson-vt@3.2.1: {} + + geojson@0.5.0: {} + + get-east-asian-width@1.3.0: {} + + get-intrinsic@1.2.7: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + + get-stream@6.0.1: {} + + get-stream@8.0.1: {} + + getos@3.2.1: + dependencies: + async: 3.2.6 + + getpass@0.1.7: + dependencies: + assert-plus: 1.0.0 + + giget@1.2.3: + dependencies: + citty: 0.1.6 + consola: 3.3.3 + defu: 6.1.4 + node-fetch-native: 1.6.4 + nypm: 0.3.12 + ohash: 1.1.4 + pathe: 1.1.2 + tar: 6.2.1 + + gl-matrix@3.4.3: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@11.0.1: + dependencies: + foreground-child: 3.3.0 + jackspeak: 4.0.2 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + global-dirs@3.0.1: + dependencies: + ini: 2.0.0 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globals@11.12.0: {} + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + gonzales-pe@4.3.0: + dependencies: + minimist: 1.2.8 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hookable@5.5.3: {} + + http-signature@1.4.0: + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.18.0 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + human-signals@1.1.1: {} + + human-signals@2.1.0: {} + + human-signals@5.0.0: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + idb@7.1.1: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + immutable@5.0.3: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@2.0.0: {} + + install@0.13.0: {} + + internmap@1.0.1: {} + + internmap@2.0.3: {} + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-installed-globally@0.4.0: + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + + is-interactive@2.0.0: {} + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-typedarray@1.0.0: {} + + is-unicode-supported@0.1.0: {} + + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + + is-what@4.1.16: {} + + isexe@2.0.0: {} + + isstream@0.1.2: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.0.2: + dependencies: + '@isaacs/cliui': 8.0.2 + + jiti@1.21.7: {} + + jiti@2.4.2: {} + + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsbn@0.1.1: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@2.2.3: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsprim@2.0.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + + kdbush@3.0.0: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@6.0.3: {} + + kleur@3.0.3: {} + + lazy-ass@1.6.0: {} + + leaflet@1.7.1: {} + + lettersanitizer@1.0.6: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.2.0: {} + + listr2@3.14.0(enquirer@2.4.1): + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.4.1 + rxjs: 7.8.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + optionalDependencies: + enquirer: 2.4.1 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.17.21: {} + + lodash.castarray@4.4.0: {} + + lodash.clonedeep@4.5.0: {} + + lodash.isequal@4.5.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lodash.once@4.1.1: {} + + lodash.sortedlastindex@4.1.0: {} + + lodash.truncate@4.4.2: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-symbols@6.0.0: + dependencies: + chalk: 5.4.1 + is-unicode-supported: 1.3.0 + + log-update@4.0.0: + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + + loupe@3.1.2: {} + + lru-cache@10.4.3: {} + + lru-cache@11.0.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-vue-next@0.378.0(vue@3.5.13(typescript@5.7.3)): + dependencies: + vue: 3.5.13(typescript@5.7.3) + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + map-stream@0.1.0: {} + + maplibre-gl@2.4.0: + dependencies: + '@mapbox/geojson-rewind': 0.5.2 + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/mapbox-gl-supported': 2.0.1 + '@mapbox/point-geometry': 0.1.0 + '@mapbox/tiny-sdf': 2.0.6 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 1.3.1 + '@mapbox/whoots-js': 3.1.0 + '@types/geojson': 7946.0.15 + '@types/mapbox__point-geometry': 0.1.4 + '@types/mapbox__vector-tile': 1.3.4 + '@types/pbf': 3.0.5 + csscolorparser: 1.0.3 + earcut: 2.2.4 + geojson-vt: 3.2.1 + gl-matrix: 3.4.3 + global-prefix: 3.0.0 + murmurhash-js: 1.0.0 + pbf: 3.3.0 + potpack: 1.0.2 + quickselect: 2.0.0 + supercluster: 7.1.5 + tinyqueue: 2.0.3 + vt-pbf: 3.1.3 + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + math-intrinsics@1.1.0: {} + + mdurl@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@3.0.0: {} + + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mitt@3.0.1: {} + + mkdirp@1.0.4: {} + + mlly@1.7.3: + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.3.0 + ufo: 1.5.4 + + mrmime@2.0.0: {} + + ms@2.1.3: {} + + murmurhash-js@1.0.0: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.8: {} + + nanoid@5.0.9: {} + + natural-compare@1.4.0: {} + + node-addon-api@7.1.1: + optional: true + + node-fetch-native@1.6.4: {} + + node-html-parser@6.1.13: + dependencies: + css-select: 5.1.0 + he: 1.2.0 + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm@10.9.2: {} + + npx@10.2.2: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nypm@0.3.12: + dependencies: + citty: 0.1.6 + consola: 3.3.3 + execa: 8.0.1 + pathe: 1.1.2 + pkg-types: 1.3.0 + ufo: 1.5.4 + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.3: {} + + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + ofetch@1.4.1: + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.4 + ufo: 1.5.4 + + ohash@1.1.4: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@8.1.1: + dependencies: + chalk: 5.4.1 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + orderedmap@2.1.1: {} + + ospath@1.2.2: {} + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + package-json-from-dist@1.0.1: {} + + parchment@1.1.4: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-unit@1.0.1: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.0.2 + minipass: 7.1.2 + + path-type@4.0.0: {} + + pathe@1.1.2: {} + + pathval@2.0.0: {} + + pause-stream@0.0.11: + dependencies: + through: 2.3.8 + + pbf@3.3.0: + dependencies: + ieee754: 1.2.1 + resolve-protobuf-schema: 2.1.0 + + pend@1.2.0: {} + + perfect-debounce@1.0.0: {} + + performance-now@2.1.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + pify@2.3.0: {} + + pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.13(typescript@5.7.3) + vue-demi: 0.14.10(vue@3.5.13(typescript@5.7.3)) + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - '@vue/composition-api' + + pirates@4.0.6: {} + + pkg-types@1.3.0: + dependencies: + confbox: 0.1.8 + mlly: 1.7.3 + pathe: 1.1.2 + + postcss-import@15.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.10 + + postcss-js@4.0.1(postcss@8.4.49): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.49 + + postcss-less@6.0.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + postcss-load-config@4.0.2(postcss@8.4.49): + dependencies: + lilconfig: 3.1.3 + yaml: 2.7.0 + optionalDependencies: + postcss: 8.4.49 + + postcss-nested@6.2.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-selector-parser: 6.1.2 + + postcss-sass@0.5.0: + dependencies: + gonzales-pe: 4.3.0 + postcss: 8.4.49 + + postcss-scss@4.0.9(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-styl@0.12.3: + dependencies: + debug: 4.4.0(supports-color@8.1.1) + fast-diff: 1.3.0 + lodash.sortedlastindex: 4.1.0 + postcss: 8.4.49 + stylus: 0.57.0 + transitivePeerDependencies: + - supports-color + + postcss-value-parser@4.2.0: {} + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + potpack@1.0.2: {} + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.4.2: {} + + pretty-bytes@5.6.0: {} + + prismjs@1.29.0: {} + + process@0.11.10: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + prosemirror-changeset@2.2.1: + dependencies: + prosemirror-transform: 1.10.2 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.3 + + prosemirror-commands@1.6.2: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-dropcursor@1.8.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.37.1 + + prosemirror-gapcursor@1.3.2: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.37.1 + + prosemirror-history@1.4.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.37.1 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.4.0: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-keymap@1.2.2: + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.1: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.24.1 + + prosemirror-menu@1.2.4: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.6.2 + prosemirror-history: 1.4.1 + prosemirror-state: 1.4.3 + + prosemirror-model@1.24.1: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.3: + dependencies: + prosemirror-model: 1.24.1 + + prosemirror-schema-list@1.5.0: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-state@1.4.3: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.37.1 + + prosemirror-tables@1.6.2: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.37.1 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.37.1): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.37.1 + + prosemirror-transform@1.10.2: + dependencies: + prosemirror-model: 1.24.1 + + prosemirror-view@1.37.1: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + protocol-buffers-schema@3.6.0: {} + + proxy-from-env@1.0.0: {} + + proxy-from-env@1.1.0: {} + + ps-tree@1.2.0: + dependencies: + event-stream: 3.3.4 + + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + qs@6.13.1: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + quickselect@2.0.0: {} + + quill-delta@3.6.3: + dependencies: + deep-equal: 1.1.2 + extend: 3.0.2 + fast-diff: 1.1.2 + + quill-delta@4.2.2: + dependencies: + fast-diff: 1.2.0 + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + + quill@1.3.7: + dependencies: + clone: 2.1.2 + deep-equal: 1.1.2 + eventemitter3: 2.0.3 + extend: 3.0.2 + parchment: 1.1.4 + quill-delta: 3.6.3 + + radix-vue@1.9.12(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@floating-ui/dom': 1.6.13 + '@floating-ui/vue': 1.1.6(vue@3.5.13(typescript@5.7.3)) + '@internationalized/date': 3.6.0 + '@internationalized/number': 3.6.0 + '@tanstack/vue-virtual': 3.11.2(vue@3.5.13(typescript@5.7.3)) + '@vueuse/core': 10.11.1(vue@3.5.13(typescript@5.7.3)) + '@vueuse/shared': 10.11.1(vue@3.5.13(typescript@5.7.3)) + aria-hidden: 1.2.4 + defu: 6.1.4 + fast-deep-equal: 3.1.3 + nanoid: 5.0.9 + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - '@vue/composition-api' + + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.3 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.0.2: {} + + recast@0.23.9: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + + regenerator-runtime@0.14.1: {} + + regexp.prototype.flags@1.5.4: + dependencies: + 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 + + request-progress@3.0.0: + dependencies: + throttleit: 1.0.1 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-protobuf-schema@2.1.0: + dependencies: + protocol-buffers-schema: 3.6.0 + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.0.4: {} + + rfdc@1.4.1: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + robust-predicates@3.0.2: {} + + rollup@4.30.1: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.30.1 + '@rollup/rollup-android-arm64': 4.30.1 + '@rollup/rollup-darwin-arm64': 4.30.1 + '@rollup/rollup-darwin-x64': 4.30.1 + '@rollup/rollup-freebsd-arm64': 4.30.1 + '@rollup/rollup-freebsd-x64': 4.30.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.30.1 + '@rollup/rollup-linux-arm-musleabihf': 4.30.1 + '@rollup/rollup-linux-arm64-gnu': 4.30.1 + '@rollup/rollup-linux-arm64-musl': 4.30.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.30.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.30.1 + '@rollup/rollup-linux-riscv64-gnu': 4.30.1 + '@rollup/rollup-linux-s390x-gnu': 4.30.1 + '@rollup/rollup-linux-x64-gnu': 4.30.1 + '@rollup/rollup-linux-x64-musl': 4.30.1 + '@rollup/rollup-win32-arm64-msvc': 4.30.1 + '@rollup/rollup-win32-ia32-msvc': 4.30.1 + '@rollup/rollup-win32-x64-msvc': 4.30.1 + fsevents: 2.3.3 + + rope-sequence@1.3.4: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rw@1.3.3: {} + + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sass@1.83.1: + dependencies: + chokidar: 4.0.3 + immutable: 5.0.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.0 + + sax@1.2.4: {} + + semver@6.3.1: {} + + semver@7.6.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + shadcn-vue@0.11.3(@vitest/ui@2.1.8)(eslint@8.57.1)(vitest@2.1.8)(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@unovue/detypes': 0.8.4 + '@vitest/ui': 2.1.8(vitest@2.1.8) + '@vue/compiler-sfc': 3.5.13 + c12: 2.0.1 + commander: 12.1.0 + consola: 3.3.3 + diff: 7.0.0 + fs-extra: 11.2.0 + https-proxy-agent: 7.0.6 + lodash-es: 4.17.21 + magic-string: 0.30.17 + nypm: 0.3.12 + ofetch: 1.4.1 + ora: 8.1.1 + pathe: 1.1.2 + pkg-types: 1.3.0 + prompts: 2.4.2 + radix-vue: 1.9.12(vue@3.5.13(typescript@5.7.3)) + semver: 7.6.3 + tsconfig-paths: 4.2.0 + vitest: 2.1.8(@types/node@22.10.5)(@vitest/ui@2.1.8)(sass@1.83.1)(stylus@0.57.0) + vue-metamorph: 3.2.0(eslint@8.57.1) + zod: 3.24.1 + transitivePeerDependencies: + - '@vue/composition-api' + - eslint + - magicast + - supports-color + - vue + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.3 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.3 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + 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 + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + + sisteransi@1.0.5: {} + + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + sortablejs@1.14.0: {} + + source-map-js@1.2.1: {} + + source-map-resolve@0.6.0: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + speakingurl@14.0.1: {} + + split@0.3.3: + dependencies: + through: 2.3.8 + + sshpk@1.18.0: + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + + stackback@0.0.2: {} + + start-server-and-test@2.0.9: + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.4.0(supports-color@8.1.1) + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 8.0.1(debug@4.4.0) + transitivePeerDependencies: + - supports-color + + std-env@3.8.0: {} + + stdin-discarder@0.2.2: {} + + stream-combiner@0.0.4: + dependencies: + duplexer: 0.1.2 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + striptags@3.2.0: {} + + stylis@4.2.0: {} + + stylus@0.57.0: + dependencies: + css: 3.0.0 + debug: 4.4.0(supports-color@8.1.1) + glob: 7.2.3 + safer-buffer: 2.1.2 + sax: 1.2.4 + source-map: 0.7.4 + transitivePeerDependencies: + - supports-color + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + supercluster@7.1.5: + dependencies: + kdbush: 3.0.0 + + superjson@2.2.2: + dependencies: + copy-anything: 3.0.5 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.9.2: + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.8.1 + + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tailwind-merge@2.6.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.17): + dependencies: + tailwindcss: 3.4.17 + + tailwindcss@3.4.17: + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.4.49 + postcss-import: 15.1.0(postcss@8.4.49) + postcss-js: 4.0.1(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49) + postcss-nested: 6.2.0(postcss@8.4.49) + postcss-selector-parser: 6.1.2 + resolve: 1.22.10 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + text-table@0.2.0: {} + + textarea@0.3.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + three@0.135.0: {} + + throttle-debounce@5.0.2: {} + + throttleit@1.0.1: {} + + through@2.3.8: {} + + tiny-invariant@1.3.3: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.10: + dependencies: + fdir: 6.4.2(picomatch@4.0.2) + picomatch: 4.0.2 + + tinypool@1.0.2: {} + + tinyqueue@2.0.3: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.8 + + tldts-core@6.1.71: {} + + tldts@6.1.71: + dependencies: + tldts-core: 6.1.71 + + tmp@0.2.3: {} + + to-px@1.1.0: + dependencies: + parse-unit: 1.0.1 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + topojson-client@3.1.0: + dependencies: + commander: 2.20.3 + + totalist@3.0.1: {} + + tough-cookie@5.1.0: + dependencies: + tldts: 6.1.71 + + tree-kill@1.2.2: {} + + ts-interface-checker@0.1.13: {} + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + tweetnacl@0.14.5: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + type-fest@0.21.3: {} + + type-fest@4.32.0: {} + + typescript@5.7.3: {} + + uc.micro@2.1.0: {} + + ufo@1.5.4: {} + + undici-types@6.20.0: + optional: true + + universalify@2.0.1: {} + + untildify@4.0.0: {} + + update-browserslist-db@1.1.2(browserslist@4.24.4): + dependencies: + browserslist: 4.24.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + uuid@8.3.2: {} + + vee-validate@4.15.0(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@vue/devtools-api': 7.7.0 + type-fest: 4.32.0 + vue: 3.5.13(typescript@5.7.3) + + verror@1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + + vite-node@2.1.8(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0): + dependencies: + cac: 6.7.14 + debug: 4.4.0(supports-color@8.1.1) + es-module-lexer: 1.6.0 + pathe: 1.1.2 + vite: 5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.30.1 + optionalDependencies: + '@types/node': 22.10.5 + fsevents: 2.3.3 + sass: 1.83.1 + stylus: 0.57.0 + + vitest@2.1.8(@types/node@22.10.5)(@vitest/ui@2.1.8)(sass@1.83.1)(stylus@0.57.0): + dependencies: + '@vitest/expect': 2.1.8 + '@vitest/mocker': 2.1.8(vite@5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0)) + '@vitest/pretty-format': 2.1.8 + '@vitest/runner': 2.1.8 + '@vitest/snapshot': 2.1.8 + '@vitest/spy': 2.1.8 + '@vitest/utils': 2.1.8 + chai: 5.1.2 + debug: 4.4.0(supports-color@8.1.1) + expect-type: 1.1.0 + magic-string: 0.30.17 + pathe: 1.1.2 + std-env: 3.8.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.11(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + vite-node: 2.1.8(@types/node@22.10.5)(sass@1.83.1)(stylus@0.57.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.10.5 + '@vitest/ui': 2.1.8(vitest@2.1.8) + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vt-pbf@3.1.3: + dependencies: + '@mapbox/point-geometry': 0.1.0 + '@mapbox/vector-tile': 1.3.1 + pbf: 3.3.0 + + vue-demi@0.14.10(vue@3.5.13(typescript@5.7.3)): + dependencies: + vue: 3.5.13(typescript@5.7.3) + + vue-eslint-parser@9.4.3(eslint@8.57.1): + dependencies: + debug: 4.4.0(supports-color@8.1.1) + eslint: 8.57.1 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + lodash: 4.17.21 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + vue-i18n@9.14.2(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@intlify/core-base': 9.14.2 + '@intlify/shared': 9.14.2 + '@vue/devtools-api': 6.6.4 + vue: 3.5.13(typescript@5.7.3) + + vue-letter@0.2.0: + dependencies: + lettersanitizer: 1.0.6 + + vue-metamorph@3.2.0(eslint@8.57.1): + dependencies: + '@babel/parser': 8.0.0-alpha.12 + ast-types: 0.14.2 + chalk: 5.4.1 + cli-progress: 3.12.0 + commander: 12.1.0 + deep-diff: 1.0.2 + fs-extra: 11.2.0 + glob: 11.0.1 + lodash-es: 4.17.21 + magic-string: 0.30.17 + micromatch: 4.0.8 + node-html-parser: 6.1.13 + postcss: 8.4.49 + postcss-less: 6.0.0(postcss@8.4.49) + postcss-sass: 0.5.0 + postcss-scss: 4.0.9(postcss@8.4.49) + postcss-styl: 0.12.3 + recast: 0.23.9 + table: 6.9.0 + vue-eslint-parser: 9.4.3(eslint@8.57.1) + transitivePeerDependencies: + - eslint + - supports-color + + vue-picture-cropper@0.7.0(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@bassist/utils': 0.4.0 + cropperjs: 1.6.2 + vue: 3.5.13(typescript@5.7.3) + + vue-router@4.5.0(vue@3.5.13(typescript@5.7.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.13(typescript@5.7.3) + + vue-sonner@1.3.0: {} + + vue3-emoji-picker@1.1.8(typescript@5.7.3): + dependencies: + '@popperjs/core': 2.11.8 + idb: 7.1.1 + vue: 3.5.13(typescript@5.7.3) + transitivePeerDependencies: + - typescript + + vue@3.5.13(typescript@5.7.3): + dependencies: + '@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@3.5.13(typescript@5.7.3)) + '@vue/shared': 3.5.13 + optionalDependencies: + typescript: 5.7.3 + + vuedraggable@4.1.0(vue@3.5.13(typescript@5.7.3)): + dependencies: + sortablejs: 1.14.0 + vue: 3.5.13(typescript@5.7.3) + + w3c-keyname@2.2.8: {} + + wait-on@8.0.1(debug@4.4.0): + dependencies: + axios: 1.7.9(debug@4.4.0) + joi: 17.13.3 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.1 + transitivePeerDependencies: + - debug + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + xml-name-validator@4.0.0: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@1.10.2: {} + + yaml@2.7.0: {} + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yocto-queue@0.1.0: {} + + zod@3.24.1: {} diff --git a/frontend/src/App.vue b/frontend/src/App.vue index dc41fa28..314ef677 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,98 +1,190 @@ diff --git a/frontend/src/Root.vue b/frontend/src/Root.vue index 1dc7b15f..3f7341b2 100644 --- a/frontend/src/Root.vue +++ b/frontend/src/Root.vue @@ -1,14 +1,14 @@ \ No newline at end of file + diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 4c3798fd..c1bb2ea0 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -33,177 +33,236 @@ http.interceptors.request.use((request) => { return request }) -const resetPassword = (data) => http.post('/api/users/reset-password', data) -const setPassword = (data) => http.post('/api/users/set-password', data) -const deleteUser = (id) => http.delete(`/api/users/${id}`) -const getEmailNotificationSettings = () => http.get('/api/settings/notifications/email') -const updateEmailNotificationSettings = (data) => http.put('/api/settings/notifications/email', data) -const getPriorities = () => http.get('/api/priorities') -const getStatuses = () => http.get('/api/statuses') -const createStatus = (data) => http.post('/api/statuses', data) -const updateStatus = (id, data) => http.put(`/api/statuses/${id}`, data) -const deleteStatus = (id) => http.delete(`/api/statuses/${id}`) -const createTag = (data) => http.post('/api/tags', data) -const updateTag = (id, data) => http.put(`/api/tags/${id}`, data) -const deleteTag = (id) => http.delete(`/api/tags/${id}`) -const getTemplate = (id) => http.get(`/api/templates/${id}`) -const getTemplates = () => http.get('/api/templates') +const searchConversations = (params) => http.get('/api/v1/conversations/search', { params }) +const searchMessages = (params) => http.get('/api/v1/messages/search', { params }) +const resetPassword = (data) => http.post('/api/v1/users/reset-password', data) +const setPassword = (data) => http.post('/api/v1/users/set-password', data) +const deleteUser = (id) => http.delete(`/api/v1/users/${id}`) +const getEmailNotificationSettings = () => http.get('/api/v1/settings/notifications/email') +const updateEmailNotificationSettings = (data) => http.put('/api/v1/settings/notifications/email', data) +const getPriorities = () => http.get('/api/v1/priorities') +const getStatuses = () => http.get('/api/v1/statuses') +const createStatus = (data) => http.post('/api/v1/statuses', data) +const updateStatus = (id, data) => http.put(`/api/v1/statuses/${id}`, data) +const deleteStatus = (id) => http.delete(`/api/v1/statuses/${id}`) +const createTag = (data) => http.post('/api/v1/tags', data) +const updateTag = (id, data) => http.put(`/api/v1/tags/${id}`, data) +const deleteTag = (id) => http.delete(`/api/v1/tags/${id}`) +const getTemplate = (id) => http.get(`/api/v1/templates/${id}`) +const getTemplates = (type) => http.get('/api/v1/templates', { params: { type: type } }) const createTemplate = (data) => - http.post('/api/templates', data, { + http.post('/api/v1/templates', data, { headers: { 'Content-Type': 'application/json' } }) -const deleteTemplate = (id) => http.delete(`/api/templates/${id}`) +const deleteTemplate = (id) => http.delete(`/api/v1/templates/${id}`) const updateTemplate = (id, data) => - http.put(`/api/templates/${id}`, data, { + http.put(`/api/v1/templates/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) + +const getAllBusinessHours = () => http.get('/api/v1/business-hours') +const getBusinessHours = (id) => http.get(`/api/v1/business-hours/${id}`) +const createBusinessHours = (data) => http.post('/api/v1/business-hours', data, { + headers: { + 'Content-Type': 'application/json' + } +}) +const updateBusinessHours = (id, data) => + http.put(`/api/v1/business-hours/${id}`, data, { + headers: { + 'Content-Type': 'application/json' + } + }) +const deleteBusinessHours = (id) => http.delete(`/api/v1/business-hours/${id}`) + +const getAllSLAs = () => http.get('/api/v1/sla') +const getSLA = (id) => http.get(`/api/v1/sla/${id}`) +const createSLA = (data) => http.post('/api/v1/sla', data) +const updateSLA = (id, data) => http.put(`/api/v1/sla/${id}`, data) +const deleteSLA = (id) => http.delete(`/api/v1/sla/${id}`) const createOIDC = (data) => - http.post('/api/oidc', data, { + http.post('/api/v1/oidc', data, { headers: { 'Content-Type': 'application/json' } }) -const getAllOIDC = () => http.get('/api/oidc') -const getOIDC = (id) => http.get(`/api/oidc/${id}`) +const getAllEnabledOIDC = () => http.get('/api/v1/oidc/enabled') +const getAllOIDC = () => http.get('/api/v1/oidc') +const getOIDC = (id) => http.get(`/api/v1/oidc/${id}`) const updateOIDC = (id, data) => - http.put(`/api/oidc/${id}`, data, { + http.put(`/api/v1/oidc/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) -const deleteOIDC = (id) => http.delete(`/api/oidc/${id}`) +const deleteOIDC = (id) => http.delete(`/api/v1/oidc/${id}`) const updateSettings = (key, data) => - http.put(`/api/settings/${key}`, data, { + http.put(`/api/v1/settings/${key}`, data, { headers: { 'Content-Type': 'application/json' } }) -const getSettings = (key) => http.get(`/api/settings/${key}`) -const login = (data) => http.post(`/api/login`, data) +const getSettings = (key) => http.get(`/api/v1/settings/${key}`) +const login = (data) => http.post(`/api/v1/login`, data) const getAutomationRules = (type) => - http.get(`/api/automation/rules`, { + http.get(`/api/v1/automation/rules`, { params: { type: type } }) -const toggleAutomationRule = (id) => http.put(`/api/automation/rules/${id}/toggle`) -const getAutomationRule = (id) => http.get(`/api/automation/rules/${id}`) +const toggleAutomationRule = (id) => http.put(`/api/v1/automation/rules/${id}/toggle`) +const getAutomationRule = (id) => http.get(`/api/v1/automation/rules/${id}`) const updateAutomationRule = (id, data) => - http.put(`/api/automation/rules/${id}`, data, { + http.put(`/api/v1/automation/rules/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) const createAutomationRule = (data) => - http.post(`/api/automation/rules`, data, { + http.post(`/api/v1/automation/rules`, data, { headers: { 'Content-Type': 'application/json' } }) -const getRoles = () => http.get('/api/roles') -const getRole = (id) => http.get(`/api/roles/${id}`) +const deleteAutomationRule = (id) => http.delete(`/api/v1/automation/rules/${id}`) +const updateAutomationRuleWeights = (data) => + http.put(`/api/v1/automation/rules/weights`, data, { + headers: { + 'Content-Type': 'application/json' + } + }) +const updateAutomationRulesExecutionMode = (data) => http.put(`/api/v1/automation/rules/execution-mode`, data) +const getRoles = () => http.get('/api/v1/roles') +const getRole = (id) => http.get(`/api/v1/roles/${id}`) const createRole = (data) => - http.post('/api/roles', data, { + http.post('/api/v1/roles', data, { headers: { 'Content-Type': 'application/json' } }) const updateRole = (id, data) => - http.put(`/api/roles/${id}`, data, { + http.put(`/api/v1/roles/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) -const deleteRole = (id) => http.delete(`/api/roles/${id}`) -const deleteAutomationRule = (id) => http.delete(`/api/automation/rules/${id}`) -const getUser = (id) => http.get(`/api/users/${id}`) -const getTeam = (id) => http.get(`/api/teams/${id}`) -const getTeams = () => http.get('/api/teams') -const getTeamsCompact = () => http.get('/api/teams/compact') -const getUsers = () => http.get('/api/users') -const getUsersCompact = () => http.get('/api/users/compact') +const deleteRole = (id) => http.delete(`/api/v1/roles/${id}`) +const getUser = (id) => http.get(`/api/v1/users/${id}`) +const getTeam = (id) => http.get(`/api/v1/teams/${id}`) +const getTeams = () => http.get('/api/v1/teams') +const updateTeam = (id, data) => http.put(`/api/v1/teams/${id}`, data) +const createTeam = (data) => http.post('/api/v1/teams', data) +const getTeamsCompact = () => http.get('/api/v1/teams/compact') +const deleteTeam = (id) => http.delete(`/api/v1/teams/${id}`) + +const getUsers = () => http.get('/api/v1/users') +const getUsersCompact = () => http.get('/api/v1/users/compact') const updateCurrentUser = (data) => - http.put('/api/users/me', data, { + http.put('/api/v1/users/me', data, { headers: { 'Content-Type': 'multipart/form-data' } }) -const deleteUserAvatar = () => http.delete('/api/users/me/avatar') -const getCurrentUser = () => http.get('/api/users/me') -const getTags = () => http.get('/api/tags') -const upsertTags = (uuid, data) => http.post(`/api/conversations/${uuid}/tags`, data) -const updateAssignee = (uuid, assignee_type, data) => - http.put(`/api/conversations/${uuid}/assignee/${assignee_type}`, data) -const updateConversationStatus = (uuid, data) => http.put(`/api/conversations/${uuid}/status`, data) -const updateConversationPriority = (uuid, data) => http.put(`/api/conversations/${uuid}/priority`, data) -const updateAssigneeLastSeen = (uuid) => http.put(`/api/conversations/${uuid}/last-seen`) -const getConversationMessage = (cuuid, uuid) => http.get(`/api/conversations/${cuuid}/messages/${uuid}`) -const retryMessage = (cuuid, uuid) => http.put(`/api/conversations/${cuuid}/messages/${uuid}/retry`) -const getConversationMessages = (uuid, page) => - http.get(`/api/conversations/${uuid}/messages`, { - params: { page: page } - }) +const deleteUserAvatar = () => http.delete('/api/v1/users/me/avatar') +const getCurrentUser = () => http.get('/api/v1/users/me') +const getCurrentUserTeams = () => http.get('/api/v1/users/me/teams') +const getTags = () => http.get('/api/v1/tags') +const upsertTags = (uuid, data) => http.post(`/api/v1/conversations/${uuid}/tags`, data) +const updateAssignee = (uuid, assignee_type, data) => http.put(`/api/v1/conversations/${uuid}/assignee/${assignee_type}`, data) +const removeAssignee = (uuid, assignee_type) => http.put(`/api/v1/conversations/${uuid}/assignee/${assignee_type}/remove`) +const updateConversationStatus = (uuid, data) => http.put(`/api/v1/conversations/${uuid}/status`, data) +const updateConversationPriority = (uuid, data) => http.put(`/api/v1/conversations/${uuid}/priority`, data) +const updateAssigneeLastSeen = (uuid) => http.put(`/api/v1/conversations/${uuid}/last-seen`) +const getConversationMessage = (cuuid, uuid) => http.get(`/api/v1/conversations/${cuuid}/messages/${uuid}`) +const retryMessage = (cuuid, uuid) => http.put(`/api/v1/conversations/${cuuid}/messages/${uuid}/retry`) +const getConversationMessages = (uuid, params) => http.get(`/api/v1/conversations/${uuid}/messages`, { params }) const sendMessage = (uuid, data) => - http.post(`/api/conversations/${uuid}/messages`, data, { + http.post(`/api/v1/conversations/${uuid}/messages`, data, { headers: { 'Content-Type': 'application/json' } }) -const getConversation = (uuid) => http.get(`/api/conversations/${uuid}`) -const getConversationParticipants = (uuid) => http.get(`/api/conversations/${uuid}/participants`) -const getCannedResponses = () => http.get('/api/canned-responses') -const createCannedResponse = (data) => http.post('/api/canned-responses', data) -const updateCannedResponse = (id, data) => http.put(`/api/canned-responses/${id}`, data) -const deleteCannedResponse = (id) => http.delete(`/api/canned-responses/${id}`) -const getAssignedConversations = (params) => - http.get('/api/conversations/assigned', { params }) -const getUnassignedConversations = (params) => - http.get('/api/conversations/unassigned', { params }) -const getAllConversations = (params) => - http.get('/api/conversations/all', { params }) +const getConversation = (uuid) => http.get(`/api/v1/conversations/${uuid}`) +const getConversationParticipants = (uuid) => http.get(`/api/v1/conversations/${uuid}/participants`) +const getAllMacros = () => http.get('/api/v1/macros') +const getMacro = (id) => http.get(`/api/v1/macros/${id}`) +const createMacro = (data) => http.post('/api/v1/macros', data, { + headers: { + 'Content-Type': 'application/json' + } +}) +const updateMacro = (id, data) => http.put(`/api/v1/macros/${id}`, data, { + headers: { + 'Content-Type': 'application/json' + } +}) +const deleteMacro = (id) => http.delete(`/api/v1/macros/${id}`) +const applyMacro = (uuid, id, data) => http.post(`/api/v1/conversations/${uuid}/macros/${id}/apply`, data, { + headers: { + 'Content-Type': 'application/json' + } +}) +const getTeamUnassignedConversations = (teamID, params) => + http.get(`/api/v1/teams/${teamID}/conversations/unassigned`, { params }) +const getAssignedConversations = (params) => http.get('/api/v1/conversations/assigned', { params }) +const getUnassignedConversations = (params) => http.get('/api/v1/conversations/unassigned', { params }) +const getAllConversations = (params) => http.get('/api/v1/conversations/all', { params }) +const getViewConversations = (id, params) => http.get(`/api/v1/views/${id}/conversations`, { params }) const uploadMedia = (data) => - http.post('/api/media', data, { + http.post('/api/v1/media', data, { headers: { 'Content-Type': 'multipart/form-data' } }) -const getGlobalDashboardCounts = () => http.get('/api/dashboard/global/counts') -const getGlobalDashboardCharts = () => http.get('/api/dashboard/global/charts') -const getUserDashboardCounts = () => http.get(`/api/dashboard/me/counts`) -const getUserDashboardCharts = () => http.get(`/api/dashboard/me/charts`) -const getLanguage = (lang) => http.get(`/api/lang/${lang}`) +const getOverviewCounts = () => http.get('/api/v1/reports/overview/counts') +const getOverviewCharts = () => http.get('/api/v1/reports/overview/charts') +const getLanguage = (lang) => http.get(`/api/v1/lang/${lang}`) const createUser = (data) => - http.post('/api/users', data, { + http.post('/api/v1/users', data, { headers: { 'Content-Type': 'application/json' } }) const updateUser = (id, data) => - http.put(`/api/users/${id}`, data, { + http.put(`/api/v1/users/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) -const updateTeam = (id, data) => http.put(`/api/teams/${id}`, data) -const createTeam = (data) => http.post('/api/teams', data) const createInbox = (data) => - http.post('/api/inboxes', data, { + http.post('/api/v1/inboxes', data, { headers: { 'Content-Type': 'application/json' } }) -const getInboxes = () => http.get('/api/inboxes') -const getInbox = (id) => http.get(`/api/inboxes/${id}`) -const toggleInbox = (id) => http.put(`/api/inboxes/${id}/toggle`) +const getInboxes = () => http.get('/api/v1/inboxes') +const getInbox = (id) => http.get(`/api/v1/inboxes/${id}`) +const toggleInbox = (id) => http.put(`/api/v1/inboxes/${id}/toggle`) const updateInbox = (id, data) => - http.put(`/api/inboxes/${id}`, data, { + http.put(`/api/v1/inboxes/${id}`, data, { headers: { 'Content-Type': 'application/json' } }) -const deleteInbox = (id) => http.delete(`/api/inboxes/${id}`) +const deleteInbox = (id) => http.delete(`/api/v1/inboxes/${id}`) +const getCurrentUserViews = () => http.get('/api/v1/views/me') +const createView = (data) => + http.post('/api/v1/views/me', data, { + headers: { + 'Content-Type': 'application/json' + } + }) +const updateView = (id, data) => + http.put(`/api/v1/views/me/${id}`, data, { + headers: { + 'Content-Type': 'application/json' + } + }) +const deleteView = (id) => http.delete(`/api/v1/views/me/${id}`) +const getAiPrompts = () => http.get('/api/v1/ai/prompts') +const aiCompletion = (data) => http.post('/api/v1/ai/completion', data) export default { login, @@ -219,6 +278,7 @@ export default { deleteRole, updateRole, getTeams, + deleteTeam, getUsers, getInbox, getInboxes, @@ -226,30 +286,45 @@ export default { getConversation, getAutomationRule, getAutomationRules, + getAllBusinessHours, + getBusinessHours, + createBusinessHours, + updateBusinessHours, + deleteBusinessHours, + getAllSLAs, + getSLA, + createSLA, + updateSLA, + deleteSLA, getAssignedConversations, getUnassignedConversations, getAllConversations, - getGlobalDashboardCharts, - getGlobalDashboardCounts, - getUserDashboardCounts, - getUserDashboardCharts, + getTeamUnassignedConversations, + getViewConversations, + getOverviewCharts, + getOverviewCounts, getConversationParticipants, getConversationMessage, getConversationMessages, getCurrentUser, - getCannedResponses, - createCannedResponse, - updateCannedResponse, - deleteCannedResponse, + getCurrentUserTeams, + getAllMacros, + getMacro, + createMacro, + updateMacro, + deleteMacro, + applyMacro, updateCurrentUser, updateAssignee, updateConversationStatus, updateConversationPriority, upsertTags, uploadMedia, - updateAutomationRule, updateAssigneeLastSeen, updateUser, + updateAutomationRule, + updateAutomationRuleWeights, + updateAutomationRulesExecutionMode, createAutomationRule, toggleAutomationRule, deleteAutomationRule, @@ -266,6 +341,7 @@ export default { updateSettings, createOIDC, getAllOIDC, + getAllEnabledOIDC, getOIDC, updateOIDC, deleteOIDC, @@ -287,4 +363,13 @@ export default { getUsersCompact, getEmailNotificationSettings, updateEmailNotificationSettings, + getCurrentUserViews, + createView, + updateView, + deleteView, + getAiPrompts, + aiCompletion, + searchConversations, + searchMessages, + removeAssignee, } diff --git a/frontend/src/assets/styles/main.scss b/frontend/src/assets/styles/main.scss index e821e6ef..6f4fe4be 100644 --- a/frontend/src/assets/styles/main.scss +++ b/frontend/src/assets/styles/main.scss @@ -2,89 +2,96 @@ @tailwind components; @tailwind utilities; -// App default font-size. -// Default: 16px, 15px looks wide. :root { - font-size: 14px; -} - -body { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - overflow-x: hidden; - overflow-y: hidden; + font-size: 16px; } .page-content { - padding: 1rem 1rem; - height: 100%; + height: 100vh; + overflow-y: scroll; + padding-bottom: 100px; + background-color: #fff; +} + +@layer base { + html, + body { + font-family: 'Plus Jakarta Sans', sans-serif; + min-height: 100%; + overflow: hidden; + margin: 0; + + @media (max-width: 768px) { + overflow-x: auto; + } + } } // Theme. - @layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; - + --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; - + --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; - + --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; - + --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; - + --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; - + --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; - + --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; - - --border: 240 5.9% 90%; - --input: 240 5.9% 90%; - --ring: 240 5.9% 10%; + + --border:240 5.9% 90%; + --input:240 5.9% 90%; + --ring:240 5.9% 10%; --radius: 0.75rem; } - + .dark { - --background: 240 10% 3.9%; - --foreground: 0 0% 98%; - - --card: 240 10% 3.9%; - --card-foreground: 0 0% 98%; - - --popover: 240 10% 3.9%; - --popover-foreground: 0 0% 98%; - - --primary: 0 0% 98%; - --primary-foreground: 240 5.9% 10%; - - --secondary: 240 3.7% 15.9%; - --secondary-foreground: 0 0% 98%; - - --muted: 240 3.7% 15.9%; - --muted-foreground: 240 5% 64.9%; - - --accent: 240 3.7% 15.9%; - --accent-foreground: 0 0% 98%; - - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; - - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 240 4.9% 83.9%; + --background:240 10% 3.9%; + --foreground:0 0% 98%; + + --card:240 10% 3.9%; + --card-foreground:0 0% 98%; + + --popover:240 10% 3.9%; + --popover-foreground:0 0% 98%; + + --primary:0 0% 98%; + --primary-foreground:240 5.9% 10%; + + --secondary:240 3.7% 15.9%; + --secondary-foreground:0 0% 98%; + + --muted:240 3.7% 15.9%; + --muted-foreground:240 5% 64.9%; + + --accent:240 3.7% 15.9%; + --accent-foreground:0 0% 98%; + + --destructive:0 62.8% 30.6%; + --destructive-foreground:0 0% 98%; + + --border:240 3.7% 15.9%; + --input:240 3.7% 15.9%; + --ring:240 4.9% 83.9%; } } + @layer base { :root { --vis-tooltip-background-color: none !important; @@ -148,11 +155,12 @@ body { pb-3 min-w-[30%] max-w-[70%] border + overflow-x-auto rounded-xl; - box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.1); - // To make email tables fit. + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); table { width: 100% !important; + table-layout: fixed !important; } } @@ -165,46 +173,42 @@ body { } .box { - @apply border shadow; -} - -.dashboard-card { - @apply rounded-lg box w-full; -} - -.admin-main-content { - @apply p-0; + @apply border shadow rounded-lg; } +// Scrollbar start ::-webkit-scrollbar { - width: 10px; -} - -::-webkit-scrollbar-track { - background: #f1f1f1; + width: 8px; /* Adjust width */ + height: 8px; /* Adjust height */ } ::-webkit-scrollbar-thumb { background-color: #888; - border-radius: 4px; + border-radius: 3px; border: 2px solid transparent; + background-clip: content-box; } ::-webkit-scrollbar-thumb:hover { - background-color: #555; + background-color: #555; /* Hover effect */ } -* { - scrollbar-width: thin; +::-webkit-scrollbar-track { + background: #f0f0f0; + border-radius: 3px; } +// End Scrollbar .code-editor { @apply rounded-md border shadow h-[65vh] min-h-[250px] w-full relative; } +.ql-container { + margin: 0 !important; +} + .ql-container .ql-editor { - margin-top: 0 !important; - height: 200px !important; + height: 300px !important; border-radius: var(--radius) !important; @apply rounded-lg rounded-t-none; } @@ -212,3 +216,107 @@ body { .ql-toolbar { @apply rounded-t-lg; } + +.blinking-dot { + display: inline-block; + width: 8px; + height: 8px; + background-color: red; + border-radius: 50%; + animation: blink 2s infinite; +} + +@keyframes blink { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0; + } +} + +// Sidebar start +@layer base { + :root { + --sidebar-background: 0 0% 97%; + --sidebar-foreground: 240 5.3% 26.1%; + --sidebar-primary: 240 5.9% 10%; + --sidebar-primary-foreground: 0 0% 98%; + --sidebar-accent: 240 4.8% 95.9%; + --sidebar-accent-foreground: 240 5.9% 10%; + --sidebar-border: 220 13% 91%; + --sidebar-ring: 217.2 91.2% 59.8%; + } + + .dark { + --sidebar-background: 240 5.9% 10%; + --sidebar-foreground: 240 4.8% 95.9%; + --sidebar-primary: 224.3 76.3% 48%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 240 3.7% 15.9%; + --sidebar-accent-foreground: 240 4.8% 95.9%; + --sidebar-border: 240 3.7% 15.9%; + --sidebar-ring: 217.2 91.2% 59.8%; + } +} +a[data-active='true'] { + background-color: hsl(var(--sidebar-background)) !important; + color: hsl(var(--sidebar-accent-foreground)) !important; + font-weight: 500; + transition: + background-color 0.2s, + color 0.2s; +} +a[data-active='false']:hover { + background-color: hsl(var(--sidebar-accent)) !important; + color: hsl(var(--sidebar-accent-foreground)) !important; + font-weight: 500; + transition: + background-color 0.2s, + color 0.2s; +} +// Sidebar end + +.show-quoted-text { + blockquote { + @apply block; + } +} + +.hide-quoted-text { + blockquote { + @apply hidden; + } +} + +.dot-loader { + display: inline-flex; + align-items: center; +} + +.dot { + width: 4px; + height: 4px; + border-radius: 50%; + background-color: currentColor; + margin: 0 2px; + animation: dot-flashing 1s infinite linear alternate; +} + +.dot:nth-child(2) { + animation-delay: 0.2s; +} + +.dot:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes dot-flashing { + 0% { + opacity: 0.2; + } + 100% { + opacity: 1; + } +} diff --git a/frontend/src/components/NavBar.vue b/frontend/src/components/NavBar.vue deleted file mode 100644 index ee37c161..00000000 --- a/frontend/src/components/NavBar.vue +++ /dev/null @@ -1,109 +0,0 @@ - - - diff --git a/frontend/src/components/account/AccountPage.vue b/frontend/src/components/account/AccountPage.vue deleted file mode 100644 index 8dd487a8..00000000 --- a/frontend/src/components/account/AccountPage.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/frontend/src/components/admin/AdminPage.vue b/frontend/src/components/admin/AdminPage.vue deleted file mode 100644 index 2b0213ed..00000000 --- a/frontend/src/components/admin/AdminPage.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/frontend/src/components/admin/DataTable.vue b/frontend/src/components/admin/DataTable.vue deleted file mode 100644 index 539d69f1..00000000 --- a/frontend/src/components/admin/DataTable.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - diff --git a/frontend/src/components/admin/automation/ActionBox.vue b/frontend/src/components/admin/automation/ActionBox.vue deleted file mode 100644 index 66ced321..00000000 --- a/frontend/src/components/admin/automation/ActionBox.vue +++ /dev/null @@ -1,189 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/automation/Automation.vue b/frontend/src/components/admin/automation/Automation.vue deleted file mode 100644 index ad6588c9..00000000 --- a/frontend/src/components/admin/automation/Automation.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/automation/CreateOrEditRule.vue b/frontend/src/components/admin/automation/CreateOrEditRule.vue deleted file mode 100644 index 10a22ecf..00000000 --- a/frontend/src/components/admin/automation/CreateOrEditRule.vue +++ /dev/null @@ -1,344 +0,0 @@ - - - diff --git a/frontend/src/components/admin/automation/RuleBox.vue b/frontend/src/components/admin/automation/RuleBox.vue deleted file mode 100644 index 1d67405e..00000000 --- a/frontend/src/components/admin/automation/RuleBox.vue +++ /dev/null @@ -1,287 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/automation/RuleTab.vue b/frontend/src/components/admin/automation/RuleTab.vue deleted file mode 100644 index b5cd1c25..00000000 --- a/frontend/src/components/admin/automation/RuleTab.vue +++ /dev/null @@ -1,58 +0,0 @@ - - - diff --git a/frontend/src/components/admin/automation/formSchema.js b/frontend/src/components/admin/automation/formSchema.js deleted file mode 100644 index 6414ccea..00000000 --- a/frontend/src/components/admin/automation/formSchema.js +++ /dev/null @@ -1,14 +0,0 @@ -import * as z from 'zod' - -export const formSchema = z.object({ - name: z.string({ - required_error: 'Rule name is required.' - }), - description: z.string({ - required_error: 'Rule description is required.' - }), - type: z.string({ - required_error: 'Rule type is required.' - }), - events: z.array(z.string()).min(1, 'Please select at least one event.'), -}) diff --git a/frontend/src/components/admin/common/MenuCard.vue b/frontend/src/components/admin/common/MenuCard.vue deleted file mode 100644 index 86c5d2b0..00000000 --- a/frontend/src/components/admin/common/MenuCard.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - diff --git a/frontend/src/components/admin/common/PageHeader.vue b/frontend/src/components/admin/common/PageHeader.vue deleted file mode 100644 index 125fa16a..00000000 --- a/frontend/src/components/admin/common/PageHeader.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/frontend/src/components/admin/conversation/Conversation.vue b/frontend/src/components/admin/conversation/Conversation.vue deleted file mode 100644 index 48bfdb8b..00000000 --- a/frontend/src/components/admin/conversation/Conversation.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - diff --git a/frontend/src/components/admin/conversation/canned_responses/CannedResponses.vue b/frontend/src/components/admin/conversation/canned_responses/CannedResponses.vue deleted file mode 100644 index 31c1942c..00000000 --- a/frontend/src/components/admin/conversation/canned_responses/CannedResponses.vue +++ /dev/null @@ -1,105 +0,0 @@ - - - diff --git a/frontend/src/components/admin/conversation/canned_responses/CannedResponsesForm.vue b/frontend/src/components/admin/conversation/canned_responses/CannedResponsesForm.vue deleted file mode 100644 index eef7d762..00000000 --- a/frontend/src/components/admin/conversation/canned_responses/CannedResponsesForm.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/conversation/canned_responses/dataTableDropdown.vue b/frontend/src/components/admin/conversation/canned_responses/dataTableDropdown.vue deleted file mode 100644 index dc1fff83..00000000 --- a/frontend/src/components/admin/conversation/canned_responses/dataTableDropdown.vue +++ /dev/null @@ -1,101 +0,0 @@ - - - diff --git a/frontend/src/components/admin/conversation/canned_responses/formSchema.js b/frontend/src/components/admin/conversation/canned_responses/formSchema.js deleted file mode 100644 index 79167a21..00000000 --- a/frontend/src/components/admin/conversation/canned_responses/formSchema.js +++ /dev/null @@ -1,18 +0,0 @@ -import * as z from 'zod' - -export const formSchema = z.object({ - title: z - .string({ - required_error: 'Title is required.' - }) - .min(1, { - message: 'Title must be at least 1 character.' - }), - content: z - .string({ - required_error: 'Content is required.' - }) - .min(1, { - message: 'Content must be atleast 3 characters.' - }) -}) diff --git a/frontend/src/components/admin/conversation/status/Status.vue b/frontend/src/components/admin/conversation/status/Status.vue deleted file mode 100644 index 25dd7183..00000000 --- a/frontend/src/components/admin/conversation/status/Status.vue +++ /dev/null @@ -1,95 +0,0 @@ - - - diff --git a/frontend/src/components/admin/conversation/tags/Tags.vue b/frontend/src/components/admin/conversation/tags/Tags.vue deleted file mode 100644 index 7654ad1f..00000000 --- a/frontend/src/components/admin/conversation/tags/Tags.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/frontend/src/components/admin/general/General.vue b/frontend/src/components/admin/general/General.vue deleted file mode 100644 index 7886a155..00000000 --- a/frontend/src/components/admin/general/General.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - diff --git a/frontend/src/components/admin/inbox/EmailInboxForm.vue b/frontend/src/components/admin/inbox/EmailInboxForm.vue deleted file mode 100644 index 0242abb2..00000000 --- a/frontend/src/components/admin/inbox/EmailInboxForm.vue +++ /dev/null @@ -1,107 +0,0 @@ - - - diff --git a/frontend/src/components/admin/inbox/InboxDataTableDropDown.vue b/frontend/src/components/admin/inbox/InboxDataTableDropDown.vue deleted file mode 100644 index cd8c7f9c..00000000 --- a/frontend/src/components/admin/inbox/InboxDataTableDropDown.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - diff --git a/frontend/src/components/admin/notification/NotificationSetting.vue b/frontend/src/components/admin/notification/NotificationSetting.vue deleted file mode 100644 index cc0eaaae..00000000 --- a/frontend/src/components/admin/notification/NotificationSetting.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/notification/NotificationSettingForm.vue b/frontend/src/components/admin/notification/NotificationSettingForm.vue deleted file mode 100644 index 1036c592..00000000 --- a/frontend/src/components/admin/notification/NotificationSettingForm.vue +++ /dev/null @@ -1,207 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/admin/oidc/dataTableDropdown.vue b/frontend/src/components/admin/oidc/dataTableDropdown.vue deleted file mode 100644 index 5470444c..00000000 --- a/frontend/src/components/admin/oidc/dataTableDropdown.vue +++ /dev/null @@ -1,52 +0,0 @@ - - - diff --git a/frontend/src/components/admin/team/Team.vue b/frontend/src/components/admin/team/Team.vue deleted file mode 100644 index 1deaf4f3..00000000 --- a/frontend/src/components/admin/team/Team.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - diff --git a/frontend/src/components/admin/team/teams/TeamDataTableDropdown.vue b/frontend/src/components/admin/team/teams/TeamDataTableDropdown.vue deleted file mode 100644 index 7b5140ce..00000000 --- a/frontend/src/components/admin/team/teams/TeamDataTableDropdown.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/frontend/src/components/admin/team/teams/TeamForm.vue b/frontend/src/components/admin/team/teams/TeamForm.vue deleted file mode 100644 index bb577ea0..00000000 --- a/frontend/src/components/admin/team/teams/TeamForm.vue +++ /dev/null @@ -1,86 +0,0 @@ - - - diff --git a/frontend/src/components/admin/team/teams/Teams.vue b/frontend/src/components/admin/team/teams/Teams.vue deleted file mode 100644 index 8a9feb31..00000000 --- a/frontend/src/components/admin/team/teams/Teams.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - diff --git a/frontend/src/components/admin/team/teams/teamFormSchema.js b/frontend/src/components/admin/team/teams/teamFormSchema.js deleted file mode 100644 index 8167f578..00000000 --- a/frontend/src/components/admin/team/teams/teamFormSchema.js +++ /dev/null @@ -1,12 +0,0 @@ -import * as z from 'zod' - -export const teamFormSchema = z.object({ - name: z - .string({ - required_error: 'Team name is required.' - }) - .min(2, { - message: 'Team name must be at least 2 characters.' - }), - auto_assign_conversations: z.boolean().optional() -}) diff --git a/frontend/src/components/admin/team/users/UsersCard.vue b/frontend/src/components/admin/team/users/UsersCard.vue deleted file mode 100644 index 4070f908..00000000 --- a/frontend/src/components/admin/team/users/UsersCard.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/frontend/src/components/admin/templates/dataTableDropdown.vue b/frontend/src/components/admin/templates/dataTableDropdown.vue deleted file mode 100644 index 4d5c4816..00000000 --- a/frontend/src/components/admin/templates/dataTableDropdown.vue +++ /dev/null @@ -1,61 +0,0 @@ - - - diff --git a/frontend/src/components/admin/templates/formSchema.js b/frontend/src/components/admin/templates/formSchema.js deleted file mode 100644 index f74d7741..00000000 --- a/frontend/src/components/admin/templates/formSchema.js +++ /dev/null @@ -1,11 +0,0 @@ -import * as z from 'zod' - -export const formSchema = z.object({ - name: z.string({ - required_error: 'Template name is required.' - }), - body: z.string({ - required_error: 'Template content is required.' - }), - is_default: z.boolean().optional() -}) diff --git a/frontend/src/components/admin/uploads/LocalFsForm.vue b/frontend/src/components/admin/uploads/LocalFsForm.vue deleted file mode 100644 index be071550..00000000 --- a/frontend/src/components/admin/uploads/LocalFsForm.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - diff --git a/frontend/src/components/admin/uploads/S3Form.vue b/frontend/src/components/admin/uploads/S3Form.vue deleted file mode 100644 index 023d56f8..00000000 --- a/frontend/src/components/admin/uploads/S3Form.vue +++ /dev/null @@ -1,191 +0,0 @@ - - - diff --git a/frontend/src/components/admin/uploads/Uploads.vue b/frontend/src/components/admin/uploads/Uploads.vue deleted file mode 100644 index be33c26d..00000000 --- a/frontend/src/components/admin/uploads/Uploads.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - diff --git a/frontend/src/components/admin/uploads/formSchema.js b/frontend/src/components/admin/uploads/formSchema.js deleted file mode 100644 index 621eed50..00000000 --- a/frontend/src/components/admin/uploads/formSchema.js +++ /dev/null @@ -1,44 +0,0 @@ -import * as z from 'zod' - -export const s3FormSchema = z.object({ - provider: z.string({ - required_error: 'Provider is required.' - }), - region: z.string({ - required_error: 'Region is required.' - }), - access_key: z.string({ - required_error: 'AWS access key is required.' - }), - access_secret: z.string({ - required_error: 'AWS access secret is required.' - }), - bucket_type: z.string({ - required_error: 'Bucket type is required.' - }), - bucket: z.string({ - required_error: 'Bucket is required.' - }), - bucket_path: z.string({ - required_error: 'Bucket path is required.' - }), - upload_expiry: z.string({ - required_error: 'Upload expiry is required.' - }), - url: z - .string({ - required_error: 'S3 backend URL is required.' - }) - .url({ - message: 'S3 backend URL must be a valid URL.' - }) -}) - -export const localFsFormSchema = z.object({ - provider: z.string({ - required_error: 'Provider is required.' - }), - upload_path: z.string({ - required_error: 'Upload path is required.' - }) -}) diff --git a/frontend/src/components/attachment/AttachmentsPreview.vue b/frontend/src/components/attachment/AttachmentsPreview.vue deleted file mode 100644 index 72adc334..00000000 --- a/frontend/src/components/attachment/AttachmentsPreview.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/frontend/src/components/common/Filter.vue b/frontend/src/components/common/Filter.vue deleted file mode 100644 index 0b8302e4..00000000 --- a/frontend/src/components/common/Filter.vue +++ /dev/null @@ -1,162 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/src/components/common/PageHeader.vue b/frontend/src/components/common/PageHeader.vue deleted file mode 100644 index 3bba0016..00000000 --- a/frontend/src/components/common/PageHeader.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/frontend/src/components/common/SidebarNav.vue b/frontend/src/components/common/SidebarNav.vue deleted file mode 100644 index d8dbc884..00000000 --- a/frontend/src/components/common/SidebarNav.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/Conversation.vue b/frontend/src/components/conversation/Conversation.vue deleted file mode 100644 index 2a0d8f17..00000000 --- a/frontend/src/components/conversation/Conversation.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/ConversationPlaceholder.vue b/frontend/src/components/conversation/ConversationPlaceholder.vue deleted file mode 100644 index e810a44a..00000000 --- a/frontend/src/components/conversation/ConversationPlaceholder.vue +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/frontend/src/components/conversation/ConversationTextEditor.vue b/frontend/src/components/conversation/ConversationTextEditor.vue deleted file mode 100644 index 5c9f3b01..00000000 --- a/frontend/src/components/conversation/ConversationTextEditor.vue +++ /dev/null @@ -1,154 +0,0 @@ - - - - - diff --git a/frontend/src/components/conversation/ReplyBox.vue b/frontend/src/components/conversation/ReplyBox.vue deleted file mode 100644 index 3cb98946..00000000 --- a/frontend/src/components/conversation/ReplyBox.vue +++ /dev/null @@ -1,278 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/ReplyBoxMenuBar.vue b/frontend/src/components/conversation/ReplyBoxMenuBar.vue deleted file mode 100644 index 8cacfe87..00000000 --- a/frontend/src/components/conversation/ReplyBoxMenuBar.vue +++ /dev/null @@ -1,58 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/list/ConversationList.vue b/frontend/src/components/conversation/list/ConversationList.vue deleted file mode 100644 index 6014a016..00000000 --- a/frontend/src/components/conversation/list/ConversationList.vue +++ /dev/null @@ -1,92 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/list/ConversationListFilters.vue b/frontend/src/components/conversation/list/ConversationListFilters.vue deleted file mode 100644 index 60986036..00000000 --- a/frontend/src/components/conversation/list/ConversationListFilters.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/conversation/list/ConversationListItem.vue b/frontend/src/components/conversation/list/ConversationListItem.vue deleted file mode 100644 index 31bdff62..00000000 --- a/frontend/src/components/conversation/list/ConversationListItem.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/list/ConversationListItemSkeleton.vue b/frontend/src/components/conversation/list/ConversationListItemSkeleton.vue deleted file mode 100644 index 693003ba..00000000 --- a/frontend/src/components/conversation/list/ConversationListItemSkeleton.vue +++ /dev/null @@ -1,13 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/conversation/sidebar/AssignAgent.vue b/frontend/src/components/conversation/sidebar/AssignAgent.vue deleted file mode 100644 index 3959d447..00000000 --- a/frontend/src/components/conversation/sidebar/AssignAgent.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/sidebar/AssignTeam.vue b/frontend/src/components/conversation/sidebar/AssignTeam.vue deleted file mode 100644 index 8c59e004..00000000 --- a/frontend/src/components/conversation/sidebar/AssignTeam.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/sidebar/ConversationInfo.vue b/frontend/src/components/conversation/sidebar/ConversationInfo.vue deleted file mode 100644 index e05976b1..00000000 --- a/frontend/src/components/conversation/sidebar/ConversationInfo.vue +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/conversation/sidebar/ConversationSideBar.vue b/frontend/src/components/conversation/sidebar/ConversationSideBar.vue deleted file mode 100644 index 3d9c3b81..00000000 --- a/frontend/src/components/conversation/sidebar/ConversationSideBar.vue +++ /dev/null @@ -1,168 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/sidebar/ConversationSideBarContact.vue b/frontend/src/components/conversation/sidebar/ConversationSideBarContact.vue deleted file mode 100644 index b0c98b7c..00000000 --- a/frontend/src/components/conversation/sidebar/ConversationSideBarContact.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/frontend/src/components/conversation/sidebar/PriorityChange.vue b/frontend/src/components/conversation/sidebar/PriorityChange.vue deleted file mode 100644 index 5b5de397..00000000 --- a/frontend/src/components/conversation/sidebar/PriorityChange.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/dashboard/DashboardCard.vue b/frontend/src/components/dashboard/DashboardCard.vue deleted file mode 100644 index fff23fe6..00000000 --- a/frontend/src/components/dashboard/DashboardCard.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/frontend/src/components/dashboard/DashboardLineChart.vue b/frontend/src/components/dashboard/DashboardLineChart.vue deleted file mode 100644 index d5a6b85e..00000000 --- a/frontend/src/components/dashboard/DashboardLineChart.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/frontend/src/components/datatable/DataTable.vue b/frontend/src/components/datatable/DataTable.vue new file mode 100644 index 00000000..fbe83adc --- /dev/null +++ b/frontend/src/components/datatable/DataTable.vue @@ -0,0 +1,66 @@ + + + + diff --git a/frontend/src/components/common/CodeEditor.vue b/frontend/src/components/editor/CodeEditor.vue similarity index 100% rename from frontend/src/components/common/CodeEditor.vue rename to frontend/src/components/editor/CodeEditor.vue diff --git a/frontend/src/components/layout/MenuCard.vue b/frontend/src/components/layout/MenuCard.vue new file mode 100644 index 00000000..aa9aa190 --- /dev/null +++ b/frontend/src/components/layout/MenuCard.vue @@ -0,0 +1,29 @@ + + + diff --git a/frontend/src/components/layout/PageHeader.vue b/frontend/src/components/layout/PageHeader.vue new file mode 100644 index 00000000..c8657935 --- /dev/null +++ b/frontend/src/components/layout/PageHeader.vue @@ -0,0 +1,22 @@ + + + diff --git a/frontend/src/components/message/ContactMessageBubble.vue b/frontend/src/components/message/ContactMessageBubble.vue deleted file mode 100644 index 95357259..00000000 --- a/frontend/src/components/message/ContactMessageBubble.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/frontend/src/components/message/MessageList.vue b/frontend/src/components/message/MessageList.vue deleted file mode 100644 index 0fe1b233..00000000 --- a/frontend/src/components/message/MessageList.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/components/sidebar/Sidebar.vue b/frontend/src/components/sidebar/Sidebar.vue new file mode 100644 index 00000000..7c7621da --- /dev/null +++ b/frontend/src/components/sidebar/Sidebar.vue @@ -0,0 +1,373 @@ + + + diff --git a/frontend/src/components/sidebar/SidebarNavUser.vue b/frontend/src/components/sidebar/SidebarNavUser.vue new file mode 100644 index 00000000..10140164 --- /dev/null +++ b/frontend/src/components/sidebar/SidebarNavUser.vue @@ -0,0 +1,82 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/table/SimpleTable.vue b/frontend/src/components/table/SimpleTable.vue new file mode 100644 index 00000000..0ea54aea --- /dev/null +++ b/frontend/src/components/table/SimpleTable.vue @@ -0,0 +1,53 @@ + + + \ No newline at end of file diff --git a/frontend/src/components/ui/button/Button.vue b/frontend/src/components/ui/button/Button.vue index 4edae9f7..82dcdca0 100644 --- a/frontend/src/components/ui/button/Button.vue +++ b/frontend/src/components/ui/button/Button.vue @@ -3,7 +3,6 @@ import { Primitive } from 'radix-vue' import { buttonVariants } from '.' import { cn } from '@/lib/utils' import { ref, computed } from 'vue' -import { ReloadIcon } from '@radix-icons/vue' const props = defineProps({ variant: { type: null, required: false }, @@ -30,9 +29,11 @@ const computedClass = computed(() => { :class="computedClass" :disabled="isLoading || isDisabled" > - - + + + + + + diff --git a/frontend/src/components/ui/collapsible/Collapsible.vue b/frontend/src/components/ui/collapsible/Collapsible.vue new file mode 100644 index 00000000..d5232a55 --- /dev/null +++ b/frontend/src/components/ui/collapsible/Collapsible.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontend/src/components/ui/collapsible/CollapsibleContent.vue b/frontend/src/components/ui/collapsible/CollapsibleContent.vue new file mode 100644 index 00000000..9e5c179f --- /dev/null +++ b/frontend/src/components/ui/collapsible/CollapsibleContent.vue @@ -0,0 +1,18 @@ + + + diff --git a/frontend/src/components/ui/collapsible/CollapsibleTrigger.vue b/frontend/src/components/ui/collapsible/CollapsibleTrigger.vue new file mode 100644 index 00000000..ace42112 --- /dev/null +++ b/frontend/src/components/ui/collapsible/CollapsibleTrigger.vue @@ -0,0 +1,14 @@ + + + diff --git a/frontend/src/components/ui/collapsible/index.js b/frontend/src/components/ui/collapsible/index.js new file mode 100644 index 00000000..56b5a955 --- /dev/null +++ b/frontend/src/components/ui/collapsible/index.js @@ -0,0 +1,3 @@ +export { default as Collapsible } from './Collapsible.vue'; +export { default as CollapsibleContent } from './CollapsibleContent.vue'; +export { default as CollapsibleTrigger } from './CollapsibleTrigger.vue'; diff --git a/frontend/src/components/ui/combobox/ComboBox.vue b/frontend/src/components/ui/combobox/ComboBox.vue new file mode 100644 index 00000000..c3b7cd13 --- /dev/null +++ b/frontend/src/components/ui/combobox/ComboBox.vue @@ -0,0 +1,83 @@ + + + diff --git a/frontend/src/components/ui/command/CommandDialog.vue b/frontend/src/components/ui/command/CommandDialog.vue index f4e9429e..d1d510f0 100644 --- a/frontend/src/components/ui/command/CommandDialog.vue +++ b/frontend/src/components/ui/command/CommandDialog.vue @@ -6,7 +6,8 @@ import { Dialog, DialogContent } from '@/components/ui/dialog' const props = defineProps({ open: { type: Boolean, required: false }, defaultOpen: { type: Boolean, required: false }, - modal: { type: Boolean, required: false } + modal: { type: Boolean, required: false }, + class: { type: String, required: false } }) const emits = defineEmits(['update:open']) @@ -15,7 +16,7 @@ const forwarded = useForwardPropsEmits(props, emits) @@ -118,7 +114,6 @@ import { SelectValue } from '@/components/ui/select' import { Input } from '@/components/ui/input' -import { Copy } from 'lucide-vue-next' const props = defineProps({ initialValues: { @@ -140,7 +135,7 @@ const props = defineProps({ isLoading: { type: Boolean, required: false - }, + } }) const form = useForm({ diff --git a/frontend/src/components/admin/oidc/dataTableColumns.js b/frontend/src/features/admin/oidc/dataTableColumns.js similarity index 78% rename from frontend/src/components/admin/oidc/dataTableColumns.js rename to frontend/src/features/admin/oidc/dataTableColumns.js index 7897266a..f3289445 100644 --- a/frontend/src/components/admin/oidc/dataTableColumns.js +++ b/frontend/src/features/admin/oidc/dataTableColumns.js @@ -22,23 +22,17 @@ export const columns = [ } }, { - accessorKey: 'disabled', + accessorKey: 'enabled', header: () => h('div', { class: 'text-center' }, 'Enabled'), cell: ({ row }) => { - const disabled = row.getValue('disabled') - return h('div', { class: 'text-center' }, [ - h('input', { - type: 'checkbox', - checked: !disabled, - disabled: true - }) - ]) + const enabled = row.getValue('enabled') + return h('div', { class: 'text-center' }, enabled ? 'Yes' : 'No') } }, { accessorKey: 'updated_at', header: function () { - return h('div', { class: 'text-center' }, 'Modified at') + return h('div', { class: 'text-center' }, 'Updated at') }, cell: function ({ row }) { return h('div', { class: 'text-center' }, format(row.getValue('updated_at'), 'PPpp')) diff --git a/frontend/src/features/admin/oidc/dataTableDropdown.vue b/frontend/src/features/admin/oidc/dataTableDropdown.vue new file mode 100644 index 00000000..16b3329e --- /dev/null +++ b/frontend/src/features/admin/oidc/dataTableDropdown.vue @@ -0,0 +1,82 @@ + + + diff --git a/frontend/src/components/admin/oidc/formSchema.js b/frontend/src/features/admin/oidc/formSchema.js similarity index 64% rename from frontend/src/components/admin/oidc/formSchema.js rename to frontend/src/features/admin/oidc/formSchema.js index 48c2ae52..6f855615 100644 --- a/frontend/src/components/admin/oidc/formSchema.js +++ b/frontend/src/features/admin/oidc/formSchema.js @@ -13,11 +13,8 @@ export const oidcLoginFormSchema = z.object({ .url({ message: 'Provider URL must be a valid URL.' }), - client_id: z.string({ - required_error: 'Client ID is required.' - }), - client_secret: z.string({ - required_error: 'Client Secret is required.' - }), - redirect_uri: z.string().readonly().optional() + client_id: z.string(), + client_secret: z.string(), + redirect_uri: z.string().readonly().optional(), + enabled: z.boolean().default(true).optional(), }) diff --git a/frontend/src/components/admin/team/roles/RoleForm.vue b/frontend/src/features/admin/roles/RoleForm.vue similarity index 50% rename from frontend/src/components/admin/team/roles/RoleForm.vue rename to frontend/src/features/admin/roles/RoleForm.vue index 26931fdd..48136579 100644 --- a/frontend/src/components/admin/team/roles/RoleForm.vue +++ b/frontend/src/features/admin/roles/RoleForm.vue @@ -21,7 +21,7 @@

Set permissions for this role

-
+

{{ entity.name }}

- + @@ -72,121 +72,46 @@ const props = defineProps({ required: false, } }) + const permissions = ref([ { name: 'Conversation', permissions: [ - { name: 'conversations:read', label: 'View' }, - { name: 'conversations:read_all', label: 'View All' }, - { name: 'conversations:read_unassigned', label: 'View Unassigned' }, - { name: 'conversations:read_assigned', label: 'View Assigned' }, - { name: 'conversations:update_user_assignee', label: 'Set assignee' }, - { name: 'conversations:update_team_assignee', label: 'Set team' }, - { name: 'conversations:update_priority', label: 'Set priority' }, - { name: 'conversations:update_status', label: 'Set status' }, - { name: 'conversations:update_tags', label: 'Add Tags' }, - { name: 'messages:read', label: 'View Messages' }, - { name: 'messages:write', label: 'Reply' }, + { name: 'conversations:read', label: 'View conversations' }, + { name: 'conversations:read_assigned', label: 'View conversations assigned to me' }, + { name: 'conversations:read_all', label: 'View all conversations' }, + { name: 'conversations:read_unassigned', label: 'View all unassigned conversations' }, + { name: 'conversations:read_team_inbox', label: 'View conversations in team inbox' }, + { name: 'conversations:update_user_assignee', label: 'Assign conversations to users' }, + { name: 'conversations:update_team_assignee', label: 'Assign conversations to teams' }, + { name: 'conversations:update_priority', label: 'Change conversation priority' }, + { name: 'conversations:update_status', label: 'Change conversation status' }, + { name: 'conversations:update_tags', label: 'Add or remove conversation tags' }, + { name: 'messages:read', label: 'View conversation messages' }, + { name: 'messages:write', label: 'Send messages in conversations' }, + { name: 'view:manage', label: 'Create and manage conversation views' }, ] }, { - name: 'Conversation status', + name: 'Admin settings', permissions: [ - { name: 'status:read', label: 'View' }, - { name: 'status:write', label: 'Update' }, - { name: 'status:delete', label: 'Delete' } + { name: 'general_settings:manage', label: 'Manage General Settings' }, + { name: 'notification_settings:manage', label: 'Manage Notification Settings' }, + { name: 'status:manage', label: 'Manage Conversation Statuses' }, + { name: 'oidc:manage', label: 'Manage SSO Configuration' }, + { name: 'tags:manage', label: 'Manage Tags' }, + { name: 'macros:manage', label: 'Manage Macros' }, + { name: 'users:manage', label: 'Manage Users' }, + { name: 'teams:manage', label: 'Manage Teams' }, + { name: 'automations:manage', label: 'Manage Automations' }, + { name: 'inboxes:manage', label: 'Manage Inboxes' }, + { name: 'roles:manage', label: 'Manage Roles' }, + { name: 'templates:manage', label: 'Manage Templates' }, + { name: 'reports:manage', label: 'Manage Reports' }, + { name: 'business_hours:manage', label: 'Manage Business Hours' }, + { name: 'sla:manage', label: 'Manage SLA Policies' }, ] }, - { - name: 'Admin', - permissions: [ - { name: 'admin:read', label: 'Access' } - ] - }, - { - name: 'Settings', - permissions: [ - { name: 'settings_general:write', label: 'Update' }, - { name: 'settings_notifications:write', label: 'Update' }, - { name: 'settings_notifications:read', label: 'View' } - ] - }, - { - name: 'OpenID Connect SSO', - permissions: [ - { name: 'oidc:read', label: 'View' }, - { name: 'oidc:write', label: 'Update' }, - { name: 'oidc:delete', label: 'Delete' } - ] - }, - { - name: 'Tags', - permissions: [ - { name: 'tags:write', label: 'Write' }, - { name: 'tags:delete', label: 'Delete' } - ] - }, - { - name: 'Canned Responses', - permissions: [ - { name: 'canned_responses:write', label: 'Write' }, - { name: 'canned_responses:delete', label: 'Delete' } - ] - }, - { - name: 'Dashboard', - permissions: [ - { name: 'dashboard_global:read', label: 'Access' } - ] - }, - { - name: 'Users', - permissions: [ - { name: 'users:read', label: 'View' }, - { name: 'users:write', label: 'Write' }, - { name: 'users:delete', label: 'Delete' } - ] - }, - { - name: 'Teams', - permissions: [ - { name: 'teams:read', label: 'View' }, - { name: 'teams:write', label: 'Write' }, - { name: 'teams:delete', label: 'Delete' } - ] - }, - { - name: 'Automations', - permissions: [ - { name: 'automations:read', label: 'View' }, - { name: 'automations:write', label: 'Write' }, - { name: 'automations:delete', label: 'Delete' } - ] - }, - { - name: 'Inboxes', - permissions: [ - { name: 'inboxes:read', label: 'View' }, - { name: 'inboxes:write', label: 'Write' }, - { name: 'inboxes:delete', label: 'Delete' } - ] - }, - { - name: 'Roles', - permissions: [ - { name: 'roles:read', label: 'View' }, - { name: 'roles:write', label: 'Write' }, - { name: 'roles:delete', label: 'Delete' } - ] - }, - { - name: 'Templates', - permissions: [ - { name: 'templates:read', label: 'View' }, - { name: 'templates:write', label: 'Write' }, - { name: 'templates:delete', label: 'Delete' } - ] - } ]) const selectedPermissions = ref([]) diff --git a/frontend/src/components/admin/team/roles/dataTableColumns.js b/frontend/src/features/admin/roles/dataTableColumns.js similarity index 100% rename from frontend/src/components/admin/team/roles/dataTableColumns.js rename to frontend/src/features/admin/roles/dataTableColumns.js diff --git a/frontend/src/components/admin/team/roles/dataTableDropdown.vue b/frontend/src/features/admin/roles/dataTableDropdown.vue similarity index 53% rename from frontend/src/components/admin/team/roles/dataTableDropdown.vue rename to frontend/src/features/admin/roles/dataTableDropdown.vue index 6e48f0a1..6c784283 100644 --- a/frontend/src/components/admin/team/roles/dataTableDropdown.vue +++ b/frontend/src/features/admin/roles/dataTableDropdown.vue @@ -1,4 +1,40 @@ + + - - diff --git a/frontend/src/components/admin/team/roles/formSchema.js b/frontend/src/features/admin/roles/formSchema.js similarity index 100% rename from frontend/src/components/admin/team/roles/formSchema.js rename to frontend/src/features/admin/roles/formSchema.js diff --git a/frontend/src/features/admin/sla/SLAForm.vue b/frontend/src/features/admin/sla/SLAForm.vue new file mode 100644 index 00000000..9f40be94 --- /dev/null +++ b/frontend/src/features/admin/sla/SLAForm.vue @@ -0,0 +1,104 @@ + + + diff --git a/frontend/src/features/admin/sla/dataTableColumns.js b/frontend/src/features/admin/sla/dataTableColumns.js new file mode 100644 index 00000000..df4782c9 --- /dev/null +++ b/frontend/src/features/admin/sla/dataTableColumns.js @@ -0,0 +1,47 @@ +import { h } from 'vue' +import dropdown from './dataTableDropdown.vue' +import { format } from 'date-fns' + +export const columns = [ + { + accessorKey: 'name', + header: function () { + return h('div', { class: 'text-center' }, 'Name') + }, + cell: function ({ row }) { + return h('div', { class: 'text-center font-medium' }, row.getValue('name')) + } + }, + { + accessorKey: 'created_at', + header: function () { + return h('div', { class: 'text-center' }, 'Created at') + }, + cell: function ({ row }) { + return h('div', { class: 'text-center font-medium' }, format(row.getValue('created_at'), 'PPpp')) + } + }, + { + accessorKey: 'updated_at', + header: function () { + return h('div', { class: 'text-center' }, 'Updated at') + }, + cell: function ({ row }) { + return h('div', { class: 'text-center font-medium' }, format(row.getValue('updated_at'), 'PPpp')) + } + }, + { + id: 'actions', + enableHiding: false, + cell: ({ row }) => { + const role = row.original + return h( + 'div', + { class: 'relative' }, + h(dropdown, { + role + }) + ) + } + } +] diff --git a/frontend/src/features/admin/sla/dataTableDropdown.vue b/frontend/src/features/admin/sla/dataTableDropdown.vue new file mode 100644 index 00000000..f04a6555 --- /dev/null +++ b/frontend/src/features/admin/sla/dataTableDropdown.vue @@ -0,0 +1,91 @@ + + + diff --git a/frontend/src/features/admin/sla/formSchema.js b/frontend/src/features/admin/sla/formSchema.js new file mode 100644 index 00000000..2ac48296 --- /dev/null +++ b/frontend/src/features/admin/sla/formSchema.js @@ -0,0 +1,25 @@ +import * as z from 'zod' +import { isGoHourMinuteDuration } from '@/utils/strings' + +export const formSchema = z.object({ + name: z + .string() + .min(1, { message: 'Name is required' }) + .max(255, { + message: 'Name must be at most 255 characters.' + }), + description: z + .string() + .min(1, { message: 'Description is required' }) + .max(255, { + message: 'Description must be at most 255 characters.' + }), + first_response_time: z.string().refine(isGoHourMinuteDuration, { + message: + 'Invalid duration format. Should be a number followed by h (hours), m (minutes).' + }), + resolution_time: z.string().refine(isGoHourMinuteDuration, { + message: + 'Invalid duration format. Should be a number followed by h (hours), m (minutes).' + }), +}) diff --git a/frontend/src/components/admin/conversation/status/StatusForm.vue b/frontend/src/features/admin/status/StatusForm.vue similarity index 100% rename from frontend/src/components/admin/conversation/status/StatusForm.vue rename to frontend/src/features/admin/status/StatusForm.vue diff --git a/frontend/src/components/admin/conversation/status/dataTableColumns.js b/frontend/src/features/admin/status/dataTableColumns.js similarity index 100% rename from frontend/src/components/admin/conversation/status/dataTableColumns.js rename to frontend/src/features/admin/status/dataTableColumns.js diff --git a/frontend/src/components/admin/conversation/status/dataTableDropdown.vue b/frontend/src/features/admin/status/dataTableDropdown.vue similarity index 64% rename from frontend/src/components/admin/conversation/status/dataTableDropdown.vue rename to frontend/src/features/admin/status/dataTableDropdown.vue index 704a9727..ee11e7e0 100644 --- a/frontend/src/components/admin/conversation/status/dataTableDropdown.vue +++ b/frontend/src/features/admin/status/dataTableDropdown.vue @@ -1,7 +1,10 @@ diff --git a/frontend/src/features/admin/teams/TeamForm.vue b/frontend/src/features/admin/teams/TeamForm.vue new file mode 100644 index 00000000..8d45bcc4 --- /dev/null +++ b/frontend/src/features/admin/teams/TeamForm.vue @@ -0,0 +1,249 @@ + + + diff --git a/frontend/src/components/admin/team/teams/TeamsDataTableColumns.js b/frontend/src/features/admin/teams/TeamsDataTableColumns.js similarity index 64% rename from frontend/src/components/admin/team/teams/TeamsDataTableColumns.js rename to frontend/src/features/admin/teams/TeamsDataTableColumns.js index f0a05ecd..183889a3 100644 --- a/frontend/src/components/admin/team/teams/TeamsDataTableColumns.js +++ b/frontend/src/features/admin/teams/TeamsDataTableColumns.js @@ -1,5 +1,5 @@ import { h } from 'vue' -import TeamDataTableDropdown from '@/components/admin/team/teams/TeamDataTableDropdown.vue' +import TeamDataTableDropdown from '@/features/admin/teams/TeamDataTableDropdown.vue' import { format } from 'date-fns' export const columns = [ @@ -12,10 +12,23 @@ export const columns = [ return h('div', { class: 'text-center font-medium' }, row.getValue('name')) } }, + { + accessorKey: 'created_at', + header: function () { + return h('div', { class: 'text-center' }, 'Created at') + }, + cell: function ({ row }) { + return h( + 'div', + { class: 'text-center font-medium' }, + format(row.getValue('created_at'), 'PPpp') + ) + } + }, { accessorKey: 'updated_at', header: function () { - return h('div', { class: 'text-center' }, 'Modified at') + return h('div', { class: 'text-center' }, 'Updated at') }, cell: function ({ row }) { return h( diff --git a/frontend/src/features/admin/teams/teamFormSchema.js b/frontend/src/features/admin/teams/teamFormSchema.js new file mode 100644 index 00000000..536746e8 --- /dev/null +++ b/frontend/src/features/admin/teams/teamFormSchema.js @@ -0,0 +1,17 @@ +import * as z from 'zod' + +export const teamFormSchema = z.object({ + name: z + .string({ + required_error: 'Team name is required.' + }) + .min(2, { + message: 'Team name must be at least 2 characters.' + }), + emoji: z.string({ required_error: 'Emoji is required.' }), + conversation_assignment_type: z.string({ required_error: 'Conversation assignment type is required.' }), + max_auto_assigned_conversations: z.coerce.number().optional().default(0), + timezone: z.string({ required_error: 'Timezone is required.' }), + business_hours_id: z.number().optional().nullable(), + sla_policy_id: z.number().optional().nullable(), +}) diff --git a/frontend/src/components/admin/templates/TemplateForm.vue b/frontend/src/features/admin/templates/TemplateForm.vue similarity index 60% rename from frontend/src/components/admin/templates/TemplateForm.vue rename to frontend/src/features/admin/templates/TemplateForm.vue index 4ce7e203..a4bfe4f7 100644 --- a/frontend/src/components/admin/templates/TemplateForm.vue +++ b/frontend/src/features/admin/templates/TemplateForm.vue @@ -4,7 +4,22 @@ Name - + + + + + + + + + Subject + + @@ -14,14 +29,19 @@ Body - + - {{ `Make sure the template has \{\{ template "content" . \}\}` }} + + {{ `Make sure the template has \{\{ template "content" . \}\} only once.` }} + - +
@@ -29,17 +49,17 @@
- There can be only one default template. + You can have only one default outgoing email template.
- + diff --git a/frontend/src/features/admin/templates/formSchema.js b/frontend/src/features/admin/templates/formSchema.js new file mode 100644 index 00000000..f8206692 --- /dev/null +++ b/frontend/src/features/admin/templates/formSchema.js @@ -0,0 +1,23 @@ +import * as z from 'zod'; + +export const formSchema = z + .object({ + name: z.string({ + required_error: 'Template name is required.', + }), + body: z.string({ + required_error: 'Template content is required.', + }), + type: z.string().optional(), + subject: z.string().optional(), + is_default: z.boolean().optional().default(false), + }) + .superRefine((data, ctx) => { + if (data.type !== 'email_outgoing' && !data.subject) { + ctx.addIssue({ + path: ['subject'], + message: 'Subject is required.', + code: z.ZodIssueCode.custom, + }); + } + }); diff --git a/frontend/src/components/admin/team/users/UserForm.vue b/frontend/src/features/admin/users/UserForm.vue similarity index 80% rename from frontend/src/components/admin/team/users/UserForm.vue rename to frontend/src/features/admin/users/UserForm.vue index 11f39eb2..5d56c962 100644 --- a/frontend/src/components/admin/team/users/UserForm.vue +++ b/frontend/src/features/admin/users/UserForm.vue @@ -9,6 +9,7 @@
+ Last name @@ -73,7 +74,19 @@ - + + + + + +
+ Enabled + +
+
+
+ + @@ -82,7 +95,7 @@ import { watch, onMounted, ref, computed } from 'vue' import { Button } from '@/components/ui/button' import { useForm } from 'vee-validate' import { toTypedSchema } from '@vee-validate/zod' -import { userFormSchema } from './userFormSchema.js' +import { userFormSchema } from './formSchema.js' import { Checkbox } from '@/components/ui/checkbox' import { Label } from '@/components/ui/label' import { vAutoAnimate } from '@formkit/auto-animate/vue' @@ -121,9 +134,9 @@ const roles = ref([]) onMounted(async () => { try { - const [teamsResp, rolesResp] = await Promise.all([api.getTeams(), api.getRoles()]) - teams.value = teamsResp.data.data - roles.value = rolesResp.data.data + const [teamsResp, rolesResp] = await Promise.allSettled([api.getTeams(), api.getRoles()]) + teams.value = teamsResp.value.data.data + roles.value = rolesResp.value.data.data } catch (err) { console.log(err) } @@ -133,11 +146,11 @@ const teamNames = computed(() => teams.value.map((team) => team.name)) const roleNames = computed(() => roles.value.map((role) => role.name)) const form = useForm({ - validationSchema: toTypedSchema(userFormSchema), + validationSchema: toTypedSchema(userFormSchema) }) const onSubmit = form.handleSubmit((values) => { - values.teams = values.teams.map(team => ({ name: team })) + values.teams = values.teams.map((team) => ({ name: team })) props.submitForm(values) }) @@ -148,12 +161,13 @@ watch( if (Object.keys(newValues).length) { setTimeout(() => { form.setValues(newValues) - form.setFieldValue('teams', newValues.teams.map(team => team.name)) + form.setFieldValue( + 'teams', + newValues.teams.map((team) => team.name) + ) }, 0) } }, { deep: true, immediate: true } ) - - diff --git a/frontend/src/components/admin/team/users/UsersDataTableColumns.js b/frontend/src/features/admin/users/dataTableColumns.js similarity index 65% rename from frontend/src/components/admin/team/users/UsersDataTableColumns.js rename to frontend/src/features/admin/users/dataTableColumns.js index 04fc264c..ba1c62c5 100644 --- a/frontend/src/components/admin/team/users/UsersDataTableColumns.js +++ b/frontend/src/features/admin/users/dataTableColumns.js @@ -1,5 +1,5 @@ import { h } from 'vue' -import UserDataTableDropDown from '@/components/admin/team/users/UserDataTableDropDown.vue' +import UserDataTableDropDown from '@/features/admin/users/dataTableDropdown.vue' import { format } from 'date-fns' export const columns = [ @@ -21,6 +21,15 @@ export const columns = [ return h('div', { class: 'text-center font-medium' }, row.getValue('last_name')) } }, + { + accessorKey: 'enabled', + header: function () { + return h('div', { class: 'text-center' }, 'Enabled') + }, + cell: function ({ row }) { + return h('div', { class: 'text-center font-medium' }, row.getValue('enabled') ? 'Yes' : 'No') + } + }, { accessorKey: 'email', header: function () { @@ -30,10 +39,23 @@ export const columns = [ return h('div', { class: 'text-center font-medium' }, row.getValue('email')) } }, + { + accessorKey: 'created_at', + header: function () { + return h('div', { class: 'text-center' }, 'Created at') + }, + cell: function ({ row }) { + return h( + 'div', + { class: 'text-center font-medium' }, + format(row.getValue('created_at'), 'PPpp') + ) + } + }, { accessorKey: 'updated_at', header: function () { - return h('div', { class: 'text-center' }, 'Modified at') + return h('div', { class: 'text-center' }, 'Updated at') }, cell: function ({ row }) { return h( diff --git a/frontend/src/components/admin/team/users/UserDataTableDropDown.vue b/frontend/src/features/admin/users/dataTableDropdown.vue similarity index 54% rename from frontend/src/components/admin/team/users/UserDataTableDropDown.vue rename to frontend/src/features/admin/users/dataTableDropdown.vue index d2de83b3..d088def1 100644 --- a/frontend/src/components/admin/team/users/UserDataTableDropDown.vue +++ b/frontend/src/features/admin/users/dataTableDropdown.vue @@ -1,4 +1,35 @@ + + - - diff --git a/frontend/src/components/admin/team/users/userFormSchema.js b/frontend/src/features/admin/users/formSchema.js similarity index 92% rename from frontend/src/components/admin/team/users/userFormSchema.js rename to frontend/src/features/admin/users/formSchema.js index b462e2be..98b7b527 100644 --- a/frontend/src/components/admin/team/users/userFormSchema.js +++ b/frontend/src/features/admin/users/formSchema.js @@ -30,6 +30,6 @@ export const userFormSchema = z.object({ .regex(/^$|^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,50}$/, { message: 'Password must be between 8 and 50 characters long, contain at least one uppercase letter and one number.' }) - .optional() - + .optional(), + enabled: z.boolean().optional().default(true) }) diff --git a/frontend/src/features/command/CommandBox.vue b/frontend/src/features/command/CommandBox.vue new file mode 100644 index 00000000..1a9adff1 --- /dev/null +++ b/frontend/src/features/command/CommandBox.vue @@ -0,0 +1,326 @@ + + + diff --git a/frontend/src/features/conversation/Conversation.vue b/frontend/src/features/conversation/Conversation.vue new file mode 100644 index 00000000..22f07616 --- /dev/null +++ b/frontend/src/features/conversation/Conversation.vue @@ -0,0 +1,73 @@ + + + diff --git a/frontend/src/features/conversation/ConversationPlaceholder.vue b/frontend/src/features/conversation/ConversationPlaceholder.vue new file mode 100644 index 00000000..3c7f3183 --- /dev/null +++ b/frontend/src/features/conversation/ConversationPlaceholder.vue @@ -0,0 +1,5 @@ + diff --git a/frontend/src/features/conversation/ConversationTextEditor.vue b/frontend/src/features/conversation/ConversationTextEditor.vue new file mode 100644 index 00000000..440fa817 --- /dev/null +++ b/frontend/src/features/conversation/ConversationTextEditor.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/frontend/src/features/conversation/MacroActionsPreview.vue b/frontend/src/features/conversation/MacroActionsPreview.vue new file mode 100644 index 00000000..e8e563e1 --- /dev/null +++ b/frontend/src/features/conversation/MacroActionsPreview.vue @@ -0,0 +1,87 @@ + + + diff --git a/frontend/src/features/conversation/ReplyBox.vue b/frontend/src/features/conversation/ReplyBox.vue new file mode 100644 index 00000000..0e2a37c4 --- /dev/null +++ b/frontend/src/features/conversation/ReplyBox.vue @@ -0,0 +1,557 @@ + + + diff --git a/frontend/src/features/conversation/ReplyBoxMenuBar.vue b/frontend/src/features/conversation/ReplyBoxMenuBar.vue new file mode 100644 index 00000000..a0d97774 --- /dev/null +++ b/frontend/src/features/conversation/ReplyBoxMenuBar.vue @@ -0,0 +1,81 @@ + + + diff --git a/frontend/src/components/conversation/list/ConversationEmptyList.vue b/frontend/src/features/conversation/list/ConversationEmptyList.vue similarity index 69% rename from frontend/src/components/conversation/list/ConversationEmptyList.vue rename to frontend/src/features/conversation/list/ConversationEmptyList.vue index 51c1ec6e..af8d434f 100644 --- a/frontend/src/components/conversation/list/ConversationEmptyList.vue +++ b/frontend/src/features/conversation/list/ConversationEmptyList.vue @@ -1,10 +1,10 @@