diff --git a/.gitea/workflow/check.yaml b/.gitea/workflow/check.yaml deleted file mode 100644 index 2b78c23..0000000 --- a/.gitea/workflow/check.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: Check build frontend and backend -run-name: ${{ gitea.actor }} is building nixcn-cms check -on: [push] - -jobs: - build-frontend: - name: Build PNPM Frontend - runs-on: ubuntu-latest - steps: - - name: Check out repository code - uses: actions/checkout@v4 - - - name: Install Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - - - name: Install Corepack - run: npm install corepack - - - name: Enable Corepack - run: corepack enable - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build frontend - run: pnpm build - - build-backend: - name: Build Go Backend - runs-on: ubuntu-latest - steps: - - name: Check out repository code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.25.5" - cache: false - - - name: Install dependencies - run: go mod tidy - - - name: Generate go dependencies - run: go generate . - - - name: Build backend - run: go build -v -o server main.go - - - name: Run Tests - run: go test ./... diff --git a/.gitignore b/.gitignore index e9e6933..573623d 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ __MACOSX # go gen *_gen.go + +# test files +.test/ diff --git a/Containerfile b/Containerfile index 795094f..e40aa00 100644 --- a/Containerfile +++ b/Containerfile @@ -1,25 +1,13 @@ -FROM docker.io/node:22-alpine AS client-cms-build -RUN apk add just -y -RUN npm install -g corepack && \ - corepack enable -WORKDIR /app -ENV VITE_APP_BASE_URL=$CLIENT_BASE_URL -COPY . . -RUN just build-client-cms - -FROM docker.io/busybox:1.37 AS client-cms -WORKDIR /app -COPY --from=client-build /app/.outputs/client/cms/dist . -EXPOSE 3000 -ENTRYPOINT ["httpd", "-f", "-p", "3000", "-h", "/app", "-v"] - FROM docker.io/golang:1.25.5-alpine AS backend-build WORKDIR /app COPY . /app +RUN go install github.com/swaggo/swag/cmd/swag@latest RUN go mod tidy && \ + go generate . && \ + go test ./... && \ go build -o /app/nixcn-cms -FROM docker.io/alpine:3.23 AS backend +FROM docker.io/alpine:3.23 WORKDIR /app COPY --from=backend-build /app/nixcn-cms /app/nixcn-cms EXPOSE 8000 diff --git a/api/agenda/agenda_handler_test.go b/api/agenda/agenda_handler_test.go new file mode 100644 index 0000000..5ef4d49 --- /dev/null +++ b/api/agenda/agenda_handler_test.go @@ -0,0 +1,443 @@ +package agenda + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/data" + "nixcn-cms/internal/authtoken" + "nixcn-cms/service/service_agenda" + "nixcn-cms/service/service_event" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func issueToken(t *testing.T, userId uuid.UUID) string { + t.Helper() + tok := &authtoken.Token{Application: viper.GetString("server.application")} + access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId) + require.NoError(t, err) + return access +} + +func newAgendaRouter(t *testing.T) *gin.Engine { + t.Helper() + r := gin.New() + ApiHandler(r.Group("/agenda")) + return r +} + +func postWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func patchWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func getWithBearer(t *testing.T, r *gin.Engine, path, token string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +// seedEventWithAttendee creates an event owned by owner and joins it with attendee. +func seedEventWithAttendee(t *testing.T, owner, attendee *data.User) *data.Event { + t.Helper() + ctx := t.Context() + + eventSvc := service_event.NewEventService() + cr := eventSvc.Create(&service_event.EventCreatePayload{ + Context: ctx, + Data: &service_event.EventCreateData{ + UserId: owner.UserId.String(), + PermissionLevel: owner.PermissionLevel, + Type: "party", + Name: "Agenda Test Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 100, + }, + }) + require.Equal(t, 200, cr.Common.HttpCode) + + eventId, err := uuid.Parse(cr.Data.EventId) + require.NoError(t, err) + + // Join as attendee + agendaSvc := service_agenda.NewAgendaService() + jr := agendaSvc.Submit(&service_agenda.SubmitPayload{ + Context: ctx, + UserId: attendee.UserId, + Data: &service_agenda.SubmitData{EventId: eventId, Name: "dummy"}, + }) + // It's OK if this fails due to not being joined; we just need the event. + _ = jr + + // Actually join via event service + joinResult := eventSvc.Join(&service_event.EventJoinPayload{ + Context: ctx, + Data: &service_event.EventJoinData{ + EventId: cr.Data.EventId, + UserId: attendee.UserId.String(), + }, + }) + require.Equal(t, 200, joinResult.Common.HttpCode) + + var event data.Event + require.NoError(t, data.Database.Where("event_id = ?", eventId).First(&event).Error) + return &event +} + +// ---- Submit ---- + +func TestAgendaSubmitHandlerNoAuth(t *testing.T) { + testutil.Setup(t) + r := newAgendaRouter(t) + + w := postWithBearer(t, r, "/agenda/submit", "", map[string]any{ + "event_id": uuid.New().String(), + "name": "Test Talk", + }) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestAgendaSubmitHandlerMissingFields(t *testing.T) { + testutil.SetupWithAuth(t) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + // Missing name and description → handler returns 400 + w := postWithBearer(t, r, "/agenda/submit", token, map[string]any{ + "event_id": uuid.New().String(), + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaSubmitHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + token := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + w := postWithBearer(t, r, "/agenda/submit", token, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "My Talk", + Description: "About Go testing", + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- ScheduleGet ---- + +func TestAgendaScheduleGetHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newAgendaRouter(t) + + w := getWithBearer(t, r, "/agenda/schedule?event_id=not-a-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaScheduleGetHandlerNotPublished(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + token := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + w := getWithBearer(t, r, "/agenda/schedule?event_id="+event.EventId.String(), token) + assert.Equal(t, http.StatusForbidden, w.Code) +} + +// ---- MyList ---- + +func TestAgendaMyListHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newAgendaRouter(t) + + w := getWithBearer(t, r, "/agenda/my-list?event_id=bad-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaMyListHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + token := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + w := getWithBearer(t, r, "/agenda/my-list?event_id="+event.EventId.String(), token) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- List (manager) ---- + +func TestAgendaListHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, manager.UserId) + r := newAgendaRouter(t) + + w := getWithBearer(t, r, "/agenda/list?event_id=bad-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Review (manager) ---- + +func TestAgendaReviewHandlerMissingFields(t *testing.T) { + testutil.SetupWithAuth(t) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, manager.UserId) + r := newAgendaRouter(t) + + w := patchWithBearer(t, r, "/agenda/review", token, map[string]any{ + "status": "approved", + // missing agenda_id and event_id → 400 + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaReviewHandlerInvalidStatus(t *testing.T) { + testutil.SetupWithAuth(t) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, manager.UserId) + r := newAgendaRouter(t) + + w := patchWithBearer(t, r, "/agenda/review", token, service_agenda.AgendaReviewData{ + EventId: uuid.New(), + AgendaId: uuid.New(), + Status: "maybe", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaReviewHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + managerToken := issueToken(t, manager.UserId) + attendeeToken := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "Talk to Review", + Description: "desc", + }) + require.Equal(t, http.StatusOK, submitW.Code) + var submitResp map[string]any + require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp)) + agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string) + + w := patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{ + EventId: event.EventId, + AgendaId: uuid.MustParse(agendaId), + Status: "approved", + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- List (success) ---- + +func TestAgendaListHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + managerToken := issueToken(t, manager.UserId) + attendeeToken := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "Talk 1", + }) + + w := getWithBearer(t, r, "/agenda/list?event_id="+event.EventId.String(), managerToken) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- Update ---- + +func TestAgendaUpdateHandlerMissingAgendaId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newAgendaRouter(t) + + w := patchWithBearer(t, r, "/agenda/update", token, map[string]any{ + "name": "New Name", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaUpdateHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + attendeeToken := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "Original Talk", + Description: "desc", + }) + require.Equal(t, http.StatusOK, submitW.Code) + var submitResp map[string]any + require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp)) + agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string) + + newName := "Updated Talk" + w := patchWithBearer(t, r, "/agenda/update", attendeeToken, service_agenda.AgendaUpdateData{ + AgendaId: uuid.MustParse(agendaId), + Name: &newName, + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- Schedule PATCH ---- + +func TestAgendaScheduleHandlerMissingAgendaId(t *testing.T) { + testutil.SetupWithAuth(t) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, manager.UserId) + r := newAgendaRouter(t) + + w := patchWithBearer(t, r, "/agenda/schedule", token, map[string]any{ + "start_time": time.Now().Add(time.Hour), + "end_time": time.Now().Add(2 * time.Hour), + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestAgendaScheduleHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + managerToken := issueToken(t, manager.UserId) + attendeeToken := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "Schedule Me", + Description: "base64desc", + }) + require.Equal(t, http.StatusOK, submitW.Code) + var submitResp map[string]any + require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp)) + agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string) + + reviewW := patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{ + EventId: event.EventId, + AgendaId: uuid.MustParse(agendaId), + Status: "approved", + }) + require.Equal(t, http.StatusOK, reviewW.Code) + + now := time.Now() + w := patchWithBearer(t, r, "/agenda/schedule", managerToken, service_agenda.AgendaScheduleData{ + AgendaId: uuid.MustParse(agendaId), + StartTime: now.Add(time.Hour), + EndTime: now.Add(2 * time.Hour), + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- ScheduleGet (success) ---- + +func TestAgendaScheduleGetHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10) + event := seedEventWithAttendee(t, owner, attendee) + manager := testutil.SeedUser(t, testutil.RandomEmail(), 30) + managerToken := issueToken(t, manager.UserId) + attendeeToken := issueToken(t, attendee.UserId) + r := newAgendaRouter(t) + + submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{ + EventId: event.EventId, + Name: "Published Talk", + Description: "base64desc", + }) + require.Equal(t, http.StatusOK, submitW.Code) + var submitResp map[string]any + require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp)) + agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string) + + patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{ + EventId: event.EventId, + AgendaId: uuid.MustParse(agendaId), + Status: "approved", + }) + + now := time.Now() + patchWithBearer(t, r, "/agenda/schedule", managerToken, service_agenda.AgendaScheduleData{ + AgendaId: uuid.MustParse(agendaId), + StartTime: now.Add(time.Hour), + EndTime: now.Add(2 * time.Hour), + }) + + require.NoError(t, new(data.Event).PatchByEventId(t.Context(), event.EventId, data.WithIsAgendaPublished(true))) + + w := getWithBearer(t, r, "/agenda/schedule?event_id="+event.EventId.String(), attendeeToken) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + items, ok := resp["data"].([]any) + require.True(t, ok) + assert.Len(t, items, 1) +} diff --git a/api/agenda/handler.go b/api/agenda/handler.go new file mode 100644 index 0000000..95bbad7 --- /dev/null +++ b/api/agenda/handler.go @@ -0,0 +1,32 @@ +package agenda + +import ( + "nixcn-cms/middleware" + "nixcn-cms/service/service_agenda" + + "github.com/gin-gonic/gin" +) + +type AgendaHandler struct { + svc service_agenda.AgendaService +} + +func ApiHandler(r *gin.RouterGroup) { + agendaSvc := service_agenda.NewAgendaService() + agendaHandler := &AgendaHandler{agendaSvc} + + // Lv10+ attendee routes + attendee := r.Group("") + attendee.Use(middleware.JWTAuth(), middleware.Permission(10)) + attendee.POST("/submit", agendaHandler.Submit) + attendee.PATCH("/update", agendaHandler.Update) + attendee.GET("/my-list", agendaHandler.MyList) + attendee.GET("/schedule", agendaHandler.ScheduleGet) + + // Manager routes (Lv30+) + manager := r.Group("") + manager.Use(middleware.JWTAuth(), middleware.Permission(30)) + manager.PATCH("/review", agendaHandler.Review) + manager.PATCH("/schedule", agendaHandler.Schedule) + manager.GET("/list", agendaHandler.List) +} diff --git a/api/agenda/list.go b/api/agenda/list.go new file mode 100644 index 0000000..37779a3 --- /dev/null +++ b/api/agenda/list.go @@ -0,0 +1,106 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// List retrieves all agenda items for an event. Manager only. +// +// @Summary List All Agendas +// @Description Returns all agendas for the specified event, regardless of status. Manager only. +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event ID" +// @Success 200 {object} utils.RespStatus{data=[]service_agenda.AgendaListItem} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/list [get] +func (self *AgendaHandler) List(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "list", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaList) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + type ListQuery struct { + EventId string `form:"event_id"` + } + + var query ListQuery + if err := c.ShouldBindQuery(&query); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + eventId, err := uuid.Parse(query.EventId) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("invalid event_id")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.List(&service_agenda.AgendaListPayload{ + Context: ctx, + UserId: userId, + Data: &service_agenda.AgendaListData{ + EventId: eventId, + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/agenda/my_list.go b/api/agenda/my_list.go new file mode 100644 index 0000000..20c4ca0 --- /dev/null +++ b/api/agenda/my_list.go @@ -0,0 +1,105 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// MyList retrieves the current user's own agenda submissions for an event. +// +// @Summary My Agenda List +// @Description Returns the calling user's agenda submissions for the specified event. User must be a joined attendee (Lv10+). +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event ID" +// @Success 200 {object} utils.RespStatus{data=[]data.Agenda} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Not an Attendee" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/my-list [get] +func (self *AgendaHandler) MyList(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "my_list", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaMyList) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + type MyListQuery struct { + EventId string `form:"event_id"` + } + + var query MyListQuery + if err := c.ShouldBindQuery(&query); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + eventId, err := uuid.Parse(query.EventId) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("invalid event_id")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.MyList(&service_agenda.AgendaMyListPayload{ + Context: ctx, + UserId: userId, + Data: &service_agenda.AgendaMyListData{ + EventId: eventId, + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/agenda/review.go b/api/agenda/review.go new file mode 100644 index 0000000..9118a9c --- /dev/null +++ b/api/agenda/review.go @@ -0,0 +1,110 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Review handles manager approval or rejection of an agenda item. +// +// @Summary Review Agenda +// @Description Manager sets the status of an agenda to approved or rejected. Not allowed after agenda is published. +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param body body service_agenda.AgendaReviewData true "Review Data" +// @Success 200 {object} utils.RespStatus{data=nil} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input / Already Published" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event or Agenda Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/review [patch] +func (self *AgendaHandler) Review(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "review", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaReview) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + data := new(service_agenda.AgendaReviewData) + if err := c.ShouldBindJSON(data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.AgendaId == uuid.Nil || data.EventId == uuid.Nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("agenda_id and event_id are required")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.Status != "approved" && data.Status != "rejected" { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("status must be 'approved' or 'rejected'")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Review(&service_agenda.AgendaReviewPayload{ + Context: ctx, + UserId: userId, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/agenda/schedule.go b/api/agenda/schedule.go new file mode 100644 index 0000000..15caa20 --- /dev/null +++ b/api/agenda/schedule.go @@ -0,0 +1,98 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Schedule handles setting start/end times for an approved agenda item. +// +// @Summary Schedule Agenda +// @Description Manager sets start_time and end_time on an approved agenda item. Available even after publish. +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param body body service_agenda.AgendaScheduleData true "Schedule Data" +// @Success 200 {object} utils.RespStatus{data=nil} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input / Not Approved" +// @Failure 404 {object} utils.RespStatus{data=nil} "Agenda Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/schedule [patch] +func (self *AgendaHandler) Schedule(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "schedule", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaSchedule) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + data := new(service_agenda.AgendaScheduleData) + if err := c.ShouldBindJSON(data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.AgendaId == uuid.Nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("agenda_id is required")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Schedule(&service_agenda.AgendaSchedulePayload{ + Context: ctx, + UserId: userId, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/agenda/schedule_get.go b/api/agenda/schedule_get.go new file mode 100644 index 0000000..fc1b9ec --- /dev/null +++ b/api/agenda/schedule_get.go @@ -0,0 +1,80 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// ScheduleGet returns the published, scheduled agenda for an event. +// +// @Summary Get Agenda Schedule +// @Description Returns all approved and scheduled agenda items, sorted by start_time ascending. Returns 403 if the agenda has not been published. +// @Tags Agenda +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event ID" +// @Success 200 {object} utils.RespStatus{data=[]data.AgendaDoc} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Agenda Not Published" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/schedule [get] +func (self *AgendaHandler) ScheduleGet(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "schedule_get", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaScheduleGet) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + type ScheduleQuery struct { + EventId string `form:"event_id"` + } + + var query ScheduleQuery + if err := c.ShouldBindQuery(&query); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + eventId, err := uuid.Parse(query.EventId) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("invalid event_id")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.ScheduleGet(&service_agenda.AgendaScheduleGetPayload{ + Context: ctx, + Data: &service_agenda.AgendaScheduleGetData{ + EventId: eventId, + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/agenda/submit.go b/api/agenda/submit.go new file mode 100644 index 0000000..6da648e --- /dev/null +++ b/api/agenda/submit.go @@ -0,0 +1,100 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Submit handles the submission of a new agenda item. +// +// @Summary Submit Agenda +// @Description Creates a new agenda item for a specific attendance record. +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param body body service_agenda.SubmitData true "Agenda Submission Data" +// @Success 200 {object} utils.RespStatus{data=service_agenda.SubmitResponse} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/submit [post] +func (self *AgendaHandler) Submit(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "submit", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaSubmit) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + data := new(service_agenda.SubmitData) + + if err := c.ShouldBindJSON(data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.EventId == uuid.Nil || data.Name == "" || data.Description == "" { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("Invalid Input")), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Submit(&service_agenda.SubmitPayload{ + Context: ctx, + UserId: userId, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), &result.Data) +} diff --git a/api/agenda/update.go b/api/agenda/update.go new file mode 100644 index 0000000..8619e27 --- /dev/null +++ b/api/agenda/update.go @@ -0,0 +1,113 @@ +package agenda + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_agenda" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Update handles editing an agenda item's name or description. +// +// @Summary Update Agenda +// @Description Submitter may edit their own pending agendas before the event deadline. Managers may edit any agenda with no restrictions. +// @Tags Agenda +// @Accept json +// @Produce json +// @Security Bearer +// @Param body body service_agenda.AgendaUpdateData true "Agenda Update Data" +// @Success 200 {object} utils.RespStatus{data=nil} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input / Not Pending / Deadline Passed" +// @Failure 403 {object} utils.RespStatus{data=nil} "Not Submitter" +// @Failure 404 {object} utils.RespStatus{data=nil} "Agenda Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /agenda/update [patch] +func (self *AgendaHandler) Update(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_agenda", + "update", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAgendaUpdate) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + data := new(service_agenda.AgendaUpdateData) + if err := c.ShouldBindJSON(data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + if data.AgendaId == uuid.Nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("agenda_id is required")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + data.PermissionLevel = permissionLevelOrig.(uint) + + result := self.svc.Update(&service_agenda.AgendaUpdatePayload{ + Context: ctx, + UserId: userId, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/auth/auth_handler_test.go b/api/auth/auth_handler_test.go new file mode 100644 index 0000000..91738f7 --- /dev/null +++ b/api/auth/auth_handler_test.go @@ -0,0 +1,251 @@ +package auth + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/service/service_auth" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func setupAuthRouter(t *testing.T) *gin.Engine { + t.Helper() + testutil.Setup(t) + testutil.SeedClient(t) + + r := gin.New() + ApiHandler(r.Group("/auth")) + return r +} + +func postJSON(t *testing.T, r *gin.Engine, path string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func getRequest(t *testing.T, r *gin.Engine, path string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func postWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + var bodyReader io.Reader + if body != nil { + b, _ := json.Marshal(body) + bodyReader = bytes.NewBuffer(b) + } + req := httptest.NewRequest(http.MethodPost, path, bodyReader) + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func extractQueryParam(t *testing.T, rawURL, param string) string { + t.Helper() + u, err := url.Parse(rawURL) + require.NoError(t, err) + return u.Query().Get(param) +} + +// ---- Magic ---- + +func TestMagicHandlerSuccess(t *testing.T) { + r := setupAuthRouter(t) + + w := postJSON(t, r, "/auth/magic", service_auth.MagicData{ + ClientId: testutil.TestClientID, + RedirectUri: "http://localhost/callback", + State: "s", + Email: "handler@example.com", + }) + + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + data, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.NotEmpty(t, data["uri"]) +} + +func TestMagicHandlerInvalidJSON(t *testing.T) { + r := setupAuthRouter(t) + + req := httptest.NewRequest(http.MethodPost, "/auth/magic", bytes.NewBufferString("{invalid")) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Redirect ---- + +func TestRedirectHandlerMissingParams(t *testing.T) { + r := setupAuthRouter(t) + + w := getRequest(t, r, "/auth/redirect") + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestRedirectHandlerInvalidCode(t *testing.T) { + r := setupAuthRouter(t) + + w := getRequest(t, r, "/auth/redirect?client_id="+testutil.TestClientID+ + "&redirect_uri=http://localhost/callback&code=bad-code&state=s") + + assert.Equal(t, http.StatusForbidden, w.Code) +} + +// ---- Token ---- + +func TestTokenHandlerInvalidCode(t *testing.T) { + r := setupAuthRouter(t) + + w := postJSON(t, r, "/auth/token", service_auth.TokenData{Code: "invalid"}) + assert.Equal(t, http.StatusForbidden, w.Code) +} + +// ---- Refresh ---- + +func TestRefreshHandlerInvalidToken(t *testing.T) { + r := setupAuthRouter(t) + + w := postJSON(t, r, "/auth/refresh", service_auth.RefreshData{RefreshToken: "bad"}) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +// ---- Full flow: Magic → Redirect → Token → Refresh ---- + +func TestAuthFullFlow(t *testing.T) { + r := setupAuthRouter(t) + + // 1. Magic + magicW := postJSON(t, r, "/auth/magic", service_auth.MagicData{ + ClientId: testutil.TestClientID, + RedirectUri: "http://localhost/callback", + State: "s", + Email: "flow@example.com", + }) + require.Equal(t, http.StatusOK, magicW.Code) + + var magicResp map[string]any + require.NoError(t, json.Unmarshal(magicW.Body.Bytes(), &magicResp)) + dataMap := magicResp["data"].(map[string]any) + rawURI := dataMap["uri"].(string) + code := extractQueryParam(t, rawURI, "code") + require.NotEmpty(t, code) + + // 2. Redirect → 302 + redirectW := getRequest(t, r, "/auth/redirect?client_id="+testutil.TestClientID+ + "&redirect_uri=http://localhost/callback&code="+code+"&state=s") + require.Equal(t, http.StatusFound, redirectW.Code) + + location := redirectW.Header().Get("Location") + require.NotEmpty(t, location) + tokenCode := extractQueryParam(t, location, "code") + require.NotEmpty(t, tokenCode) + + // 3. Token + tokenW := postJSON(t, r, "/auth/token", service_auth.TokenData{Code: tokenCode}) + require.Equal(t, http.StatusOK, tokenW.Code) + + var tokenResp map[string]any + require.NoError(t, json.Unmarshal(tokenW.Body.Bytes(), &tokenResp)) + tokenData := tokenResp["data"].(map[string]any) + accessToken := tokenData["access_token"].(string) + refreshToken := tokenData["refresh_token"].(string) + + // 4. Refresh + refreshW := postJSON(t, r, "/auth/refresh", service_auth.RefreshData{ + RefreshToken: refreshToken, + }) + require.Equal(t, http.StatusOK, refreshW.Code) + + var refreshResp map[string]any + require.NoError(t, json.Unmarshal(refreshW.Body.Bytes(), &refreshResp)) + refreshData := refreshResp["data"].(map[string]any) + assert.NotEmpty(t, refreshData["access_token"]) + assert.NotEqual(t, refreshToken, refreshData["refresh_token"]) + _ = accessToken +} + +// ---- Exchange ---- + +func TestExchangeHandlerNoAuth(t *testing.T) { + r := setupAuthRouter(t) + + w := postJSON(t, r, "/auth/exchange", service_auth.ExchangeData{ + ClientId: testutil.TestClientID, + RedirectUri: "http://localhost/callback", + State: "s", + }) + // No auth header → 401 + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestExchangeHandlerSuccess(t *testing.T) { + r := setupAuthRouter(t) + + // Step 1: Magic (debug mode, returns redirect URI with code) + magicW := postJSON(t, r, "/auth/magic", service_auth.MagicData{ + ClientId: testutil.TestClientID, + RedirectUri: "http://localhost/callback", + State: "s", + Email: "exchange@example.com", + }) + require.Equal(t, http.StatusOK, magicW.Code) + var magicResp map[string]any + require.NoError(t, json.Unmarshal(magicW.Body.Bytes(), &magicResp)) + rawURI := magicResp["data"].(map[string]any)["uri"].(string) + code := extractQueryParam(t, rawURI, "code") + + // Step 2: Redirect → produces token code + redirectW := getRequest(t, r, "/auth/redirect?client_id="+testutil.TestClientID+ + "&redirect_uri=http://localhost/callback&code="+code+"&state=s") + require.Equal(t, http.StatusFound, redirectW.Code) + location := redirectW.Header().Get("Location") + tokenCode := extractQueryParam(t, location, "code") + + // Step 3: Token → get access token + tokenW := postJSON(t, r, "/auth/token", service_auth.TokenData{Code: tokenCode}) + require.Equal(t, http.StatusOK, tokenW.Code) + var tokenResp map[string]any + require.NoError(t, json.Unmarshal(tokenW.Body.Bytes(), &tokenResp)) + accessToken := tokenResp["data"].(map[string]any)["access_token"].(string) + + // Step 4: Exchange (requires JWT Bearer token) + w := postWithBearer(t, r, "/auth/exchange", accessToken, service_auth.ExchangeData{ + ClientId: testutil.TestClientID, + RedirectUri: "http://localhost/callback", + State: "s", + }) + assert.Equal(t, http.StatusOK, w.Code) + var exchangeResp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &exchangeResp)) + exchangeData, ok := exchangeResp["data"].(map[string]any) + require.True(t, ok) + assert.NotEmpty(t, exchangeData["redirect_uri"]) +} diff --git a/api/auth/exchange.go b/api/auth/exchange.go new file mode 100644 index 0000000..73914cd --- /dev/null +++ b/api/auth/exchange.go @@ -0,0 +1,91 @@ +package auth + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_auth" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Exchange handles the authorization code swap process. +// +// @Summary Exchange Auth Code +// @Description Exchanges client credentials and user session for a specific redirect authorization code. +// @Tags Authentication +// @Accept json +// @Produce json +// @Security Bearer +// @Param payload body service_auth.ExchangeData true "Exchange Request Credentials" +// @Success 200 {object} utils.RespStatus{data=service_auth.ExchangeResponse} "Successful exchange" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /auth/exchange [post] +func (self *AuthHandler) Exchange(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_auth", + "exchange", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAuthExchange) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + var exchangeData service_auth.ExchangeData + + if err := c.ShouldBindJSON(&exchangeData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUnauthorized), + exception.WithError(errors.New("Unauthorized")), + ).Throw(ctx).String() + + utils.HttpResponse(c, 401, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 500, errorCode) + return + } + + result := self.svc.Exchange(&service_auth.ExchangePayload{ + Context: ctx, + UserId: userId, + Data: &exchangeData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/auth/handler.go b/api/auth/handler.go index ad630b1..149552d 100644 --- a/api/auth/handler.go +++ b/api/auth/handler.go @@ -1,8 +1,23 @@ package auth import ( + "nixcn-cms/middleware" + "nixcn-cms/service/service_auth" + "github.com/gin-gonic/gin" ) -func ApiHandler(r *gin.RouterGroup) { +type AuthHandler struct { + svc service_auth.AuthService +} + +func ApiHandler(r *gin.RouterGroup) { + authSvc := service_auth.NewAuthService() + authHandler := &AuthHandler{authSvc} + + r.GET("/redirect", authHandler.Redirect) + r.POST("/magic", authHandler.Magic) + r.POST("/token", authHandler.Token) + r.POST("/refresh", authHandler.Refresh) + r.POST("/exchange", middleware.JWTAuth(), authHandler.Exchange) } diff --git a/api/auth/magic.go b/api/auth/magic.go new file mode 100644 index 0000000..00487ff --- /dev/null +++ b/api/auth/magic.go @@ -0,0 +1,63 @@ +package auth + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_auth" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Magic handles the "Magic Link" authentication request. +// +// @Summary Request Magic Link +// @Description Verifies Turnstile token and sends an authentication link via email. Returns the URI directly if debug mode is enabled. +// @Tags Authentication +// @Accept json +// @Produce json +// @Param payload body service_auth.MagicData true "Magic Link Request Data" +// @Success 200 {object} utils.RespStatus{data=service_auth.MagicResponse} "Successful request" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Turnstile Verification Failed" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /auth/magic [post] +func (self *AuthHandler) Magic(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_auth", + "magic", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAuthMagic) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + var magicData service_auth.MagicData + + if err := c.ShouldBindJSON(&magicData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + magicData.ClientIP = c.ClientIP() + + result := self.svc.Magic(&service_auth.MagicPayload{ + Context: ctx, + Data: &magicData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/auth/redirect.go b/api/auth/redirect.go new file mode 100644 index 0000000..2a397ec --- /dev/null +++ b/api/auth/redirect.go @@ -0,0 +1,70 @@ +package auth + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_auth" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Redirect handles the post-verification callback and redirects the user to the target application. +// +// @Summary Handle Auth Callback and Redirect +// @Description Verifies the temporary email code, ensures the user exists (or creates one), validates the client's redirect URI, and finally performs a 302 redirect with a new authorization code. +// @Tags Authentication +// @Accept x-www-form-urlencoded +// @Produce json +// @Produce html +// @Param client_id query string true "Client Identifier" +// @Param redirect_uri query string true "Target Redirect URI" +// @Param code query string true "Temporary Verification Code" +// @Param state query string false "Opaque state used to maintain state between the request and callback" +// @Success 302 {string} string "Redirect to the provided RedirectUri with a new code" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input / Client Not Found / URI Mismatch" +// @Failure 403 {object} utils.RespStatus{data=nil} "Invalid or Expired Verification Code" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /auth/redirect [get] +func (self *AuthHandler) Redirect(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_auth", + "redirect", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAuthRedirect) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + data := &service_auth.RedirectData{ + ClientId: c.Query("client_id"), + RedirectUri: c.Query("redirect_uri"), + State: c.Query("state"), + Code: c.Query("code"), + } + + if data.ClientId == "" || data.RedirectUri == "" || data.Code == "" { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("Invalid Input")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Redirect(&service_auth.RedirectPayload{ + Context: ctx, + Data: data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + c.Redirect(302, result.Data) +} diff --git a/api/auth/refresh.go b/api/auth/refresh.go new file mode 100644 index 0000000..3a9c6e8 --- /dev/null +++ b/api/auth/refresh.go @@ -0,0 +1,61 @@ +package auth + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_auth" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Refresh handles the token rotation process. +// +// @Summary Refresh Access Token +// @Description Accepts a valid refresh token to issue a new access token and a rotated refresh token. +// @Tags Authentication +// @Accept json +// @Produce json +// @Param payload body service_auth.RefreshData true "Refresh Token Body" +// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful rotation" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Invalid Refresh Token" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /auth/refresh [post] +func (self *AuthHandler) Refresh(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_auth", + "refresh", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAuthRefresh) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + var refreshData service_auth.RefreshData + + if err := c.ShouldBindJSON(&refreshData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Refresh(&service_auth.RefreshPayload{ + Context: ctx, + Data: &refreshData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/auth/token.go b/api/auth/token.go new file mode 100644 index 0000000..48f7de1 --- /dev/null +++ b/api/auth/token.go @@ -0,0 +1,61 @@ +package auth + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_auth" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Token exchanges an authorization code for access and refresh tokens. +// +// @Summary Exchange Code for Token +// @Description Verifies the provided authorization code and issues a pair of JWT tokens (Access and Refresh). +// @Tags Authentication +// @Accept json +// @Produce json +// @Param payload body service_auth.TokenData true "Token Request Body" +// @Success 200 {object} utils.RespStatus{data=service_auth.TokenResponse} "Successful token issuance" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Invalid or Expired Code" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /auth/token [post] +func (self *AuthHandler) Token(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_auth", + "token", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointAuthToken) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + var tokenData service_auth.TokenData + + if err := c.ShouldBindJSON(&tokenData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Token(&service_auth.TokenPayload{ + Context: ctx, + Data: &tokenData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/attendance.go b/api/event/attendance.go new file mode 100644 index 0000000..49ab3ff --- /dev/null +++ b/api/event/attendance.go @@ -0,0 +1,110 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// AttendanceList handles the retrieval of the paginated attendance list for a specific event. +// +// @Summary Get Attendance List +// @Description Retrieves the paginated list of attendees with optional filters. Only accessible by the event owner (Manager). Supports name substring search and KYC status filtering. +// @Tags Event +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event UUID" +// @Param name query string false "Substring filter on attendee nickname" +// @Param kyc_status query string false "KYC filter: 'with_kyc' or 'without_kyc'" +// @Param limit query int false "Maximum number of results to return (default 20)" +// @Param offset query int false "Number of results to skip (default 0)" +// @Param sort_by query string false "Sort field: 'checkin_at' (default) or 'id'" +// @Param sort_order query string false "Sort direction: 'asc' or 'desc' (default)" +// @Success 200 {object} utils.RespStatus{data=[]service_event.AttendanceListResponse} "Successful retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Not Event Owner" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/attendance [get] +func (self *EventHandler) Attendance(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "attendance", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventAttendance) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + eventIdStr := c.Query("event_id") + eventId, err := uuid.Parse(eventIdStr) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + limit := c.Query("limit") + offset := c.Query("offset") + sortBy := c.Query("sort_by") + sortOrder := c.Query("sort_order") + + listData := service_event.AttendanceListData{ + EventId: eventId, + Name: c.Query("name"), + KycStatus: c.Query("kyc_status"), + Limit: &limit, + Offset: &offset, + SortBy: &sortBy, + SortOrder: &sortOrder, + } + + result := self.svc.AttendanceList(&service_event.AttendanceListPayload{ + Context: ctx, + UserId: userId, + Data: &listData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/checkin.go b/api/event/checkin.go new file mode 100644 index 0000000..b469979 --- /dev/null +++ b/api/event/checkin.go @@ -0,0 +1,190 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Checkin generates a check-in code for a specific event. +// +// @Summary Generate Check-in Code +// @Description Creates a temporary check-in code for the authenticated user and event. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=service_event.CheckinResponse} "Successfully generated code" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/checkin [get] +func (self *EventHandler) Checkin(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "checkin", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventCheckin) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + eventIdOrig := c.Query("event_id") + eventId, err := uuid.Parse(eventIdOrig) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Checkin(&service_event.CheckinPayload{ + Context: ctx, + UserId: userId, + Data: &service_event.CheckinData{EventId: eventId}, + }) + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} + +// CheckinSubmit validates a check-in code to complete attendance. +// +// @Summary Submit Check-in Code +// @Description Submits the generated code to mark the user as attended. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param payload body service_event.CheckinSubmitData true "Checkin Code Data" +// @Success 200 {object} utils.RespStatus{data=nil} "Attendance marked successfully" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Code or Input" +// @Router /event/checkin/submit [post] +func (self *EventHandler) CheckinSubmit(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "checkin_submit", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventCheckinSubmit) + + var data service_event.CheckinSubmitData + if err := c.ShouldBindJSON(&data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.CheckinSubmit(&service_event.CheckinSubmitPayload{ + Context: ctx, + Data: &data, + }) + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} + +// CheckinQuery retrieves the check-in status of a user for an event. +// +// @Summary Query Check-in Status +// @Description Returns the timestamp of when the user checked in, or null if not yet checked in. +// @Tags Event +// @Accept json +// @Produce json +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=service_event.CheckinQueryResponse} "Current attendance status" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 404 {object} utils.RespStatus{data=nil} "Record Not Found" +// @Router /event/checkin/query [get] +func (self *EventHandler) CheckinQuery(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "checkin_query", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventCheckinQuery) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + eventIdOrig := c.Query("event_id") + eventId, err := uuid.Parse(eventIdOrig) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.CheckinQuery(&service_event.CheckinQueryPayload{ + Context: ctx, + UserId: userId, + Data: &service_event.CheckinQueryData{EventId: eventId}, + }) + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/create.go b/api/event/create.go new file mode 100644 index 0000000..99a8f8d --- /dev/null +++ b/api/event/create.go @@ -0,0 +1,91 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Create handles the request to create a new event. +// +// @Summary Create an Event +// @Description Allows a Lv30+ user to create a new event. Users at exactly Lv30 may only create events with type 'party'. Sets type and enable_kyc, which are immutable after creation. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param request body service_event.EventCreateData true "Event Creation Details" +// @Success 200 {object} utils.RespStatus{data=service_event.EventCreateResponse} "Successfully created the event" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Permission Denied / Type Not Allowed for this level" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / Database Error" +// @Router /event/create [post] +func (self *EventHandler) Create(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "create", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventCreate) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var createData service_event.EventCreateData + if err := c.ShouldBindJSON(&createData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + createData.UserId = userIdOrig.(string) + createData.PermissionLevel = permissionLevelOrig.(uint) + + payload := &service_event.EventCreatePayload{ + Context: ctx, + Data: &createData, + } + + result := self.svc.Create(payload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/delete.go b/api/event/delete.go new file mode 100644 index 0000000..e95f746 --- /dev/null +++ b/api/event/delete.go @@ -0,0 +1,74 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Delete removes an event by event_id. +// +// @Summary Delete an Event +// @Description Permanently deletes an event. Requires Lv40+. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param request body service_event.EventDeleteData true "Event to delete" +// @Success 200 {object} utils.RespStatus{data=nil} "Successfully deleted" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/delete [delete] +func (self *EventHandler) Delete(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "delete", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventDelete) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + _, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var deleteData service_event.EventDeleteData + if err := c.ShouldBindJSON(&deleteData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.Delete(&service_event.EventDeletePayload{ + Context: ctx, + Data: &deleteData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/event/event_handler_test.go b/api/event/event_handler_test.go new file mode 100644 index 0000000..65b602f --- /dev/null +++ b/api/event/event_handler_test.go @@ -0,0 +1,608 @@ +package event + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/data" + "nixcn-cms/internal/authtoken" + "nixcn-cms/service/service_event" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func issueToken(t *testing.T, userId uuid.UUID) string { + t.Helper() + tok := &authtoken.Token{Application: viper.GetString("server.application")} + access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId) + require.NoError(t, err) + return access +} + +func newEventRouter(t *testing.T) *gin.Engine { + t.Helper() + r := gin.New() + ApiHandler(r.Group("/event")) + return r +} + +func postJSON(t *testing.T, r *gin.Engine, path string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func getRequest(t *testing.T, r *gin.Engine, path string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func patchJSON(t *testing.T, r *gin.Engine, path string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func deleteReq(t *testing.T, r *gin.Engine, path string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodDelete, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func postWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func getWithBearer(t *testing.T, r *gin.Engine, path, token string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func patchWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func deleteWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodDelete, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +// ---- Create ---- + +func TestEventCreateHandler(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "official", + Name: "Handler Test Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + data, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.NotEmpty(t, data["event_id"]) +} + +func TestEventCreateHandlerMissingAuth(t *testing.T) { + testutil.Setup(t) + r := newEventRouter(t) + + w := postJSON(t, r, "/event/create", map[string]any{"type": "party"}) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestEventCreateHandlerInvalidJSON(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, owner.UserId) + r := newEventRouter(t) + + req := httptest.NewRequest(http.MethodPost, "/event/create", bytes.NewBufferString("{bad json")) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Info ---- + +func TestEventInfoHandlerNotFound(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/info?event_id=00000000-0000-0000-0000-000000000001", token) + assert.Equal(t, http.StatusNotFound, w.Code) +} + +// ---- List ---- + +func TestEventListHandlerRequiresOffset(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/list", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestEventListHandlerWithOffset(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/list?offset=0&limit=10", token) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- Join ---- + +func TestEventJoinHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + require.NoError(t, new(data.User).PatchByUserId(t.Context(), user.UserId, data.WithNickname("Joiner"))) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := postWithBearer(t, r, "/event/join", token, map[string]any{"event_id": "not-a-uuid"}) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Delete ---- + +func TestEventDeleteHandlerNotFound(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + nonExistentId := uuid.New().String() + w := deleteWithBearer(t, r, "/event/delete", token, map[string]any{ + "event_id": nonExistentId, + }) + assert.Equal(t, http.StatusNotFound, w.Code) +} + +func TestEventDeleteHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, owner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "party", + Name: "Delete Me", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + w := deleteWithBearer(t, r, "/event/delete", token, map[string]any{"event_id": eventId}) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- Info (success) ---- + +func TestEventInfoHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + ownerToken := issueToken(t, owner.UserId) + userToken := issueToken(t, user.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", ownerToken, service_event.EventCreateData{ + Type: "party", + Name: "Info Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + w := getWithBearer(t, r, "/event/info?event_id="+eventId, userToken) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + d, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.Equal(t, eventId, d["event_id"]) +} + +// ---- Join (success) ---- + +func TestEventJoinHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + joiner := testutil.SeedUser(t, testutil.RandomEmail(), 10) + require.NoError(t, new(data.User).PatchByUserId(t.Context(), joiner.UserId, data.WithNickname("Joiner"))) + + ownerToken := issueToken(t, owner.UserId) + joinerToken := issueToken(t, joiner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", ownerToken, service_event.EventCreateData{ + Type: "party", + Name: "Join Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + w := postWithBearer(t, r, "/event/join", joinerToken, map[string]any{"event_id": eventId}) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- Update ---- + +func TestEventUpdateHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, owner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "party", + Name: "Original Name", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + newName := "Updated Name" + w := patchWithBearer(t, r, "/event/update", token, map[string]any{ + "event_id": eventId, + "name": newName, + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +func TestEventUpdateHandlerInvalidJSON(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + req := httptest.NewRequest(http.MethodPatch, "/event/update", bytes.NewBufferString("{bad")) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Stats ---- + +func TestEventStatsHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, owner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "party", + Name: "Stats Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + w := getWithBearer(t, r, "/event/stats?event_id="+eventId, token) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + d, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.NotNil(t, d["join_count"]) +} + +func TestEventStatsHandlerMissingEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/stats?event_id=not-a-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Checkin ---- + +func TestEventCheckinHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/checkin?event_id=not-a-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestEventCheckinHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + joiner := testutil.SeedUser(t, testutil.RandomEmail(), 10) + require.NoError(t, new(data.User).PatchByUserId(t.Context(), joiner.UserId, data.WithNickname("Joiner"))) + + ownerToken := issueToken(t, owner.UserId) + joinerToken := issueToken(t, joiner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", ownerToken, service_event.EventCreateData{ + Type: "party", + Name: "Checkin Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + joinW := postWithBearer(t, r, "/event/join", joinerToken, map[string]any{"event_id": eventId}) + require.Equal(t, http.StatusOK, joinW.Code) + + w := getWithBearer(t, r, "/event/checkin?event_id="+eventId, joinerToken) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + d, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.NotEmpty(t, d["checkin_code"]) +} + +// ---- CheckinSubmit ---- + +func TestEventCheckinSubmitHandlerInvalidCode(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 20) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := postWithBearer(t, r, "/event/checkin/submit", token, service_event.CheckinSubmitData{ + CheckinCode: "000000", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestEventCheckinSubmitHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + joiner := testutil.SeedUser(t, testutil.RandomEmail(), 10) + require.NoError(t, new(data.User).PatchByUserId(t.Context(), joiner.UserId, data.WithNickname("Joiner"))) + + ownerToken := issueToken(t, owner.UserId) + joinerToken := issueToken(t, joiner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", ownerToken, service_event.EventCreateData{ + Type: "party", + Name: "Checkin Submit Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + joinW := postWithBearer(t, r, "/event/join", joinerToken, map[string]any{"event_id": eventId}) + require.Equal(t, http.StatusOK, joinW.Code) + + checkinW := getWithBearer(t, r, "/event/checkin?event_id="+eventId, joinerToken) + require.Equal(t, http.StatusOK, checkinW.Code) + var checkinResp map[string]any + require.NoError(t, json.Unmarshal(checkinW.Body.Bytes(), &checkinResp)) + code := checkinResp["data"].(map[string]any)["checkin_code"].(string) + + w := postWithBearer(t, r, "/event/checkin/submit", ownerToken, service_event.CheckinSubmitData{ + CheckinCode: code, + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- CheckinQuery ---- + +func TestEventCheckinQueryHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/checkin/query?event_id=not-a-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestEventCheckinQueryHandlerNotJoined(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/checkin/query?event_id="+uuid.New().String(), token) + assert.Equal(t, http.StatusNotFound, w.Code) +} + +// ---- Attendance ---- + +func TestEventAttendanceHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := getWithBearer(t, r, "/event/attendance?event_id=not-a-uuid", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestEventAttendanceHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + owner := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, owner.UserId) + r := newEventRouter(t) + + createW := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "party", + Name: "Attendance Event", + Subtitle: "sub", + StartTime: time.Now().Add(24 * time.Hour), + EndTime: time.Now().Add(48 * time.Hour), + Quota: 100, + Limit: 150, + }) + require.Equal(t, http.StatusOK, createW.Code) + var createResp map[string]any + require.NoError(t, json.Unmarshal(createW.Body.Bytes(), &createResp)) + eventId := createResp["data"].(map[string]any)["event_id"].(string) + + w := getWithBearer(t, r, "/event/attendance?event_id="+eventId, token) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + d, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.NotNil(t, d["total"]) +} + +// ---- Guide ---- + +func TestEventGuideHandlerInvalidEventId(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + // The guide handler returns 500 for invalid UUID (source behaviour) + w := getWithBearer(t, r, "/event/guide?event_id=not-a-uuid", token) + assert.NotEqual(t, http.StatusNotFound, w.Code, "route must be registered") +} + +// ---- Permission enforcement ---- + +func TestEventCreateHandlerLowPermission(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := postWithBearer(t, r, "/event/create", token, service_event.EventCreateData{ + Type: "party", + Name: "Should Fail", + Quota: 10, + Limit: 20, + }) + assert.Equal(t, http.StatusForbidden, w.Code) +} + +func TestEventDeleteHandlerLowPermission(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 30) + token := issueToken(t, user.UserId) + r := newEventRouter(t) + + w := deleteWithBearer(t, r, "/event/delete", token, map[string]any{ + "event_id": uuid.New().String(), + }) + assert.Equal(t, http.StatusForbidden, w.Code) +} diff --git a/api/event/guide.go b/api/event/guide.go new file mode 100644 index 0000000..cd60085 --- /dev/null +++ b/api/event/guide.go @@ -0,0 +1,92 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Specific guide about a specific event. +// +// @Summary Get Event Guide +// @Description Fetching attendance guide of an event using its UUID. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=service_event.AttendanceGuideResponse} "Successful retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/guide [get] +func (self *EventHandler) Guide(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "guide", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventAttendanceGuide) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + eventIdOrig := c.Query("event_id") + eventId, err := uuid.Parse(eventIdOrig) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 500, errorCode) + return + } + + result := self.svc.GetAttendanceGuide(&service_event.AttendanceGuidePayload{ + Context: ctx, + UserId: userId, + Data: &service_event.AttendanceGuideData{ + EventId: eventId, + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/handler.go b/api/event/handler.go index 8e182c5..525ab32 100644 --- a/api/event/handler.go +++ b/api/event/handler.go @@ -2,10 +2,44 @@ package event import ( "nixcn-cms/middleware" + "nixcn-cms/service/service_event" "github.com/gin-gonic/gin" ) -func ApiHandler(r *gin.RouterGroup) { - r.Use(middleware.ApiVersionCheck(), middleware.JWTAuth(), middleware.Permission(10)) +type EventHandler struct { + svc service_event.EventService +} + +func ApiHandler(r *gin.RouterGroup) { + eventSvc := service_event.NewEventService() + eventHandler := &EventHandler{eventSvc} + + // Lv10+ routes + lv10 := r.Group("") + lv10.Use(middleware.JWTAuth(), middleware.Permission(10)) + lv10.GET("/info", eventHandler.Info) + lv10.GET("/checkin", eventHandler.Checkin) + lv10.GET("/checkin/query", eventHandler.CheckinQuery) + lv10.POST("/join", eventHandler.Join) + lv10.GET("/guide", eventHandler.Guide) + lv10.GET("/list", eventHandler.List) + + // Lv20+ routes + lv20 := r.Group("") + lv20.Use(middleware.JWTAuth(), middleware.Permission(20)) + lv20.POST("/checkin/submit", eventHandler.CheckinSubmit) + + // Lv30+ routes + lv30 := r.Group("") + lv30.Use(middleware.JWTAuth(), middleware.Permission(30)) + lv30.POST("/create", eventHandler.Create) + lv30.PATCH("/update", eventHandler.Update) + lv30.GET("/attendance", eventHandler.Attendance) + lv30.GET("/stats", eventHandler.Stats) + + // Lv40+ routes + lv40 := r.Group("") + lv40.Use(middleware.JWTAuth(), middleware.Permission(40)) + lv40.DELETE("/delete", eventHandler.Delete) } diff --git a/api/event/info.go b/api/event/info.go new file mode 100644 index 0000000..f6334ff --- /dev/null +++ b/api/event/info.go @@ -0,0 +1,103 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Info retrieves basic information about a specific event. +// +// @Summary Get Event Information +// @Description Fetches the name, start time, and end time of an event using its UUID. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=service_event.EventInfoResponse} "Successful retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/info [get] +func (self *EventHandler) Info(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "info", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventInfo) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + eventIdOrig := c.Query("event_id") + if eventIdOrig == "" { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingEventId), + exception.WithError(errors.New("Missing EventId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + eventId, err := uuid.Parse(eventIdOrig) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + + utils.HttpResponse(c, 500, errorCode) + return + } + + result := self.svc.GetInfo(&service_event.EventInfoPayload{ + Context: ctx, + UserId: userId, + Data: &service_event.EventInfoData{ + EventId: eventId, + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, 200, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/join.go b/api/event/join.go new file mode 100644 index 0000000..0fb5723 --- /dev/null +++ b/api/event/join.go @@ -0,0 +1,78 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Join handles the request for a user to join a specific event. +// +// @Summary Join an Event +// @Description Allows an authenticated user to join an event by providing the event ID. The user's role and state are initialized by the service. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param request body service_event.EventJoinData true "Event Join Details (UserId and EventId are required)" +// @Success 200 {object} utils.RespStatus{data=service_event.EventJoinResponse} "Successfully joined the event" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input or UUID Parse Failed" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized / Missing User ID / Event Limit Exceeded" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / Database Error" +// @Router /event/join [post] +func (self *EventHandler) Join(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "join", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventJoin) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var joinData service_event.EventJoinData + if err := c.ShouldBindJSON(&joinData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + joinData.UserId = userIdOrig.(string) + + payload := &service_event.EventJoinPayload{ + Context: ctx, + Data: &joinData, + } + + result := self.svc.Join(payload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/event/list.go b/api/event/list.go new file mode 100644 index 0000000..9c78f8a --- /dev/null +++ b/api/event/list.go @@ -0,0 +1,118 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// List retrieves a paginated, filterable list of events. +// +// @Summary List Events +// @Description Returns a paginated list of events. Supports filtering by type and sorting. Lv30 users are automatically scoped to events they own. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param limit query int false "Maximum number of events to return (default 20)" +// @Param offset query int true "Number of events to skip" +// @Param type query string false "Filter by event type: 'official' or 'party'" +// @Param sort_by query string false "Sort field: 'start_time' (default), 'end_time', 'name'" +// @Param sort_order query string false "Sort direction: 'asc' or 'desc' (default)" +// @Success 200 {object} utils.RespStatus{data=service_event.EventListResponse} "Successful paginated list retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/list [get] +func (self *EventHandler) List(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "list", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventList) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + type ListQuery struct { + Limit *string `form:"limit"` + Offset *string `form:"offset"` + Type *string `form:"type"` + SortBy *string `form:"sort_by"` + SortOrder *string `form:"sort_order"` + } + + var query ListQuery + if err := c.ShouldBindQuery(&query); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusClient), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.List(&service_event.EventListPayload{ + Context: ctx, + UserId: userId, + Data: &service_event.EventListData{ + Limit: query.Limit, + Offset: query.Offset, + Type: query.Type, + SortBy: query.SortBy, + SortOrder: query.SortOrder, + PermissionLevel: permissionLevelOrig.(uint), + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/stats.go b/api/event/stats.go new file mode 100644 index 0000000..71e4930 --- /dev/null +++ b/api/event/stats.go @@ -0,0 +1,78 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Stats returns aggregate statistics for an event. +// +// @Summary Get Event Statistics +// @Description Returns join count, checkin count, KYC pass rate, and agenda submission count. Only accessible by the event owner (Manager). +// @Tags Event +// @Produce json +// @Security Bearer +// @Param event_id query string true "Event UUID" +// @Success 200 {object} utils.RespStatus{data=service_event.EventStatsResponse} "Statistics retrieved successfully" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Not Event Owner" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/stats [get] +func (self *EventHandler) Stats(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "stats", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventStats) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userId, err := uuid.Parse(userIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + result := self.svc.Stats(&service_event.EventStatsPayload{ + Context: ctx, + UserId: userId, + Data: &service_event.EventStatsData{ + EventId: c.Query("event_id"), + }, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/event/update.go b/api/event/update.go new file mode 100644 index 0000000..83ebfb8 --- /dev/null +++ b/api/event/update.go @@ -0,0 +1,90 @@ +package event + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_event" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Update modifies editable fields of an event owned by the requesting user. +// +// @Summary Update an Event +// @Description Allows the event owner (Manager) to update name, subtitle, description, start_time, end_time, thumbnail, and is_agenda_published. Lv40+ users (admins) bypass the owner restriction and may update any event. Changes to type or enable_kyc are rejected. is_agenda_published is write-once: it can only be set to true (requires at least one agenda submission) and cannot be reverted. +// @Tags Event +// @Accept json +// @Produce json +// @Security Bearer +// @Param request body service_event.EventUpdateData true "Fields to update (all optional except event_id)" +// @Success 200 {object} utils.RespStatus{data=nil} "Successfully updated" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input / Immutable Field / Agenda Pre-flight Failed" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 403 {object} utils.RespStatus{data=nil} "Not Event Owner" +// @Failure 404 {object} utils.RespStatus{data=nil} "Event Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /event/update [patch] +func (self *EventHandler) Update(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_event", + "update", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointEventUpdate) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var updateData service_event.EventUpdateData + if err := c.ShouldBindJSON(&updateData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + updateData.UserId = userIdOrig.(string) + updateData.PermissionLevel = permissionLevelOrig.(uint) + + result := self.svc.Update(&service_event.EventUpdatePayload{ + Context: ctx, + Data: &updateData, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/handler.go b/api/handler.go index 883fca7..bead84a 100644 --- a/api/handler.go +++ b/api/handler.go @@ -1,9 +1,11 @@ package api import ( + "nixcn-cms/api/agenda" "nixcn-cms/api/auth" "nixcn-cms/api/event" "nixcn-cms/api/kyc" + "nixcn-cms/api/stats" "nixcn-cms/api/user" "github.com/gin-gonic/gin" @@ -14,4 +16,6 @@ func Handler(r *gin.RouterGroup) { user.ApiHandler(r.Group("/user")) event.ApiHandler(r.Group("/event")) kyc.ApiHandler(r.Group("/kyc")) + agenda.ApiHandler(r.Group("/agenda")) + stats.ApiHandler(r.Group("/stats")) } diff --git a/api/kyc/handler.go b/api/kyc/handler.go index 452c43d..9358235 100644 --- a/api/kyc/handler.go +++ b/api/kyc/handler.go @@ -2,10 +2,20 @@ package kyc import ( "nixcn-cms/middleware" + "nixcn-cms/service/service_kyc" "github.com/gin-gonic/gin" ) -func ApiHandler(r *gin.RouterGroup) { - r.Use(middleware.ApiVersionCheck(), middleware.JWTAuth(), middleware.Permission(10)) +type KycHandler struct { + svc service_kyc.KycService +} + +func ApiHandler(r *gin.RouterGroup) { + kycSvc := service_kyc.NewKycService() + kycHandler := &KycHandler{kycSvc} + + r.Use(middleware.JWTAuth(), middleware.Permission(10)) + r.POST("/session", kycHandler.Session) + r.POST("/query", kycHandler.Query) } diff --git a/api/kyc/kyc_handler_test.go b/api/kyc/kyc_handler_test.go new file mode 100644 index 0000000..a93f391 --- /dev/null +++ b/api/kyc/kyc_handler_test.go @@ -0,0 +1,132 @@ +package kyc + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/internal/authtoken" + "nixcn-cms/service/service_kyc" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func issueToken(t *testing.T, userId uuid.UUID) string { + t.Helper() + tok := &authtoken.Token{Application: viper.GetString("server.application")} + access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId) + require.NoError(t, err) + return access +} + +func newKycRouter(t *testing.T) *gin.Engine { + t.Helper() + r := gin.New() + ApiHandler(r.Group("/kyc")) + return r +} + +func postWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +// ---- Session ---- + +func TestKycSessionHandlerNoAuth(t *testing.T) { + testutil.Setup(t) + r := newKycRouter(t) + + w := postWithBearer(t, r, "/kyc/session", "", map[string]any{ + "type": "cnrid", + "identity": "dGVzdA==", + }) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestKycSessionHandlerInvalidJSON(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newKycRouter(t) + + req := httptest.NewRequest(http.MethodPost, "/kyc/session", bytes.NewBufferString("{bad")) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestKycSessionHandlerInvalidBase64Identity(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newKycRouter(t) + + w := postWithBearer(t, r, "/kyc/session", token, service_kyc.KycSessionData{ + Type: "cnrid", + Identity: "!!!not-base64!!!", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestKycSessionHandlerInvalidType(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newKycRouter(t) + + validB64 := base64.StdEncoding.EncodeToString([]byte(`{}`)) + w := postWithBearer(t, r, "/kyc/session", token, service_kyc.KycSessionData{ + Type: "unknown_type", + Identity: validB64, + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +// ---- Query ---- + +func TestKycQueryHandlerNoAuth(t *testing.T) { + testutil.Setup(t) + r := newKycRouter(t) + + w := postWithBearer(t, r, "/kyc/query", "", map[string]any{ + "kyc_id": "00000000-0000-0000-0000-000000000001", + }) + assert.Equal(t, http.StatusUnauthorized, w.Code) +} + +func TestKycQueryHandlerInvalidJSON(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newKycRouter(t) + + req := httptest.NewRequest(http.MethodPost, "/kyc/query", bytes.NewBufferString("{bad")) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) +} diff --git a/api/kyc/query.go b/api/kyc/query.go new file mode 100644 index 0000000..136a9e9 --- /dev/null +++ b/api/kyc/query.go @@ -0,0 +1,73 @@ +package kyc + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_kyc" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// @Summary Query KYC Status +// @Description Checks the current state of a KYC session and updates local database if approved. +// @Tags KYC +// @Accept json +// @Produce json +// @Security Bearer +// @Param payload body service_kyc.KycQueryData true "KYC query data (KycId)" +// @Success 200 {object} utils.RespStatus{data=service_kyc.KycQueryResponse} "Query processed (success/pending/failed)" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid UUID or input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /kyc/query [post] +func (self *KycHandler) Query(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_kyc", + "query", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointKycQuery) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + _, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var queryData service_kyc.KycQueryData + if err := c.ShouldBindJSON(&queryData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + queryPayload := &service_kyc.KycQueryPayload{ + Context: ctx, + Data: &queryData, + } + + result := self.svc.QueryKyc(queryPayload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/kyc/session.go b/api/kyc/session.go new file mode 100644 index 0000000..b6f3a48 --- /dev/null +++ b/api/kyc/session.go @@ -0,0 +1,75 @@ +package kyc + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_kyc" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// @Summary Create KYC Session +// @Description Initializes a KYC process (CNRid or Passport) and returns the status or redirect URI. +// @Tags KYC +// @Accept json +// @Produce json +// @Security Bearer +// @Param payload body service_kyc.KycSessionData true "KYC session data (Type and Base64 Identity)" +// @Success 200 {object} utils.RespStatus{data=service_kyc.KycSessionResponse} "Session created successfully" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid input or decode failed" +// @Failure 403 {object} utils.RespStatus{data=nil} "Missing User ID" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error / KYC Service Error" +// @Router /kyc/session [post] +func (self *KycHandler) Session(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_kyc", + "session", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointKycSession) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdFromHeaderOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + var sessionData service_kyc.KycSessionData + if err := c.ShouldBindJSON(&sessionData); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + sessionData.UserId = userIdFromHeaderOrig.(string) + + kycPayload := &service_kyc.KycSessionPayload{ + Context: ctx, + Data: &sessionData, + } + + result := self.svc.SessionKyc(kycPayload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/stats/global.go b/api/stats/global.go new file mode 100644 index 0000000..2167f6f --- /dev/null +++ b/api/stats/global.go @@ -0,0 +1,44 @@ +package stats + +import ( + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_stats" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" +) + +// Global returns platform-wide statistics. Lv40+ only. +// +// @Summary Global Stats +// @Description Returns total users, user counts per permission_level, and per-event join/checkin counts. +// @Tags Stats +// @Produce json +// @Security Bearer +// @Success 200 {object} utils.RespStatus{data=service_stats.GlobalStatsResponse} +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /stats/global [get] +func (self *StatsHandler) Global(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_stats", + "global", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointStatsGlobal) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + result := self.svc.Global(&service_stats.GlobalStatsPayload{ + Context: ctx, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/stats/handler.go b/api/stats/handler.go new file mode 100644 index 0000000..ce2e70c --- /dev/null +++ b/api/stats/handler.go @@ -0,0 +1,22 @@ +package stats + +import ( + "nixcn-cms/middleware" + "nixcn-cms/service/service_stats" + + "github.com/gin-gonic/gin" +) + +type StatsHandler struct { + svc service_stats.StatsService +} + +func ApiHandler(r *gin.RouterGroup) { + statsSvc := service_stats.NewStatsService() + statsHandler := &StatsHandler{statsSvc} + + // Lv40+ routes + lv40 := r.Group("") + lv40.Use(middleware.JWTAuth(), middleware.Permission(40)) + lv40.GET("/global", statsHandler.Global) +} diff --git a/api/stats/stats_handler_test.go b/api/stats/stats_handler_test.go new file mode 100644 index 0000000..e330679 --- /dev/null +++ b/api/stats/stats_handler_test.go @@ -0,0 +1,66 @@ +package stats + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/internal/authtoken" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func issueToken(t *testing.T, userId uuid.UUID) string { + t.Helper() + tok := &authtoken.Token{Application: viper.GetString("server.application")} + access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId) + require.NoError(t, err) + return access +} + +func newStatsRouter(t *testing.T) *gin.Engine { + t.Helper() + r := gin.New() + ApiHandler(r.Group("/stats")) + return r +} + +func TestGlobalStatsHandler(t *testing.T) { + testutil.SetupWithAuth(t) + admin := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, admin.UserId) + r := newStatsRouter(t) + + req := httptest.NewRequest(http.MethodGet, "/stats/global", nil) + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + data, ok := resp["data"].(map[string]any) + require.True(t, ok) + _, hasTotalUsers := data["total_users"] + assert.True(t, hasTotalUsers) +} + +func TestGlobalStatsHandlerNoAuth(t *testing.T) { + testutil.Setup(t) + r := newStatsRouter(t) + + req := httptest.NewRequest(http.MethodGet, "/stats/global", nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + + assert.Equal(t, http.StatusUnauthorized, w.Code) +} diff --git a/api/user/admin_update.go b/api/user/admin_update.go new file mode 100644 index 0000000..cf3aa9a --- /dev/null +++ b/api/user/admin_update.go @@ -0,0 +1,115 @@ +package user + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_user" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// AdminUpdate modifies another user's profile. Lv40+ only. +// +// @Summary Admin Update User +// @Description Lv40+ operators may update any user with a strictly lower permission_level. Editable fields: all profile fields plus permission_level (new value must be below operator's own level). +// @Tags User +// @Accept json +// @Produce json +// @Security Bearer +// @Param user_id path string true "Target User ID" +// @Param payload body service_user.UserInfoUpdateData true "Fields to update" +// @Success 200 {object} utils.RespStatus{data=nil} +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 403 {object} utils.RespStatus{data=nil} "Permission Matrix Violation" +// @Failure 404 {object} utils.RespStatus{data=nil} "Target User Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /user/update/{user_id} [patch] +func (self *UserHandler) AdminUpdate(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_user", + "admin_update", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointUserAdminUpdate) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + operatorIdOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + operatorId, err := uuid.Parse(operatorIdOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + targetId, err := uuid.Parse(c.Param("user_id")) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(errors.New("invalid user_id")), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + var data service_user.UserInfoData + if err := c.ShouldBindJSON(&data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + + result := self.svc.UpdateInfo(&service_user.UserInfoPayload{ + Context: ctx, + UserId: targetId, + OperatorId: operatorId, + OperatorLevel: permissionLevelOrig.(uint), + Data: &data, + }) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) +} diff --git a/api/user/create.go b/api/user/create.go deleted file mode 100644 index dafe823..0000000 --- a/api/user/create.go +++ /dev/null @@ -1,6 +0,0 @@ -package user - -import "github.com/gin-gonic/gin" - -func (self *UserHandler) Create(c *gin.Context) { -} diff --git a/api/user/full.go b/api/user/full.go deleted file mode 100644 index 5c434af..0000000 --- a/api/user/full.go +++ /dev/null @@ -1,24 +0,0 @@ -package user - -import ( - "nixcn-cms/internal/exception" - "nixcn-cms/service" - "nixcn-cms/utils" - - "github.com/gin-gonic/gin" -) - -func (self *UserHandler) Full(c *gin.Context) { - userTablePayload := &service.UserTablePayload{ - Context: c, - } - - result := self.svc.GetUserFullTable(userTablePayload) - - if result.Common.Exception.Original != exception.CommonSuccess { - utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) - return - } - - utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) -} diff --git a/api/user/handler.go b/api/user/handler.go index 1d2ac0f..ccfdac9 100644 --- a/api/user/handler.go +++ b/api/user/handler.go @@ -2,23 +2,29 @@ package user import ( "nixcn-cms/middleware" - "nixcn-cms/service" + "nixcn-cms/service/service_user" "github.com/gin-gonic/gin" ) type UserHandler struct { - svc service.UserService + svc service_user.UserService } func ApiHandler(r *gin.RouterGroup) { - userSvc := service.NewUserService() + userSvc := service_user.NewUserService() userHandler := &UserHandler{userSvc} - r.Use(middleware.ApiVersionCheck(), middleware.JWTAuth(), middleware.Permission(5)) - r.GET("/info", userHandler.Info) - r.PATCH("/update", userHandler.Update) - r.GET("/list", middleware.Permission(20), userHandler.List) - r.POST("/full", middleware.Permission(40), userHandler.Full) - r.POST("/create", middleware.Permission(50), userHandler.Create) + // Lv5+ routes + lv5 := r.Group("") + lv5.Use(middleware.JWTAuth(), middleware.Permission(5)) + lv5.GET("/info", userHandler.Info) + lv5.GET("/info/:user_id", userHandler.Other) + lv5.PATCH("/update", userHandler.Update) + + // Lv40+ routes + lv40 := r.Group("") + lv40.Use(middleware.JWTAuth(), middleware.Permission(40)) + lv40.GET("/list", userHandler.List) + lv40.PATCH("/update/:user_id", userHandler.AdminUpdate) } diff --git a/api/user/info.go b/api/user/info.go index 2e506e8..461f5f5 100644 --- a/api/user/info.go +++ b/api/user/info.go @@ -1,51 +1,72 @@ package user import ( + "errors" "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" + "nixcn-cms/tracer" "nixcn-cms/utils" "github.com/gin-gonic/gin" "github.com/google/uuid" ) +// Info retrieves the profile information of the currently authenticated user. +// +// @Summary Get My User Information +// @Description Fetches the complete profile data for the user associated with the provided session/token. +// @Tags User +// @Accept json +// @Produce json +// @Security Bearer +// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" +// @Router /user/info [get] func (self *UserHandler) Info(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_user", + "info", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointUserInfo) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + userIdOrig, ok := c.Get("user_id") if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceInfo). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorMissingUserId). - Throw(c). - String() + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() utils.HttpResponse(c, 403, errorCode) return } userId, err := uuid.Parse(userIdOrig.(string)) if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceInfo). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - SetError(err). - Throw(c). - String() + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() utils.HttpResponse(c, 500, errorCode) return } - UserInfoPayload := &service.UserInfoPayload{ - Context: c, + UserInfoPayload := &service_user.UserInfoPayload{ + Context: ctx, UserId: userId, + IsOther: false, Data: nil, } - result := self.svc.GetUserInfo(UserInfoPayload) + result := self.svc.GetInfo(UserInfoPayload) if result.Common.Exception.Original != exception.CommonSuccess { utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) diff --git a/api/user/list.go b/api/user/list.go index 0c4eeee..4388e9f 100644 --- a/api/user/list.go +++ b/api/user/list.go @@ -2,45 +2,98 @@ package user import ( "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" + "nixcn-cms/tracer" "nixcn-cms/utils" + "strconv" "github.com/gin-gonic/gin" ) +// List retrieves a paginated, filterable list of users. Lv40+ only. +// +// @Summary List Users (Admin) +// @Description Returns a paginated list of users with permission_level included. Supports filtering by permission_level and sorting. +// @Tags User +// @Accept json +// @Produce json +// @Security Bearer +// @Param limit query string false "Maximum number of users to return (default 20)" +// @Param offset query string true "Number of users to skip" +// @Param sort_by query string false "Sort field: 'id' (default) | 'permission_level'" +// @Param sort_order query string false "Sort direction: 'asc' (default) | 'desc'" +// @Param permission_level query int false "Filter by exact permission level" +// @Success 200 {object} utils.RespStatus{data=[]service_user.UserListResponse} "Successful paginated list retrieval" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /user/list [get] func (self *UserHandler) List(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_user", + "list", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointUserList) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + type ListQuery struct { - Limit *string `form:"limit"` - Offset *string `form:"offset"` + Limit *string `form:"limit"` + Offset *string `form:"offset"` + SortBy *string `form:"sort_by"` + SortOrder *string `form:"sort_order"` + PermissionLevel *string `form:"permission_level"` } var query ListQuery if err := c.ShouldBindQuery(&query); err != nil { - exception := new(exception.Builder). - SetStatus(exception.StatusClient). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceList). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - Throw(c). - String() - - utils.HttpResponse(c, 400, exception) + errorCode := exception.New( + exception.WithStatus(exception.StatusClient), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) return } - userListPayload := &service.UserListPayload{ - Context: c, - Limit: query.Limit, - Offset: query.Offset, + var permLevel *uint + if query.PermissionLevel != nil && *query.PermissionLevel != "" { + v, err := strconv.ParseUint(*query.PermissionLevel, 10, 64) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 400, errorCode) + return + } + u := uint(v) + permLevel = &u } - result := self.svc.ListUsers(userListPayload) + result := self.svc.List(&service_user.UserListPayload{ + Context: ctx, + Data: &service_user.UserListData{ + Limit: query.Limit, + Offset: query.Offset, + SortBy: query.SortBy, + SortOrder: query.SortOrder, + PermissionLevel: permLevel, + }, + }) if result.Common.Exception.Original != exception.CommonSuccess { utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) return } - utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), gin.H{ + "total": result.Total, + "items": result.Data, + }) } diff --git a/api/user/other.go b/api/user/other.go new file mode 100644 index 0000000..adfef06 --- /dev/null +++ b/api/user/other.go @@ -0,0 +1,103 @@ +package user + +import ( + "errors" + "nixcn-cms/internal/exception" + "nixcn-cms/service/service_user" + "nixcn-cms/tracer" + "nixcn-cms/utils" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" +) + +// Info retrieves the profile information of the other user. +// +// @Summary Get Other User Information +// @Description Fetches the complete profile data for the user associated with the provided session/token. +// @Tags User +// @Accept json +// @Produce json +// @Security Bearer +// @Param user_id path string true "Other user id" +// @Success 200 {object} utils.RespStatus{data=service_user.UserInfoData} "Successful profile retrieval" +// @Failure 401 {object} utils.RespStatus{data=nil} "Missing User ID / Unauthorized" +// @Failure 404 {object} utils.RespStatus{data=nil} "User Not Found" +// @Failure 403 {object} utils.RespStatus{data=nil} "User Not Public" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error (UUID Parse Failed)" +// @Router /user/info/{user_id} [get] +func (self *UserHandler) Other(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_user", + "other", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointUserInfo) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + + userIdFromUrlOrig := c.Param("user_id") + + userIdFromUrl, err := uuid.Parse(userIdFromUrlOrig) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + userIdFromHeaderOrig, ok := c.Get("user_id") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return + } + + userIdFromHeader, err := uuid.Parse(userIdFromHeaderOrig.(string)) + if err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() + utils.HttpResponse(c, 500, errorCode) + return + } + + var UserInfoPayload = &service_user.UserInfoPayload{} + if userIdFromUrl == userIdFromHeader { + UserInfoPayload = &service_user.UserInfoPayload{ + Context: ctx, + UserId: userIdFromHeader, + IsOther: false, + Data: nil, + } + } else if userIdFromUrl != userIdFromHeader { + UserInfoPayload = &service_user.UserInfoPayload{ + Context: ctx, + UserId: userIdFromUrl, + IsOther: true, + Data: nil, + } + } + + result := self.svc.GetInfo(UserInfoPayload) + + if result.Common.Exception.Original != exception.CommonSuccess { + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) + return + } + + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) +} diff --git a/api/user/update.go b/api/user/update.go index 18ab94a..4927751 100644 --- a/api/user/update.go +++ b/api/user/update.go @@ -1,69 +1,102 @@ package user import ( + "errors" "nixcn-cms/internal/exception" - "nixcn-cms/service" + "nixcn-cms/service/service_user" + "nixcn-cms/tracer" "nixcn-cms/utils" "github.com/gin-gonic/gin" "github.com/google/uuid" ) +// Update modifies the profile information for the currently authenticated user. +// +// @Summary Update User Information +// @Description Updates specific profile fields such as username, nickname, subtitle, avatar (URL), and bio (Base64). +// @Description Validation: Username (5-255 chars), Nickname (max 24 chars), Subtitle (max 32 chars). +// @Tags User +// @Accept json +// @Produce json +// @Security Bearer +// @Param payload body service_user.UserInfoUpdateData true "Updated User Profile Data" +// @Success 200 {object} utils.RespStatus{data=nil} "Successful profile update" +// @Failure 400 {object} utils.RespStatus{data=nil} "Invalid Input" +// @Failure 401 {object} utils.RespStatus{data=nil} "Unauthorized" +// @Failure 500 {object} utils.RespStatus{data=nil} "Internal Server Error" +// @Router /user/update [patch] func (self *UserHandler) Update(c *gin.Context) { + ctx, span := tracer.StartSpan( + c.Request.Context(), + "api_user", + "update", + ) + defer span.End() + + ctx = exception.ContextWithEndpoint(ctx, exception.EndpointUserUpdate) + ctx = exception.ContextWithService(ctx, exception.ServiceEndpoint) + userIdOrig, ok := c.Get("user_id") if !ok { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceUpdate). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorMissingUserId). - Throw(c). - String() + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorMissingUserId), + exception.WithError(errors.New("Missing UserId")), + ).Throw(ctx).String() utils.HttpResponse(c, 403, errorCode) return } userId, err := uuid.Parse(userIdOrig.(string)) if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusServer). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceUpdate). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorUuidParseFailed). - Throw(c). - String() + errorCode := exception.New( + exception.WithStatus(exception.StatusServer), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorUuidParseFailed), + exception.WithError(err), + ).Throw(ctx).String() utils.HttpResponse(c, 500, errorCode) return } - userInfoPayload := &service.UserInfoPayload{ - Context: c, - UserId: userId, + permissionLevelOrig, ok := c.Get("permission_level") + if !ok { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorPermissionDenied), + exception.WithError(errors.New("Missing PermissionLevel")), + ).Throw(ctx).String() + utils.HttpResponse(c, 403, errorCode) + return } - err = c.ShouldBindJSON(&userInfoPayload.Data) - if err != nil { - errorCode := new(exception.Builder). - SetStatus(exception.StatusUser). - SetService(exception.ServiceUser). - SetEndpoint(exception.EndpointUserServiceUpdate). - SetType(exception.TypeCommon). - SetOriginal(exception.CommonErrorInvalidInput). - SetError(err). - Throw(c). - String() + payload := &service_user.UserInfoPayload{ + Context: ctx, + UserId: userId, + OperatorId: userId, + OperatorLevel: permissionLevelOrig.(uint), + } + + if err := c.ShouldBindJSON(&payload.Data); err != nil { + errorCode := exception.New( + exception.WithStatus(exception.StatusUser), + exception.WithType(exception.TypeCommon), + exception.WithOriginal(exception.CommonErrorInvalidInput), + exception.WithError(err), + ).Throw(ctx).String() utils.HttpResponse(c, 400, errorCode) return } - result := self.svc.UpdateUserInfo(userInfoPayload) + result := self.svc.UpdateInfo(payload) if result.Common.Exception.Original != exception.CommonSuccess { utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) return } - utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String(), result.Data) + utils.HttpResponse(c, result.Common.HttpCode, result.Common.Exception.String()) } diff --git a/api/user/user_handler_test.go b/api/user/user_handler_test.go new file mode 100644 index 0000000..9f6a740 --- /dev/null +++ b/api/user/user_handler_test.go @@ -0,0 +1,227 @@ +package user + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "nixcn-cms/data" + "nixcn-cms/internal/authtoken" + "nixcn-cms/testutil" +) + +func init() { gin.SetMode(gin.TestMode) } + +func issueToken(t *testing.T, userId uuid.UUID) string { + t.Helper() + tok := &authtoken.Token{Application: viper.GetString("server.application")} + access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId) + require.NoError(t, err) + return access +} + +func newUserRouter(t *testing.T) *gin.Engine { + t.Helper() + r := gin.New() + ApiHandler(r.Group("/user")) + return r +} + +func getWithBearer(t *testing.T, r *gin.Engine, path, token string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func patchWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+token) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func patchJSON(t *testing.T, r *gin.Engine, path string, body any) *httptest.ResponseRecorder { + t.Helper() + b, _ := json.Marshal(body) + req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +func getRequest(t *testing.T, r *gin.Engine, path string) *httptest.ResponseRecorder { + t.Helper() + req := httptest.NewRequest(http.MethodGet, path, nil) + w := httptest.NewRecorder() + r.ServeHTTP(w, req) + return w +} + +// ---- Info ---- + +func TestUserInfoHandlerSelf(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, "selfinfo@example.com", 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/info", token) + assert.Equal(t, http.StatusOK, w.Code) + + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + data, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.Equal(t, "selfinfo@example.com", data["email"]) +} + +func TestUserInfoHandlerOtherNotFound(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, "caller@example.com", 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/info/00000000-0000-0000-0000-000000000099", token) + assert.Equal(t, http.StatusNotFound, w.Code) +} + +// ---- Update ---- + +func TestUserUpdateHandlerEmptyNickname(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, "update@example.com", 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := patchWithBearer(t, r, "/user/update", token, map[string]any{ + "nickname": "", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestUserUpdateHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, "update2@example.com", 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := patchWithBearer(t, r, "/user/update", token, map[string]any{ + "nickname": "New Nickname", + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +// ---- List (admin) ---- + +func TestUserListHandlerRequiresOffset(t *testing.T) { + testutil.SetupWithAuth(t) + admin := testutil.SeedUser(t, "admin@example.com", 40) + token := issueToken(t, admin.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/list", token) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestUserListHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + admin := testutil.SeedUser(t, testutil.RandomEmail(), 40) + for i := 0; i < 3; i++ { + testutil.SeedUser(t, testutil.RandomEmail(), 10) + } + token := issueToken(t, admin.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/list?offset=0&limit=10", token) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + assert.NotNil(t, resp["data"]) +} + +func TestUserListHandlerLowPermission(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/list?offset=0", token) + assert.Equal(t, http.StatusForbidden, w.Code) +} + +// ---- Other (info by user_id) ---- + +func TestUserInfoHandlerOtherSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + caller := testutil.SeedUser(t, testutil.RandomEmail(), 10) + target := testutil.SeedUser(t, testutil.RandomEmail(), 10) + require.NoError(t, new(data.User).PatchByUserId(context.Background(), target.UserId, data.WithAllowPublic(true))) + + token := issueToken(t, caller.UserId) + r := newUserRouter(t) + + w := getWithBearer(t, r, "/user/info/"+target.UserId.String(), token) + assert.Equal(t, http.StatusOK, w.Code) + var resp map[string]any + require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp)) + d, ok := resp["data"].(map[string]any) + require.True(t, ok) + assert.Equal(t, target.Email, d["email"]) +} + +// ---- AdminUpdate ---- + +func TestUserAdminUpdateHandlerSuccess(t *testing.T) { + testutil.SetupWithAuth(t) + admin := testutil.SeedUser(t, testutil.RandomEmail(), 40) + target := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, admin.UserId) + r := newUserRouter(t) + + w := patchWithBearer(t, r, "/user/update/"+target.UserId.String(), token, map[string]any{ + "nickname": "Admin Set Nickname", + }) + assert.Equal(t, http.StatusOK, w.Code) +} + +func TestUserAdminUpdateHandlerInvalidUserId(t *testing.T) { + testutil.SetupWithAuth(t) + admin := testutil.SeedUser(t, testutil.RandomEmail(), 40) + token := issueToken(t, admin.UserId) + r := newUserRouter(t) + + w := patchWithBearer(t, r, "/user/update/not-a-uuid", token, map[string]any{ + "nickname": "Test", + }) + assert.Equal(t, http.StatusBadRequest, w.Code) +} + +func TestUserAdminUpdateHandlerLowPermission(t *testing.T) { + testutil.SetupWithAuth(t) + user := testutil.SeedUser(t, testutil.RandomEmail(), 10) + target := testutil.SeedUser(t, testutil.RandomEmail(), 10) + token := issueToken(t, user.UserId) + r := newUserRouter(t) + + w := patchWithBearer(t, r, "/user/update/"+target.UserId.String(), token, map[string]any{ + "nickname": "Hacked", + }) + assert.Equal(t, http.StatusForbidden, w.Code) +} + diff --git a/charts/.gitkeep b/charts/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/client/cms/.gitignore b/client/cms/.gitignore deleted file mode 100644 index 668095b..0000000 --- a/client/cms/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -.direnv diff --git a/client/cms/components.json b/client/cms/components.json deleted file mode 100644 index 2b0833f..0000000 --- a/client/cms/components.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "", - "css": "src/index.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "iconLibrary": "lucide", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": {} -} diff --git a/client/cms/eslint.config.js b/client/cms/eslint.config.js deleted file mode 100644 index 75e958b..0000000 --- a/client/cms/eslint.config.js +++ /dev/null @@ -1,16 +0,0 @@ -import antfu from '@antfu/eslint-config'; -import pluginQuery from '@tanstack/eslint-plugin-query'; - -export default antfu({ - gitignore: true, - ignores: ['**/node_modules/**', '**/dist/**', 'bun.lock', '**/routeTree.gen.ts', '**/ui/**', 'src/components/editor/**/*'], - react: true, - stylistic: { - semi: true, - quotes: 'single', - indent: 2, - }, - typescript: { - tsconfigPath: 'tsconfig.json', - }, -}, ...pluginQuery.configs['flat/recommended']); diff --git a/client/cms/index.html b/client/cms/index.html deleted file mode 100644 index a16cb6b..0000000 --- a/client/cms/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - client - - -
- - - diff --git a/client/cms/package.json b/client/cms/package.json deleted file mode 100644 index 266c7ff..0000000 --- a/client/cms/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "client", - "type": "module", - "version": "0.0.0", - "private": true, - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@dnd-kit/core": "^6.3.1", - "@dnd-kit/modifiers": "^9.0.0", - "@dnd-kit/sortable": "^10.0.0", - "@dnd-kit/utilities": "^3.2.2", - "@hookform/resolvers": "^5.2.2", - "@marsidev/react-turnstile": "^1.4.0", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toggle": "^1.1.10", - "@radix-ui/react-toggle-group": "^1.1.11", - "@radix-ui/react-tooltip": "^1.2.8", - "@tabler/icons-react": "^3.36.0", - "@tailwindcss/vite": "^4.1.18", - "@tanstack/react-form": "^1.27.7", - "@tanstack/react-query": "^5.90.12", - "@tanstack/react-router": "^1.141.6", - "@tanstack/react-router-devtools": "^1.141.6", - "@tanstack/react-table": "^8.21.3", - "@tanstack/zod-adapter": "^1.143.4", - "@tanstack/zod-form-adapter": "^0.42.1", - "@uiw/react-md-editor": "^4.0.11", - "axios": "^1.13.2", - "base-64": "^1.0.0", - "buffer": "^6.0.3", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "culori": "^4.0.2", - "immer": "^11.1.0", - "lodash-es": "^4.17.22", - "lucide-react": "^0.562.0", - "next-themes": "^0.4.6", - "qrcode": "^1.5.4", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "react-hook-form": "^7.69.0", - "react-markdown": "^10.1.0", - "recharts": "2.15.4", - "sonner": "^2.0.7", - "tailwind-merge": "^3.4.0", - "tailwindcss": "^4.1.18", - "utf8": "^3.0.0", - "vaul": "^1.1.2", - "zod": "^4.2.1", - "zustand": "^5.0.9" - }, - "devDependencies": { - "@antfu/eslint-config": "^6.7.1", - "@eslint-react/eslint-plugin": "^2.3.13", - "@eslint/js": "^9.39.1", - "@tailwindcss/typography": "^0.5.19", - "@tanstack/eslint-plugin-query": "^5.91.2", - "@tanstack/router-plugin": "^1.141.7", - "@types/base-64": "^1.0.2", - "@types/culori": "^4.0.1", - "@types/lodash-es": "^4.17.12", - "@types/node": "^25.0.3", - "@types/qrcode": "^1.5.6", - "@types/react": "^19.2.5", - "@types/react-dom": "^19.2.3", - "@types/utf8": "^3.0.3", - "@vitejs/plugin-react": "^5.1.1", - "eslint": "^9.39.1", - "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.4.26", - "globals": "^16.5.0", - "lint-staged": "^16.2.7", - "simple-git-hooks": "^2.13.1", - "tw-animate-css": "^1.4.0", - "type-fest": "^5.4.1", - "typescript": "~5.9.3", - "typescript-eslint": "^8.46.4", - "vite": "^7.2.4", - "vite-plugin-svgr": "^4.5.0" - }, - "simple-git-hooks": { - "pre-commit": "bun run lint-staged" - }, - "lint-staged": { - "*": "eslint --fix" - }, - "packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316" -} diff --git a/client/cms/pnpm-lock.yaml b/client/cms/pnpm-lock.yaml deleted file mode 100644 index 7bbc249..0000000 --- a/client/cms/pnpm-lock.yaml +++ /dev/null @@ -1,8472 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@dnd-kit/core': - specifier: ^6.3.1 - version: 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@dnd-kit/modifiers': - specifier: ^9.0.0 - version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) - '@dnd-kit/sortable': - specifier: ^10.0.0 - version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) - '@dnd-kit/utilities': - specifier: ^3.2.2 - version: 3.2.2(react@19.2.3) - '@hookform/resolvers': - specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.71.1(react@19.2.3)) - '@marsidev/react-turnstile': - specifier: ^1.4.0 - version: 1.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-avatar': - specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-checkbox': - specifier: ^1.3.3 - version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-dialog': - specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-dropdown-menu': - specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-label': - specifier: ^2.1.8 - version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-select': - specifier: ^2.2.6 - version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-separator': - specifier: ^1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': - specifier: ^1.2.4 - version: 1.2.4(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-tabs': - specifier: ^1.1.13 - version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-toggle': - specifier: ^1.1.10 - version: 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-toggle-group': - specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-tooltip': - specifier: ^1.2.8 - version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tabler/icons-react': - specifier: ^3.36.0 - version: 3.36.1(react@19.2.3) - '@tailwindcss/vite': - specifier: ^4.1.18 - version: 4.1.18(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) - '@tanstack/react-form': - specifier: ^1.27.7 - version: 1.27.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/react-query': - specifier: ^5.90.12 - version: 5.90.19(react@19.2.3) - '@tanstack/react-router': - specifier: ^1.141.6 - version: 1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/react-router-devtools': - specifier: ^1.141.6 - version: 1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.153.2)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/react-table': - specifier: ^8.21.3 - version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/zod-adapter': - specifier: ^1.143.4 - version: 1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@4.3.5) - '@tanstack/zod-form-adapter': - specifier: ^0.42.1 - version: 0.42.1(zod@4.3.5) - '@uiw/react-md-editor': - specifier: ^4.0.11 - version: 4.0.11(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - axios: - specifier: ^1.13.2 - version: 1.13.2 - base-64: - specifier: ^1.0.0 - version: 1.0.0 - buffer: - specifier: ^6.0.3 - version: 6.0.3 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - culori: - specifier: ^4.0.2 - version: 4.0.2 - immer: - specifier: ^11.1.0 - version: 11.1.3 - lodash-es: - specifier: ^4.17.22 - version: 4.17.22 - lucide-react: - specifier: ^0.562.0 - version: 0.562.0(react@19.2.3) - next-themes: - specifier: ^0.4.6 - version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - qrcode: - specifier: ^1.5.4 - version: 1.5.4 - react: - specifier: ^19.2.0 - version: 19.2.3 - react-dom: - specifier: ^19.2.0 - version: 19.2.3(react@19.2.3) - react-hook-form: - specifier: ^7.69.0 - version: 7.71.1(react@19.2.3) - react-markdown: - specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.8)(react@19.2.3) - recharts: - specifier: 2.15.4 - version: 2.15.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - sonner: - specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - tailwind-merge: - specifier: ^3.4.0 - version: 3.4.0 - tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 - utf8: - specifier: ^3.0.0 - version: 3.0.0 - vaul: - specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: - specifier: ^4.2.1 - version: 4.3.5 - zustand: - specifier: ^5.0.9 - version: 5.0.10(@types/react@19.2.8)(immer@11.1.3)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)) - devDependencies: - '@antfu/eslint-config': - specifier: ^6.7.1 - version: 6.7.3(@eslint-react/eslint-plugin@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@vue/compiler-sfc@3.5.27)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eslint-plugin': - specifier: ^2.3.13 - version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint/js': - specifier: ^9.39.1 - version: 9.39.2 - '@tailwindcss/typography': - specifier: ^0.5.19 - version: 0.5.19(tailwindcss@4.1.18) - '@tanstack/eslint-plugin-query': - specifier: ^5.91.2 - version: 5.91.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@tanstack/router-plugin': - specifier: ^1.141.7 - version: 1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) - '@types/base-64': - specifier: ^1.0.2 - version: 1.0.2 - '@types/culori': - specifier: ^4.0.1 - version: 4.0.1 - '@types/lodash-es': - specifier: ^4.17.12 - version: 4.17.12 - '@types/node': - specifier: ^25.0.3 - version: 25.0.9 - '@types/qrcode': - specifier: ^1.5.6 - version: 1.5.6 - '@types/react': - specifier: ^19.2.5 - version: 19.2.8 - '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.8) - '@types/utf8': - specifier: ^3.0.3 - version: 3.0.3 - '@vitejs/plugin-react': - specifier: ^5.1.1 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) - eslint: - specifier: ^9.39.1 - version: 9.39.2(jiti@2.6.1) - eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-react-refresh: - specifier: ^0.4.26 - version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) - globals: - specifier: ^16.5.0 - version: 16.5.0 - lint-staged: - specifier: ^16.2.7 - version: 16.2.7 - simple-git-hooks: - specifier: ^2.13.1 - version: 2.13.1 - tw-animate-css: - specifier: ^1.4.0 - version: 1.4.0 - type-fest: - specifier: ^5.4.1 - version: 5.4.1 - typescript: - specifier: ~5.9.3 - version: 5.9.3 - typescript-eslint: - specifier: ^8.46.4 - version: 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - vite: - specifier: ^7.2.4 - version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - vite-plugin-svgr: - specifier: ^4.5.0 - version: 4.5.0(rollup@4.55.2)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)) - -packages: - - '@antfu/eslint-config@6.7.3': - resolution: {integrity: sha512-0tYYzY59uLnxWgbP9xpuxpvodTcWDacj439kTAJZB3sn7O0BnPfVxTnRvleGYaKCEALBZkzdC/wCho9FD7ICLw==} - hasBin: true - peerDependencies: - '@eslint-react/eslint-plugin': ^2.0.1 - '@next/eslint-plugin-next': '>=15.0.0' - '@prettier/plugin-xml': ^3.4.1 - '@unocss/eslint-plugin': '>=0.50.0' - astro-eslint-parser: ^1.0.2 - eslint: ^9.10.0 - eslint-plugin-astro: ^1.2.0 - eslint-plugin-format: '>=0.1.0' - eslint-plugin-jsx-a11y: '>=6.10.2' - eslint-plugin-react-hooks: ^7.0.0 - eslint-plugin-react-refresh: ^0.4.19 - eslint-plugin-solid: ^0.14.3 - eslint-plugin-svelte: '>=2.35.1' - eslint-plugin-vuejs-accessibility: ^2.4.1 - prettier-plugin-astro: ^0.14.0 - prettier-plugin-slidev: ^1.0.5 - svelte-eslint-parser: '>=0.37.0' - peerDependenciesMeta: - '@eslint-react/eslint-plugin': - optional: true - '@next/eslint-plugin-next': - optional: true - '@prettier/plugin-xml': - optional: true - '@unocss/eslint-plugin': - optional: true - astro-eslint-parser: - optional: true - eslint-plugin-astro: - optional: true - eslint-plugin-format: - optional: true - eslint-plugin-jsx-a11y: - optional: true - eslint-plugin-react-hooks: - optional: true - eslint-plugin-react-refresh: - optional: true - eslint-plugin-solid: - optional: true - eslint-plugin-svelte: - optional: true - eslint-plugin-vuejs-accessibility: - optional: true - prettier-plugin-astro: - optional: true - prettier-plugin-slidev: - optional: true - svelte-eslint-parser: - optional: true - - '@antfu/install-pkg@1.1.0': - resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} - - '@babel/code-frame@7.28.6': - resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.6': - resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.6': - resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.6': - resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.6': - resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.6': - resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.6': - resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} - engines: {node: '>=6.9.0'} - - '@clack/core@0.5.0': - resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} - - '@clack/prompts@0.11.0': - resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} - - '@dnd-kit/accessibility@3.1.1': - resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} - peerDependencies: - react: '>=16.8.0' - - '@dnd-kit/core@6.3.1': - resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@dnd-kit/modifiers@9.0.0': - resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} - peerDependencies: - '@dnd-kit/core': ^6.3.0 - react: '>=16.8.0' - - '@dnd-kit/sortable@10.0.0': - resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} - peerDependencies: - '@dnd-kit/core': ^6.3.0 - react: '>=16.8.0' - - '@dnd-kit/utilities@3.2.2': - resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} - peerDependencies: - react: '>=16.8.0' - - '@es-joy/jsdoccomment@0.78.0': - resolution: {integrity: sha512-rQkU5u8hNAq2NVRzHnIUUvR6arbO0b6AOlvpTNS48CkiKSn/xtNfOzBK23JE4SiW89DgvU7GtxLVgV4Vn2HBAw==} - engines: {node: '>=20.11.0'} - - '@es-joy/resolve.exports@1.2.0': - resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} - engines: {node: '>=10'} - - '@esbuild/aix-ppc64@0.27.2': - resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.2': - resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.2': - resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.2': - resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.2': - resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.2': - resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.2': - resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.2': - resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.2': - resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.2': - resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.2': - resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.2': - resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.2': - resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.2': - resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.2': - resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.2': - resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.2': - resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.2': - resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.2': - resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.2': - resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.2': - resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.2': - resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.2': - resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.2': - resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.2': - resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.2': - resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-plugin-eslint-comments@4.6.0': - resolution: {integrity: sha512-2EX2bBQq1ez++xz2o9tEeEQkyvfieWgUFMH4rtJJri2q0Azvhja3hZGXsjPXs31R4fQkZDtWzNDDK2zQn5UE5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - 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.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint-react/ast@2.7.2': - resolution: {integrity: sha512-RB8AVNjboN6/md9Da4rUG4WqxLT+DqUR+qXIR6iAD0+xxp6Dtihu541+lKLZ3GCstunbBcDwu7gdhSbz+BHSuQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@eslint-react/core@2.7.2': - resolution: {integrity: sha512-QOYh8OWwUGMYLhuvb8WcmoS2jYXb0SJbpX+Ozk+Ht2G9XGRAahl+8PDy/o2l2lLnFXv5JQGfLrN+m2WPTi104g==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@eslint-react/eff@2.7.2': - resolution: {integrity: sha512-AzQGbidoI8g8izka/1H9xCKW56NR7xWGGPMccBCUZwbCoJZ4wyRKcE10E7ot7LwBv5kBoUQp3GJ9UXCcg/Er0w==} - engines: {node: '>=20.19.0'} - - '@eslint-react/eslint-plugin@2.7.2': - resolution: {integrity: sha512-h9T5cc2TxsKMv/8iO63KKamXyJjHHAmeG2MJVjeIm4FaZdsX0/2Bx254B3Fa8IDqQi4X81AMyJ8ohtbxsn6pOw==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@eslint-react/shared@2.7.2': - resolution: {integrity: sha512-U1H3dLaTj7kvEbyJyJEgn6xX3BmrCH1f9f+tg9gLWlN7askgWT5NF56wfX1l+jtwiEAZD/78W1TfICKkMnZDxQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@eslint-react/var@2.7.2': - resolution: {integrity: sha512-sPnXmikpzmAdIWh6lqqKm4Bu0ypKTCAQ7WxGuR5ejxtrA/HjQQuKMBIyPkBdjHWlF9ADdh9pKuo1j2RQwUWiqA==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@eslint/compat@1.4.1': - resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.40 || 9 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/markdown@7.5.1': - resolution: {integrity: sha512-R8uZemG9dKTbru/DQRPblbJyXpObwKzo8rv1KYGGuPUPtjM4LXBYM9q5CIZAComzZupws3tWbDwam5AFpPLyJQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - - '@floating-ui/react-dom@2.1.6': - resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - - '@hookform/resolvers@5.2.2': - resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} - peerDependencies: - react-hook-form: ^7.55.0 - - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@marsidev/react-turnstile@1.4.1': - resolution: {integrity: sha512-1jE0IjvB8z+q1NFRs3149gXzXwIzXQWqQjn9fmAr13BiE3RYLWck5Me6flHYE90shW5L12Jkm6R1peS1OnA9oQ==} - peerDependencies: - react: ^17.0.2 || ^18.0.0 || ^19.0 - react-dom: ^17.0.2 || ^18.0.0 || ^19.0 - - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-avatar@1.1.11': - resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.3': - resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.8': - resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.4': - resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.8': - resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle-group@1.1.11': - resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/rollup-android-arm-eabi@4.55.2': - resolution: {integrity: sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.55.2': - resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.55.2': - resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.55.2': - resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.55.2': - resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.55.2': - resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.55.2': - resolution: {integrity: sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.55.2': - resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.55.2': - resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.55.2': - resolution: {integrity: sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.55.2': - resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.55.2': - resolution: {integrity: sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.55.2': - resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.55.2': - resolution: {integrity: sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.55.2': - resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.55.2': - resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.55.2': - resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.55.2': - resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.55.2': - resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.55.2': - resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.55.2': - resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.55.2': - resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.55.2': - resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.55.2': - resolution: {integrity: sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.55.2': - resolution: {integrity: sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==} - cpu: [x64] - os: [win32] - - '@sindresorhus/base62@1.0.0': - resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} - engines: {node: '>=18'} - - '@standard-schema/utils@0.3.0': - resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - - '@stylistic/eslint-plugin@5.7.0': - resolution: {integrity: sha512-PsSugIf9ip1H/mWKj4bi/BlEoerxXAda9ByRFsYuwsmr6af9NxJL0AaiNXs8Le7R21QR5KMiD/KdxZZ71LjAxQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=9.0.0' - - '@svgr/babel-plugin-add-jsx-attribute@8.0.0': - resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': - resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': - resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': - resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-svg-dynamic-title@8.0.0': - resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-svg-em-dimensions@8.0.0': - resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-transform-react-native-svg@8.1.0': - resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-plugin-transform-svg-component@8.0.0': - resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} - engines: {node: '>=12'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/babel-preset@8.1.0': - resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@svgr/core@8.1.0': - resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} - engines: {node: '>=14'} - - '@svgr/hast-util-to-babel-ast@8.0.0': - resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} - engines: {node: '>=14'} - - '@svgr/plugin-jsx@8.1.0': - resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} - engines: {node: '>=14'} - peerDependencies: - '@svgr/core': '*' - - '@tabler/icons-react@3.36.1': - resolution: {integrity: sha512-/8nOXeNeMoze9xY/QyEKG65wuvRhkT3q9aytaur6Gj8bYU2A98YVJyLc9MRmc5nVvpy+bRlrrwK/Ykr8WGyUWg==} - peerDependencies: - react: '>= 16' - - '@tabler/icons@3.36.1': - resolution: {integrity: sha512-f4Jg3Fof/Vru5ioix/UO4GX+sdDsF9wQo47FbtvG+utIYYVQ/QVAC0QYgcBbAjQGfbdOh2CCf0BgiFOF9Ixtjw==} - - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} - - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} - - '@tailwindcss/typography@0.5.19': - resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' - - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 - - '@tanstack/devtools-event-client@0.4.0': - resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} - engines: {node: '>=18'} - - '@tanstack/eslint-plugin-query@5.91.3': - resolution: {integrity: sha512-5GMGZMYFK9dOvjpdedjJs4hU40EdPuO2AjzObQzP7eOSsikunCfrXaU3oNGXSsvoU9ve1Z1xQZZuDyPi0C1M7Q==} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - - '@tanstack/form-core@0.42.1': - resolution: {integrity: sha512-jTU0jyHqFceujdtPNv3jPVej1dTqBwa8TYdIyWB5BCwRVUBZEp1PiYEBkC9r92xu5fMpBiKc+JKud3eeVjuMiA==} - - '@tanstack/form-core@1.27.7': - resolution: {integrity: sha512-nvogpyE98fhb0NDw1Bf2YaCH+L7ZIUgEpqO9TkHucDn6zg3ni521boUpv0i8HKIrmmFwDYjWZoCnrgY4HYWTkw==} - - '@tanstack/history@1.153.2': - resolution: {integrity: sha512-TVa0Wju5w6JZGq/S74Q7TQNtKXDatJaB4NYrhMZVU9ETlkgpr35NhDfOzsCJ93P0KCo1ZoDodlFp3c54/dLsyw==} - engines: {node: '>=12'} - - '@tanstack/pacer-lite@0.1.1': - resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} - engines: {node: '>=18'} - - '@tanstack/query-core@5.90.19': - resolution: {integrity: sha512-GLW5sjPVIvH491VV1ufddnfldyVB+teCnpPIvweEfkpRx7CfUmUGhoh9cdcUKBh/KwVxk22aNEDxeTsvmyB/WA==} - - '@tanstack/react-form@1.27.7': - resolution: {integrity: sha512-xTg4qrUY0fuLaSnkATLZcK3BWlnwLp7IuAb6UTbZKngiDEvvDCNTvVvHgPlgef1O2qN4klZxInRyRY6oEkXZ2A==} - peerDependencies: - '@tanstack/react-start': '*' - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@tanstack/react-start': - optional: true - - '@tanstack/react-query@5.90.19': - resolution: {integrity: sha512-qTZRZ4QyTzQc+M0IzrbKHxSeISUmRB3RPGmao5bT+sI6ayxSRhn0FXEnT5Hg3as8SBFcRosrXXRFB+yAcxVxJQ==} - peerDependencies: - react: ^18 || ^19 - - '@tanstack/react-router-devtools@1.153.2': - resolution: {integrity: sha512-LCEuRIyrF0tNKCBspR+TQj13MQ7sTCE4QkkuKAOp30nSdWLxq53bltnGs9bj/V/PTD52JibuAOYyxB94ssWZUA==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/react-router': ^1.153.2 - '@tanstack/router-core': ^1.153.2 - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - peerDependenciesMeta: - '@tanstack/router-core': - optional: true - - '@tanstack/react-router@1.153.2': - resolution: {integrity: sha512-fAXUBA2gZAId7h2eSHsRcgTeF8pioUz8V5rrQ+IrvA0a6IsxhbTSKLYyqUg4jRDkkcUKtM8StKtvbZCY+0IYWw==} - engines: {node: '>=12'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - - '@tanstack/react-store@0.8.0': - resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - '@tanstack/react-table@8.21.3': - resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} - engines: {node: '>=12'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - '@tanstack/router-core@1.153.2': - resolution: {integrity: sha512-WLaR+rSNW7bj9UCJQ3SKpuh6nZBZkpGnf2mpjn/uRB6joIQ3BU7aRdhb7w9Via/MP52iaHh5sd8NY3MaLpF2tQ==} - engines: {node: '>=12'} - - '@tanstack/router-devtools-core@1.153.2': - resolution: {integrity: sha512-53gFlnz2oUeGvRwu7hzi+jlqm5F5X1XwNniirCTjggsV5P+FVQ7YJ+gfMuN5MHonWmVCLd1QqGkl2nYRTGHeTg==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/router-core': ^1.153.2 - csstype: ^3.0.10 - peerDependenciesMeta: - csstype: - optional: true - - '@tanstack/router-generator@1.153.2': - resolution: {integrity: sha512-bEhmCtXq5vv3HukKq5zmTDBNDRqVllYxsHoWtqEvHv5hCb5xwKKfUMGemRoiQ96/wLFuGnA5DYkem2GZWcG3wg==} - engines: {node: '>=12'} - - '@tanstack/router-plugin@1.153.2': - resolution: {integrity: sha512-aMMc70ChM0wBYOToq39kTMKI2A0EKWpumiKTJyAwEglXf0raF48+26Fmv0gr9/5CLvD0g8ljllsskVDyzg8oDw==} - engines: {node: '>=12'} - peerDependencies: - '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.153.2 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' - vite-plugin-solid: ^2.11.10 - webpack: '>=5.92.0' - peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@tanstack/react-router': - optional: true - vite: - optional: true - vite-plugin-solid: - optional: true - webpack: - optional: true - - '@tanstack/router-utils@1.143.11': - resolution: {integrity: sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA==} - engines: {node: '>=12'} - - '@tanstack/store@0.7.7': - resolution: {integrity: sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==} - - '@tanstack/store@0.8.0': - resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} - - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} - - '@tanstack/virtual-file-routes@1.145.4': - resolution: {integrity: sha512-CI75JrfqSluhdGwLssgVeQBaCphgfkMQpi8MCY3UJX1hoGzXa8kHYJcUuIFMOLs1q7zqHy++EVVtMK03osR5wQ==} - engines: {node: '>=12'} - - '@tanstack/zod-adapter@1.153.2': - resolution: {integrity: sha512-E3OPtB/QSRo9lN8wWbxjvjMfQI4MOKjTEZOrwZiHXXMzlOMYWqxg99eCPeHP8kcXKJ+LdIkf29sZ/0rC62I4aQ==} - engines: {node: '>=12'} - peerDependencies: - '@tanstack/react-router': '>=1.43.2' - zod: ^3.23.8 - - '@tanstack/zod-form-adapter@0.42.1': - resolution: {integrity: sha512-hPRM0lawVKP64yurW4c6KHZH6altMo2MQN14hfi+GMBTKjO9S7bW1x5LPZ5cayoJE3mBvdlahpSGT5rYZtSbXQ==} - peerDependencies: - zod: ^3.x - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/base-64@1.0.2': - resolution: {integrity: sha512-uPgKMmM9fmn7I+Zi6YBqctOye4SlJsHKcisjHIMWpb2YKZRc36GpKyNuQ03JcT+oNXg1m7Uv4wU94EVltn8/cw==} - - '@types/culori@4.0.1': - resolution: {integrity: sha512-43M51r/22CjhbOXyGT361GZ9vncSVQ39u62x5eJdBQFviI8zWp2X5jzqg7k4M6PVgDQAClpy2bUe2dtwEgEDVQ==} - - '@types/d3-array@3.2.2': - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - - '@types/d3-color@3.1.3': - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - - '@types/d3-ease@3.0.2': - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - - '@types/d3-interpolate@3.0.4': - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - - '@types/d3-scale@4.0.9': - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - - '@types/d3-shape@3.1.8': - resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} - - '@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/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/hast@2.3.10': - resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/lodash-es@4.17.12': - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - - '@types/lodash@4.17.23': - resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@25.0.9': - resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} - - '@types/prismjs@1.26.5': - resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} - - '@types/qrcode@1.5.6': - resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.8': - resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} - - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/utf8@3.0.3': - resolution: {integrity: sha512-+lqLGxWZsEe4Z6OrzBI7Ym4SMUTaMS5yOrHZ0/IL0bpIye1Qbs4PpobJL2mLDbftUXlPFZR7fu6d1yM+bHLX1w==} - - '@typescript-eslint/eslint-plugin@8.53.1': - resolution: {integrity: sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.53.1 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.53.1': - resolution: {integrity: sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.53.1': - resolution: {integrity: sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.53.1': - resolution: {integrity: sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.53.1': - resolution: {integrity: sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.53.1': - resolution: {integrity: sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.53.1': - resolution: {integrity: sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.53.1': - resolution: {integrity: sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.53.1': - resolution: {integrity: sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.53.1': - resolution: {integrity: sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@uiw/copy-to-clipboard@1.0.19': - resolution: {integrity: sha512-AYxzFUBkZrhtExb2QC0C4lFH2+BSx6JVId9iqeGHakBuosqiQHUQaNZCvIBeM97Ucp+nJ22flOh8FBT2pKRRAA==} - - '@uiw/react-markdown-preview@5.1.5': - resolution: {integrity: sha512-DNOqx1a6gJR7Btt57zpGEKTfHRlb7rWbtctMRO2f82wWcuoJsxPBrM+JWebDdOD0LfD8oe2CQvW2ICQJKHQhZg==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@uiw/react-md-editor@4.0.11': - resolution: {integrity: sha512-F0OR5O1v54EkZYvJj3ew0I7UqLiPeU34hMAY4MdXS3hI86rruYi5DHVkG/VuvLkUZW7wIETM2QFtZ459gKIjQA==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@vitejs/plugin-react@5.1.2': - resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/eslint-plugin@1.6.6': - resolution: {integrity: sha512-bwgQxQWRtnTVzsUHK824tBmHzjV0iTx3tZaiQIYDjX3SA7TsQS8CuDVqxXrRY3FaOUMgbGavesCxI9MOfFLm7Q==} - engines: {node: '>=18'} - peerDependencies: - eslint: '>=8.57.0' - typescript: '>=5.0.0' - vitest: '*' - peerDependenciesMeta: - typescript: - optional: true - vitest: - optional: true - - '@vue/compiler-core@3.5.27': - resolution: {integrity: sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==} - - '@vue/compiler-dom@3.5.27': - resolution: {integrity: sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==} - - '@vue/compiler-sfc@3.5.27': - resolution: {integrity: sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==} - - '@vue/compiler-ssr@3.5.27': - resolution: {integrity: sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==} - - '@vue/shared@3.5.27': - resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-escapes@7.2.0: - resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} - engines: {node: '>=18'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} - engines: {node: '>=14'} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - are-docs-informative@0.0.2: - resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} - engines: {node: '>=14'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - - babel-dead-code-elimination@1.0.12: - resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - - bail@2.0.2: - resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base-64@1.0.0: - resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - baseline-browser-mapping@2.9.15: - resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} - hasBin: true - - bcp-47-match@2.0.3: - resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - birecord@0.1.1: - resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - builtin-modules@5.0.0: - resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} - engines: {node: '>=18.20'} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001765: - resolution: {integrity: sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - - character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} - engines: {node: '>=8'} - - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - - clean-regexp@1.0.0: - resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} - engines: {node: '>=4'} - - cli-cursor@5.0.0: - resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} - engines: {node: '>=18'} - - cli-truncate@5.1.1: - resolution: {integrity: sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==} - engines: {node: '>=20'} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - 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'} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} - engines: {node: '>=20'} - - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} - engines: {node: '>= 12.0.0'} - - comment-parser@1.4.4: - resolution: {integrity: sha512-0D6qSQ5IkeRrGJFHRClzaMOenMeT0gErz3zIw3AprKMqhRN6LNU2jQOdkPG/FZ+8bCgXE1VidrgSzlBBDZRr8A==} - engines: {node: '>= 12.0.0'} - - compare-versions@6.1.1: - resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-es@2.0.0: - resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} - - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} - - cosmiconfig@8.3.6: - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - css-selector-parser@3.3.0: - resolution: {integrity: sha512-Y2asgMGFqJKF4fq4xHDSlFYIkeVfRsm69lQC1q9kbEsH5XtnINTMrweLkjYMeaUgiXBy/uvKeO/a1JHTNnmB2g==} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - culori@4.0.2: - resolution: {integrity: sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - 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'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decimal.js-light@2.5.1: - resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} - - decode-named-character-reference@1.3.0: - resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - diff-sequences@27.5.1: - resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - diff@8.0.3: - resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} - engines: {node: '>=0.3.1'} - - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - - direction@2.0.1: - resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} - hasBin: true - - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - - dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} - engines: {node: '>=14'} - - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} - engines: {node: '>=10.13.0'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - entities@7.0.0: - resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} - engines: {node: '>=0.12'} - - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - - 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-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild@0.27.2: - resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} - engines: {node: '>=18'} - 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'} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - eslint-compat-utils@0.5.1: - resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=6.0.0' - - eslint-compat-utils@0.6.5: - resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==} - engines: {node: '>=12'} - peerDependencies: - eslint: '>=6.0.0' - - eslint-config-flat-gitignore@2.1.0: - resolution: {integrity: sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==} - peerDependencies: - eslint: ^9.5.0 - - eslint-flat-config-utils@2.1.4: - resolution: {integrity: sha512-bEnmU5gqzS+4O+id9vrbP43vByjF+8KOs+QuuV4OlqAuXmnRW2zfI/Rza1fQvdihQ5h4DUo0NqFAiViD4mSrzQ==} - - eslint-json-compat-utils@0.2.1: - resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==} - engines: {node: '>=12'} - peerDependencies: - '@eslint/json': '*' - eslint: '*' - jsonc-eslint-parser: ^2.4.0 - peerDependenciesMeta: - '@eslint/json': - optional: true - - eslint-merge-processors@2.0.0: - resolution: {integrity: sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA==} - peerDependencies: - eslint: '*' - - eslint-plugin-antfu@3.1.3: - resolution: {integrity: sha512-Az1QuqQJ/c2efWCxVxF249u3D4AcAu1Y3VCGAlJm+x4cgnn1ybUAnCT5DWVcogeaWduQKeVw07YFydVTOF4xDw==} - peerDependencies: - eslint: '*' - - eslint-plugin-command@3.4.0: - resolution: {integrity: sha512-EW4eg/a7TKEhG0s5IEti72kh3YOTlnhfFNuctq5WnB1fst37/IHTd5OkD+vnlRf3opTvUcSRihAateP6bT5ZcA==} - peerDependencies: - eslint: '*' - - eslint-plugin-es-x@7.8.0: - resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '>=8' - - eslint-plugin-import-lite@0.4.0: - resolution: {integrity: sha512-My0ReAg8WbHXYECIHVJkWB8UxrinZn3m72yonOYH6MFj40ZN1vHYQj16iq2Fd8Wrt/vRZJwDX2xm/BzDk1FzTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=9.0.0' - typescript: '>=4.5' - peerDependenciesMeta: - typescript: - optional: true - - eslint-plugin-jsdoc@61.7.1: - resolution: {integrity: sha512-36DpldF95MlTX//n3/naULFVt8d1cV4jmSkx7ZKrE9ikkKHAgMLesuWp1SmwpVwAs5ndIM6abKd6PeOYZUgdWg==} - engines: {node: '>=20.11.0'} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - - eslint-plugin-jsonc@2.21.0: - resolution: {integrity: sha512-HttlxdNG5ly3YjP1cFMP62R4qKLxJURfBZo2gnMY+yQojZxkLyOpY1H1KRTKBmvQeSG9pIpSGEhDjE17vvYosg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '>=6.0.0' - - eslint-plugin-n@17.23.2: - resolution: {integrity: sha512-RhWBeb7YVPmNa2eggvJooiuehdL76/bbfj/OJewyoGT80qn5PXdz8zMOTO6YHOsI7byPt7+Ighh/i/4a5/v7hw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=8.23.0' - - eslint-plugin-no-only-tests@3.3.0: - resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} - engines: {node: '>=5.0.0'} - - eslint-plugin-perfectionist@4.15.1: - resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==} - engines: {node: ^18.0.0 || >=20.0.0} - peerDependencies: - eslint: '>=8.45.0' - - eslint-plugin-pnpm@1.5.0: - resolution: {integrity: sha512-ayMo1GvrQ/sF/bz1aOAiH0jv9eAqU2Z+a1ycoWz/uFFK5NxQDq49BDKQtBumcOUBf2VHyiTW4a8u+6KVqoIWzQ==} - peerDependencies: - eslint: ^9.0.0 - - eslint-plugin-react-dom@2.7.2: - resolution: {integrity: sha512-Qzd4HAFwsxvOJoAycLIRxziOTJwEZ6EGAA6jEFFBSD1BbFVnDlozMvOLp9/+GrZW3cE0FGmAS6QXnjuMf0QYLQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - eslint-plugin-react-hooks-extra@2.7.2: - resolution: {integrity: sha512-wcjQeBO1naCFPV47osw7nnK2p81eudCE2PhasKLtBV+GcAEi34jbt9QGULzQYueP+zd1aW53SmnVrTinY4DC6w==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - - eslint-plugin-react-naming-convention@2.7.2: - resolution: {integrity: sha512-T+/RQFEda3AgCzBHguE3isLQetn8KUOZ14SnDBQSOZSWS/GjgQn+gmqHi3EVHX/sDdL+LsIUKRsRR6KmmYWMiw==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - eslint-plugin-react-refresh@0.4.26: - resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} - peerDependencies: - eslint: '>=8.40' - - eslint-plugin-react-web-api@2.7.2: - resolution: {integrity: sha512-iA3D8jbwasMeeUfK8XucGkgrjQvZowCTi1+TzA43U7IFsWzyQWQpbN/I9B0BY/g6/JU9falC5b7qv6HB7P5JhA==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - eslint-plugin-react-x@2.7.2: - resolution: {integrity: sha512-0NbYqJhc3tZQVluaFMVCOg6HEFarlNNXe+DHa/JrLAR0PVb9AtJGk8FBEDdxaUZO8ph0sAekUNLB7gymftj4Dw==} - engines: {node: '>=20.19.0'} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - eslint-plugin-regexp@2.10.0: - resolution: {integrity: sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==} - engines: {node: ^18 || >=20} - peerDependencies: - eslint: '>=8.44.0' - - eslint-plugin-toml@0.12.0: - resolution: {integrity: sha512-+/wVObA9DVhwZB1nG83D2OAQRrcQZXy+drqUnFJKymqnmbnbfg/UPmEMCKrJNcEboUGxUjYrJlgy+/Y930mURQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '>=6.0.0' - - eslint-plugin-unicorn@62.0.0: - resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} - engines: {node: ^20.10.0 || >=21.0.0} - peerDependencies: - eslint: '>=9.38.0' - - eslint-plugin-unused-imports@4.3.0: - resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 - eslint: ^9.0.0 || ^8.0.0 - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - - eslint-plugin-vue@10.7.0: - resolution: {integrity: sha512-r2XFCK4qlo1sxEoAMIoTTX0PZAdla0JJDt1fmYiworZUX67WeEGqm+JbyAg3M+pGiJ5U6Mp5WQbontXWtIW7TA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 - vue-eslint-parser: ^10.0.0 - peerDependenciesMeta: - '@stylistic/eslint-plugin': - optional: true - '@typescript-eslint/parser': - optional: true - - eslint-plugin-yml@1.19.1: - resolution: {integrity: sha512-bYkOxyEiXh9WxUhVYPELdSHxGG5pOjCSeJOVkfdIyj6tuiHDxrES2WAW1dBxn3iaZQey57XflwLtCYRcNPOiOg==} - engines: {node: ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '>=6.0.0' - - eslint-processor-vue-blocks@2.0.0: - resolution: {integrity: sha512-u4W0CJwGoWY3bjXAuFpc/b6eK3NQEI8MoeW7ritKj3G3z/WtHrKjkqf+wk8mPEy5rlMGS+k6AZYOw2XBoN/02Q==} - peerDependencies: - '@vue/compiler-sfc': ^3.3.0 - eslint: '>=9.0.0' - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.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-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@5.0.0: - resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - espree@11.1.0: - resolution: {integrity: sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - 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.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - 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-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-equals@5.4.0: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.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==} - - fault@2.0.1: - resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} - engines: {node: '>=18'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - format@0.2.2: - resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} - engines: {node: '>=0.4.x'} - - 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==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} - engines: {node: '>=18'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} - - github-slugger@2.0.0: - resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} - - 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'} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} - engines: {node: '>=18'} - - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} - engines: {node: '>=18'} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - goober@2.1.18: - resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} - peerDependencies: - csstype: ^3.0.10 - - 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-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'} - - hast-util-from-html@2.0.3: - resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} - - hast-util-from-parse5@8.0.3: - resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - - hast-util-has-property@3.0.0: - resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} - - hast-util-heading-rank@3.0.0: - resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} - - hast-util-is-element@3.0.0: - resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - - hast-util-parse-selector@3.1.1: - resolution: {integrity: sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hast-util-raw@9.1.0: - resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - - hast-util-select@6.0.4: - resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-to-jsx-runtime@2.3.6: - resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} - - hast-util-to-parse5@8.0.1: - resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} - - hast-util-to-string@3.0.1: - resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hastscript@7.2.0: - resolution: {integrity: sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==} - - hastscript@9.0.1: - resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - html-entities@2.6.0: - resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} - - html-url-attributes@3.0.1: - resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - 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'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - immer@11.1.3: - resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - - inline-style-parser@0.2.7: - resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} - - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - - 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-builtin-module@5.0.0: - resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} - engines: {node: '>=18.20'} - - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - 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-fullwidth-code-point@5.1.0: - resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} - engines: {node: '>=18'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - - is-immutable-type@5.0.1: - resolution: {integrity: sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==} - peerDependencies: - eslint: '*' - typescript: '>=4.7.4' - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - isbot@5.1.33: - resolution: {integrity: sha512-P4Hgb5NqswjkI0J1CM6XKXon/sxKY1SuowE7Qx2hrBhIwICFyXy54mfgB5eMHXsbe/eStzzpbIGNOvGmz+dlKg==} - engines: {node: '>=18'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsdoc-type-pratt-parser@4.8.0: - resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} - engines: {node: '>=12.0.0'} - - jsdoc-type-pratt-parser@7.0.0: - resolution: {integrity: sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==} - engines: {node: '>=20.0.0'} - - 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-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonc-eslint-parser@2.4.2: - resolution: {integrity: sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - lint-staged@16.2.7: - resolution: {integrity: sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==} - engines: {node: '>=20.17'} - hasBin: true - - listr2@9.0.5: - resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} - engines: {node: '>=20.0.0'} - - local-pkg@1.1.2: - resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} - engines: {node: '>=14'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash-es@4.17.22: - resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - log-update@6.1.0: - resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} - engines: {node: '>=18'} - - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lucide-react@0.562.0: - resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - markdown-table@3.0.4: - resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdast-util-find-and-replace@3.0.2: - resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} - - mdast-util-frontmatter@2.0.1: - resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} - - mdast-util-gfm-autolink-literal@2.0.1: - resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} - - mdast-util-gfm-footnote@2.1.0: - resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} - - mdast-util-gfm-strikethrough@2.0.0: - resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} - - mdast-util-gfm-table@2.0.0: - resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} - - mdast-util-gfm-task-list-item@2.0.0: - resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} - - mdast-util-gfm@3.1.0: - resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} - - mdast-util-mdx-expression@2.0.1: - resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} - - mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} - - mdast-util-mdxjs-esm@2.0.1: - resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} - - mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - - mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - - micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - - micromark-extension-frontmatter@2.0.0: - resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} - - micromark-extension-gfm-autolink-literal@2.1.0: - resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} - - micromark-extension-gfm-footnote@2.1.0: - resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} - - micromark-extension-gfm-strikethrough@2.1.0: - resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} - - micromark-extension-gfm-table@2.1.1: - resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} - - micromark-extension-gfm-tagfilter@2.0.0: - resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} - - micromark-extension-gfm-task-list-item@2.1.0: - resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} - - micromark-extension-gfm@3.0.0: - resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} - - micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - - micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - - micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - - micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - - micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - - micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - - micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - - micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - - micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - - micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - - micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - - 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'} - - mimic-function@5.0.1: - resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} - engines: {node: '>=18'} - - 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'} - - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nano-spawn@2.0.0: - resolution: {integrity: sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==} - engines: {node: '>=20.17'} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - natural-orderby@5.0.0: - resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} - engines: {node: '>=18'} - - next-themes@0.4.6: - resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-deep-merge@2.0.0: - resolution: {integrity: sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==} - - 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'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-manager-detector@1.6.0: - resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} - - parse-gitignore@2.0.0: - resolution: {integrity: sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==} - engines: {node: '>=14'} - - parse-imports-exports@0.2.4: - resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - parse-numeric-range@1.3.0: - resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} - - parse-statements@1.0.11: - resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - 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.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pidtree@0.6.0: - resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} - engines: {node: '>=0.10'} - hasBin: true - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - pngjs@5.0.0: - resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} - engines: {node: '>=10.13.0'} - - pnpm-workspace-yaml@1.5.0: - resolution: {integrity: sha512-PxdyJuFvq5B0qm3s9PaH/xOtSxrcvpBRr+BblhucpWjs8c79d4b7/cXhyY4AyHOHCnqklCYZTjfl0bT/mFVTRw==} - - postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} - - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier@3.8.0: - resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} - engines: {node: '>=14'} - hasBin: true - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - property-information@6.5.0: - resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qrcode@1.5.4: - resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} - engines: {node: '>=10.13.0'} - hasBin: true - - quansync@0.2.11: - resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} - peerDependencies: - react: ^19.2.3 - - react-hook-form@7.71.1: - resolution: {integrity: sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-markdown@10.1.0: - resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} - peerDependencies: - '@types/react': '>=18' - react: '>=18' - - react-markdown@9.0.3: - resolution: {integrity: sha512-Yk7Z94dbgYTOrdk41Z74GoKA7rThnsbbqBTRYuxoe08qvfQ9tJVhmAKw6BJS/ZORG7kTy/s1QvYzSuaoBA1qfw==} - peerDependencies: - '@types/react': '>=18' - react: '>=18' - - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-smooth@4.0.4: - resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} - engines: {node: '>=0.10.0'} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - - recharts-scale@0.4.5: - resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} - - recharts@2.15.4: - resolution: {integrity: sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==} - engines: {node: '>=14'} - peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - refa@0.12.1: - resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - refractor@4.9.0: - resolution: {integrity: sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==} - - regexp-ast-analysis@0.7.1: - resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - regexp-tree@0.1.27: - resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} - hasBin: true - - regjsparser@0.13.0: - resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} - hasBin: true - - rehype-attr@3.0.3: - resolution: {integrity: sha512-Up50Xfra8tyxnkJdCzLBIBtxOcB2M1xdeKe1324U06RAvSjYm7ULSeoM+b/nYPQPVd7jsXJ9+39IG1WAJPXONw==} - engines: {node: '>=16'} - - rehype-autolink-headings@7.1.0: - resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} - - rehype-ignore@2.0.3: - resolution: {integrity: sha512-IzhP6/u/6sm49sdktuYSmeIuObWB+5yC/5eqVws8BhuGA9kY25/byz6uCy/Ravj6lXUShEd2ofHM5MyAIj86Sg==} - engines: {node: '>=16'} - - rehype-parse@9.0.1: - resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} - - rehype-prism-plus@2.0.0: - resolution: {integrity: sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==} - - rehype-prism-plus@2.0.1: - resolution: {integrity: sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q==} - - rehype-raw@7.0.0: - resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} - - rehype-rewrite@4.0.4: - resolution: {integrity: sha512-L/FO96EOzSA6bzOam4DVu61/PB3AGKcSPXpa53yMIozoxH4qg1+bVZDF8zh1EsuxtSauAhzt5cCnvoplAaSLrw==} - engines: {node: '>=16.0.0'} - - rehype-slug@6.0.0: - resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} - - rehype-stringify@10.0.1: - resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} - - rehype@13.0.2: - resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} - - remark-gfm@4.0.1: - resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} - - remark-github-blockquote-alert@1.3.1: - resolution: {integrity: sha512-OPNnimcKeozWN1w8KVQEuHOxgN3L4rah8geMOLhA5vN9wITqU4FWD+G26tkEsCGHiOVDbISx+Se5rGZ+D1p0Jg==} - engines: {node: '>=16'} - - remark-parse@11.0.0: - resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - - remark-rehype@11.1.2: - resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} - - remark-stringify@11.0.0: - resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - - reserved-identifiers@1.2.0: - resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} - engines: {node: '>=18'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - restore-cursor@5.1.0: - resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} - engines: {node: '>=18'} - - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - - rollup@4.55.2: - resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - scslre@0.3.0: - resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} - engines: {node: ^14.0.0 || >=16.0.0} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true - - seroval-plugins@1.4.2: - resolution: {integrity: sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - - seroval@1.4.2: - resolution: {integrity: sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==} - engines: {node: '>=10'} - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - 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'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-git-hooks@2.13.1: - resolution: {integrity: sha512-WszCLXwT4h2k1ufIXAgsbiTOazqqevFCIncOuUBZJ91DdvWcC5+OFkluWRQPrcuSYd8fjq+o2y1QfWqYMoAToQ==} - hasBin: true - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slice-ansi@7.1.2: - resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} - engines: {node: '>=18'} - - snake-case@3.0.4: - resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} - - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@4.0.0: - resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - - spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} - - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - - string-ts@2.3.1: - resolution: {integrity: sha512-xSJq+BS52SaFFAVxuStmx6n5aYZU571uYUnUrPXkPFCfdHyZMMlbP2v2Wx5sNBnAVzq/2+0+mcBLBa3Xa5ubYw==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - string-width@8.1.0: - resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} - engines: {node: '>=20'} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} - engines: {node: '>=12'} - - strip-indent@4.1.1: - resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} - engines: {node: '>=12'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - style-to-js@1.1.21: - resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} - - style-to-object@1.0.14: - resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - svg-parser@2.0.4: - resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} - - synckit@0.11.12: - resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} - engines: {node: ^14.18.0 || >=16.0.0} - - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} - - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - to-valid-identifier@1.0.0: - resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} - engines: {node: '>=20'} - - toml-eslint-parser@0.10.1: - resolution: {integrity: sha512-9mjy3frhioGIVGcwamlVlUyJ9x+WHw/TXiz9R4YOlmsIuBN43r9Dp8HZ35SF9EKjHrn3BUZj04CF+YqZ2oJ+7w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - trough@2.2.0: - resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - ts-declaration-location@1.0.7: - resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} - peerDependencies: - typescript: '>=4.0.0' - - ts-pattern@5.9.0: - resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} - engines: {node: '>=18.0.0'} - hasBin: true - - tw-animate-css@1.4.0: - resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@5.4.1: - resolution: {integrity: sha512-xygQcmneDyzsEuKZrFbRMne5HDqMs++aFzefrJTgEIKjQ3rekM+RPfFCVq2Gp1VIDqddoYeppCj4Pcb+RZW0GQ==} - engines: {node: '>=20'} - - typescript-eslint@8.53.1: - resolution: {integrity: sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unified@11.0.5: - resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - - unist-util-filter@5.0.1: - resolution: {integrity: sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} - - unplugin@2.3.11: - resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} - engines: {node: '>=18.12.0'} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - utf8@3.0.0: - resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vaul@1.1.2: - resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - - vfile-location@5.0.3: - resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - victory-vendor@36.9.2: - resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} - - vite-plugin-svgr@4.5.0: - resolution: {integrity: sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==} - peerDependencies: - vite: '>=2.6.0' - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vue-eslint-parser@10.2.0: - resolution: {integrity: sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - 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@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - - xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml-eslint-parser@1.3.2: - resolution: {integrity: sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==} - engines: {node: ^14.17.0 || >=16.0.0} - - yaml-eslint-parser@2.0.0: - resolution: {integrity: sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.3.5: - resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} - - zustand@5.0.10: - resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@antfu/eslint-config@6.7.3(@eslint-react/eslint-plugin@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(@vue/compiler-sfc@3.5.27)(eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)))(eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@antfu/install-pkg': 1.1.0 - '@clack/prompts': 0.11.0 - '@eslint-community/eslint-plugin-eslint-comments': 4.6.0(eslint@9.39.2(jiti@2.6.1)) - '@eslint/markdown': 7.5.1 - '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@vitest/eslint-plugin': 1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - ansis: 4.2.0 - cac: 6.7.14 - eslint: 9.39.2(jiti@2.6.1) - eslint-config-flat-gitignore: 2.1.0(eslint@9.39.2(jiti@2.6.1)) - eslint-flat-config-utils: 2.1.4 - eslint-merge-processors: 2.0.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-antfu: 3.1.3(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-command: 3.4.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import-lite: 0.4.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-jsdoc: 61.7.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-jsonc: 2.21.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-n: 17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-no-only-tests: 3.3.0 - eslint-plugin-perfectionist: 4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-pnpm: 1.5.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-toml: 0.12.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-unicorn: 62.0.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-unused-imports: 4.3.0(@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-vue: 10.7.0(@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) - eslint-plugin-yml: 1.19.1(eslint@9.39.2(jiti@2.6.1)) - eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.27)(eslint@9.39.2(jiti@2.6.1)) - globals: 16.5.0 - jsonc-eslint-parser: 2.4.2 - local-pkg: 1.1.2 - parse-gitignore: 2.0.0 - toml-eslint-parser: 0.10.1 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) - yaml-eslint-parser: 1.3.2 - optionalDependencies: - '@eslint-react/eslint-plugin': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-react-refresh: 0.4.26(eslint@9.39.2(jiti@2.6.1)) - transitivePeerDependencies: - - '@eslint/json' - - '@vue/compiler-sfc' - - supports-color - - typescript - - vitest - - '@antfu/install-pkg@1.1.0': - dependencies: - package-manager-detector: 1.6.0 - tinyexec: 1.0.2 - - '@babel/code-frame@7.28.6': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.6': {} - - '@babel/core@7.28.6': - dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.6': - dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.28.6 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.6 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.28.6 - - '@babel/parser@7.28.6': - dependencies: - '@babel/types': 7.28.6 - - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/runtime@7.28.6': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - - '@babel/traverse@7.28.6': - dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.6 - '@babel/template': 7.28.6 - '@babel/types': 7.28.6 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.6': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@clack/core@0.5.0': - dependencies: - picocolors: 1.1.1 - sisteransi: 1.0.5 - - '@clack/prompts@0.11.0': - dependencies: - '@clack/core': 0.5.0 - picocolors: 1.1.1 - sisteransi: 1.0.5 - - '@dnd-kit/accessibility@3.1.1(react@19.2.3)': - dependencies: - react: 19.2.3 - tslib: 2.8.1 - - '@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.2.3) - '@dnd-kit/utilities': 3.2.2(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tslib: 2.8.1 - - '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': - dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@dnd-kit/utilities': 3.2.2(react@19.2.3) - react: 19.2.3 - tslib: 2.8.1 - - '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': - dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@dnd-kit/utilities': 3.2.2(react@19.2.3) - react: 19.2.3 - tslib: 2.8.1 - - '@dnd-kit/utilities@3.2.2(react@19.2.3)': - dependencies: - react: 19.2.3 - tslib: 2.8.1 - - '@es-joy/jsdoccomment@0.78.0': - dependencies: - '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.53.1 - comment-parser: 1.4.1 - esquery: 1.7.0 - jsdoc-type-pratt-parser: 7.0.0 - - '@es-joy/resolve.exports@1.2.0': {} - - '@esbuild/aix-ppc64@0.27.2': - optional: true - - '@esbuild/android-arm64@0.27.2': - optional: true - - '@esbuild/android-arm@0.27.2': - optional: true - - '@esbuild/android-x64@0.27.2': - optional: true - - '@esbuild/darwin-arm64@0.27.2': - optional: true - - '@esbuild/darwin-x64@0.27.2': - optional: true - - '@esbuild/freebsd-arm64@0.27.2': - optional: true - - '@esbuild/freebsd-x64@0.27.2': - optional: true - - '@esbuild/linux-arm64@0.27.2': - optional: true - - '@esbuild/linux-arm@0.27.2': - optional: true - - '@esbuild/linux-ia32@0.27.2': - optional: true - - '@esbuild/linux-loong64@0.27.2': - optional: true - - '@esbuild/linux-mips64el@0.27.2': - optional: true - - '@esbuild/linux-ppc64@0.27.2': - optional: true - - '@esbuild/linux-riscv64@0.27.2': - optional: true - - '@esbuild/linux-s390x@0.27.2': - optional: true - - '@esbuild/linux-x64@0.27.2': - optional: true - - '@esbuild/netbsd-arm64@0.27.2': - optional: true - - '@esbuild/netbsd-x64@0.27.2': - optional: true - - '@esbuild/openbsd-arm64@0.27.2': - optional: true - - '@esbuild/openbsd-x64@0.27.2': - optional: true - - '@esbuild/openharmony-arm64@0.27.2': - optional: true - - '@esbuild/sunos-x64@0.27.2': - optional: true - - '@esbuild/win32-arm64@0.27.2': - optional: true - - '@esbuild/win32-ia32@0.27.2': - optional: true - - '@esbuild/win32-x64@0.27.2': - optional: true - - '@eslint-community/eslint-plugin-eslint-comments@4.6.0(eslint@9.39.2(jiti@2.6.1))': - dependencies: - escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - ignore: 7.0.5 - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': - dependencies: - eslint: 9.39.2(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint-react/ast@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@eslint-react/core@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - birecord: 0.1.1 - eslint: 9.39.2(jiti@2.6.1) - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@eslint-react/eff@2.7.2': {} - - '@eslint-react/eslint-plugin@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-react-dom: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-hooks-extra: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-naming-convention: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-web-api: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-x: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@eslint-react/shared@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - ts-pattern: 5.9.0 - typescript: 5.9.3 - zod: 4.3.5 - transitivePeerDependencies: - - supports-color - - '@eslint-react/var@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@eslint/compat@1.4.1(eslint@9.39.2(jiti@2.6.1))': - dependencies: - '@eslint/core': 0.17.0 - optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) - - '@eslint/config-array@0.21.1': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.3': - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.2': {} - - '@eslint/markdown@7.5.1': - dependencies: - '@eslint/core': 0.17.0 - '@eslint/plugin-kit': 0.4.1 - github-slugger: 2.0.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-frontmatter: 2.0.1 - mdast-util-gfm: 3.1.0 - micromark-extension-frontmatter: 2.0.0 - micromark-extension-gfm: 3.0.0 - micromark-util-normalize-identifier: 2.0.1 - transitivePeerDependencies: - - supports-color - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@floating-ui/core@1.7.3': - dependencies: - '@floating-ui/utils': 0.2.10 - - '@floating-ui/dom@1.7.4': - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - - '@floating-ui/react-dom@2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@floating-ui/dom': 1.7.4 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@floating-ui/utils@0.2.10': {} - - '@hookform/resolvers@5.2.2(react-hook-form@7.71.1(react@19.2.3))': - dependencies: - '@standard-schema/utils': 0.3.0 - react-hook-form: 7.71.1(react@19.2.3) - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@marsidev/react-turnstile@1.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@pkgr/core@0.2.9': {} - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-context@1.1.3(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.2(@types/react@19.2.8)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.2(@types/react@19.2.8)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/rect': 1.1.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.2(@types/react@19.2.8)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-slot@1.2.4(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.8)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.8)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.8)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.8 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - - '@radix-ui/rect@1.1.1': {} - - '@rolldown/pluginutils@1.0.0-beta.53': {} - - '@rollup/pluginutils@5.3.0(rollup@4.55.2)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.55.2 - - '@rollup/rollup-android-arm-eabi@4.55.2': - optional: true - - '@rollup/rollup-android-arm64@4.55.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.55.2': - optional: true - - '@rollup/rollup-darwin-x64@4.55.2': - optional: true - - '@rollup/rollup-freebsd-arm64@4.55.2': - optional: true - - '@rollup/rollup-freebsd-x64@4.55.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.55.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.55.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.55.2': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.55.2': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.55.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.55.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.55.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.55.2': - optional: true - - '@rollup/rollup-openbsd-x64@4.55.2': - optional: true - - '@rollup/rollup-openharmony-arm64@4.55.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.55.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.55.2': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.55.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.55.2': - optional: true - - '@sindresorhus/base62@1.0.0': {} - - '@standard-schema/utils@0.3.0': {} - - '@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1))': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/types': 8.53.1 - eslint: 9.39.2(jiti@2.6.1) - eslint-visitor-keys: 5.0.0 - espree: 11.1.0 - estraverse: 5.3.0 - picomatch: 4.0.3 - - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - - '@svgr/babel-preset@8.1.0(@babel/core@7.28.6)': - dependencies: - '@babel/core': 7.28.6 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.6) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.6) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.6) - - '@svgr/core@8.1.0(typescript@5.9.3)': - dependencies: - '@babel/core': 7.28.6 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.6) - camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.9.3) - snake-case: 3.0.4 - transitivePeerDependencies: - - supports-color - - typescript - - '@svgr/hast-util-to-babel-ast@8.0.0': - dependencies: - '@babel/types': 7.28.6 - entities: 4.5.0 - - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': - dependencies: - '@babel/core': 7.28.6 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.6) - '@svgr/core': 8.1.0(typescript@5.9.3) - '@svgr/hast-util-to-babel-ast': 8.0.0 - svg-parser: 2.0.4 - transitivePeerDependencies: - - supports-color - - '@tabler/icons-react@3.36.1(react@19.2.3)': - dependencies: - '@tabler/icons': 3.36.1 - react: 19.2.3 - - '@tabler/icons@3.36.1': {} - - '@tailwindcss/node@4.1.18': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.4 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.18 - - '@tailwindcss/oxide-android-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.18': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide@4.1.18': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 - - '@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)': - dependencies: - postcss-selector-parser: 6.0.10 - tailwindcss: 4.1.18 - - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - - '@tanstack/devtools-event-client@0.4.0': {} - - '@tanstack/eslint-plugin-query@5.91.3(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - transitivePeerDependencies: - - supports-color - - typescript - - '@tanstack/form-core@0.42.1': - dependencies: - '@tanstack/store': 0.7.7 - - '@tanstack/form-core@1.27.7': - dependencies: - '@tanstack/devtools-event-client': 0.4.0 - '@tanstack/pacer-lite': 0.1.1 - '@tanstack/store': 0.7.7 - - '@tanstack/history@1.153.2': {} - - '@tanstack/pacer-lite@0.1.1': {} - - '@tanstack/query-core@5.90.19': {} - - '@tanstack/react-form@1.27.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@tanstack/form-core': 1.27.7 - '@tanstack/react-store': 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - transitivePeerDependencies: - - react-dom - - '@tanstack/react-query@5.90.19(react@19.2.3)': - dependencies: - '@tanstack/query-core': 5.90.19 - react: 19.2.3 - - '@tanstack/react-router-devtools@1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@tanstack/router-core@1.153.2)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@tanstack/react-router': 1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/router-devtools-core': 1.153.2(@tanstack/router-core@1.153.2)(csstype@3.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@tanstack/router-core': 1.153.2 - transitivePeerDependencies: - - csstype - - '@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@tanstack/history': 1.153.2 - '@tanstack/react-store': 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@tanstack/router-core': 1.153.2 - isbot: 5.1.33 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/react-store@0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@tanstack/store': 0.8.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) - - '@tanstack/react-table@8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@tanstack/table-core': 8.21.3 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - '@tanstack/router-core@1.153.2': - dependencies: - '@tanstack/history': 1.153.2 - '@tanstack/store': 0.8.0 - cookie-es: 2.0.0 - seroval: 1.4.2 - seroval-plugins: 1.4.2(seroval@1.4.2) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 - - '@tanstack/router-devtools-core@1.153.2(@tanstack/router-core@1.153.2)(csstype@3.2.3)': - dependencies: - '@tanstack/router-core': 1.153.2 - clsx: 2.1.1 - goober: 2.1.18(csstype@3.2.3) - tiny-invariant: 1.3.3 - optionalDependencies: - csstype: 3.2.3 - - '@tanstack/router-generator@1.153.2': - dependencies: - '@tanstack/router-core': 1.153.2 - '@tanstack/router-utils': 1.143.11 - '@tanstack/virtual-file-routes': 1.145.4 - prettier: 3.8.0 - recast: 0.23.11 - source-map: 0.7.6 - tsx: 4.21.0 - zod: 3.25.76 - transitivePeerDependencies: - - supports-color - - '@tanstack/router-plugin@1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) - '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - '@tanstack/router-core': 1.153.2 - '@tanstack/router-generator': 1.153.2 - '@tanstack/router-utils': 1.143.11 - '@tanstack/virtual-file-routes': 1.145.4 - babel-dead-code-elimination: 1.0.12 - chokidar: 3.6.0 - unplugin: 2.3.11 - zod: 3.25.76 - optionalDependencies: - '@tanstack/react-router': 1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - - '@tanstack/router-utils@1.143.11': - dependencies: - '@babel/core': 7.28.6 - '@babel/generator': 7.28.6 - '@babel/parser': 7.28.6 - ansis: 4.2.0 - diff: 8.0.3 - pathe: 2.0.3 - tinyglobby: 0.2.15 - transitivePeerDependencies: - - supports-color - - '@tanstack/store@0.7.7': {} - - '@tanstack/store@0.8.0': {} - - '@tanstack/table-core@8.21.3': {} - - '@tanstack/virtual-file-routes@1.145.4': {} - - '@tanstack/zod-adapter@1.153.2(@tanstack/react-router@1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(zod@4.3.5)': - dependencies: - '@tanstack/react-router': 1.153.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: 4.3.5 - - '@tanstack/zod-form-adapter@0.42.1(zod@4.3.5)': - dependencies: - '@tanstack/form-core': 0.42.1 - zod: 4.3.5 - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.6 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.6 - - '@types/base-64@1.0.2': {} - - '@types/culori@4.0.1': {} - - '@types/d3-array@3.2.2': {} - - '@types/d3-color@3.1.3': {} - - '@types/d3-ease@3.0.2': {} - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-path@3.1.1': {} - - '@types/d3-scale@4.0.9': - dependencies: - '@types/d3-time': 3.0.4 - - '@types/d3-shape@3.1.8': - dependencies: - '@types/d3-path': 3.1.1 - - '@types/d3-time@3.0.4': {} - - '@types/d3-timer@3.0.2': {} - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 2.1.0 - - '@types/estree-jsx@1.0.5': - dependencies: - '@types/estree': 1.0.8 - - '@types/estree@1.0.8': {} - - '@types/hast@2.3.10': - dependencies: - '@types/unist': 2.0.11 - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/json-schema@7.0.15': {} - - '@types/lodash-es@4.17.12': - dependencies: - '@types/lodash': 4.17.23 - - '@types/lodash@4.17.23': {} - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/ms@2.1.0': {} - - '@types/node@25.0.9': - dependencies: - undici-types: 7.16.0 - - '@types/prismjs@1.26.5': {} - - '@types/qrcode@1.5.6': - dependencies: - '@types/node': 25.0.9 - - '@types/react-dom@19.2.3(@types/react@19.2.8)': - dependencies: - '@types/react': 19.2.8 - - '@types/react@19.2.8': - dependencies: - csstype: 3.2.3 - - '@types/unist@2.0.11': {} - - '@types/unist@3.0.3': {} - - '@types/utf8@3.0.3': {} - - '@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.1 - eslint: 9.39.2(jiti@2.6.1) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.1 - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.53.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.53.1(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.53.1': - dependencies: - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/visitor-keys': 8.53.1 - - '@typescript-eslint/tsconfig-utils@8.53.1(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.53.1': {} - - '@typescript-eslint/typescript-estree@8.53.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.53.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.53.1(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/visitor-keys': 8.53.1 - debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.53.1': - dependencies: - '@typescript-eslint/types': 8.53.1 - eslint-visitor-keys: 4.2.1 - - '@uiw/copy-to-clipboard@1.0.19': {} - - '@uiw/react-markdown-preview@5.1.5(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@babel/runtime': 7.28.6 - '@uiw/copy-to-clipboard': 1.0.19 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-markdown: 9.0.3(@types/react@19.2.8)(react@19.2.3) - rehype-attr: 3.0.3 - rehype-autolink-headings: 7.1.0 - rehype-ignore: 2.0.3 - rehype-prism-plus: 2.0.0 - rehype-raw: 7.0.0 - rehype-rewrite: 4.0.4 - rehype-slug: 6.0.0 - remark-gfm: 4.0.1 - remark-github-blockquote-alert: 1.3.1 - unist-util-visit: 5.0.0 - transitivePeerDependencies: - - '@types/react' - - supports-color - - '@uiw/react-md-editor@4.0.11(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@babel/runtime': 7.28.6 - '@uiw/react-markdown-preview': 5.1.5(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - rehype: 13.0.2 - rehype-prism-plus: 2.0.1 - transitivePeerDependencies: - - '@types/react' - - supports-color - - '@ungap/structured-clone@1.3.0': {} - - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) - '@rolldown/pluginutils': 1.0.0-beta.53 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - - '@vitest/eslint-plugin@1.6.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@vue/compiler-core@3.5.27': - dependencies: - '@babel/parser': 7.28.6 - '@vue/shared': 3.5.27 - entities: 7.0.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - - '@vue/compiler-dom@3.5.27': - dependencies: - '@vue/compiler-core': 3.5.27 - '@vue/shared': 3.5.27 - - '@vue/compiler-sfc@3.5.27': - dependencies: - '@babel/parser': 7.28.6 - '@vue/compiler-core': 3.5.27 - '@vue/compiler-dom': 3.5.27 - '@vue/compiler-ssr': 3.5.27 - '@vue/shared': 3.5.27 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.6 - source-map-js: 1.2.1 - - '@vue/compiler-ssr@3.5.27': - dependencies: - '@vue/compiler-dom': 3.5.27 - '@vue/shared': 3.5.27 - - '@vue/shared@3.5.27': {} - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - - acorn@8.15.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 - - ansi-escapes@7.2.0: - dependencies: - environment: 1.1.0 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.3: {} - - ansis@4.2.0: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - are-docs-informative@0.0.2: {} - - argparse@2.0.1: {} - - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - - asynckit@0.4.0: {} - - axios@1.13.2: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - babel-dead-code-elimination@1.0.12: - dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 - transitivePeerDependencies: - - supports-color - - bail@2.0.2: {} - - balanced-match@1.0.2: {} - - base-64@1.0.0: {} - - base64-js@1.5.1: {} - - baseline-browser-mapping@2.9.15: {} - - bcp-47-match@2.0.3: {} - - binary-extensions@2.3.0: {} - - birecord@0.1.1: {} - - boolbase@1.0.0: {} - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.9.15 - caniuse-lite: 1.0.30001765 - electron-to-chromium: 1.5.267 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - builtin-modules@5.0.0: {} - - cac@6.7.14: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - callsites@3.1.0: {} - - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001765: {} - - ccount@2.0.1: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - change-case@5.4.4: {} - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - character-reference-invalid@2.0.1: {} - - 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 - - ci-info@4.3.1: {} - - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - - clean-regexp@1.0.0: - dependencies: - escape-string-regexp: 1.0.5 - - cli-cursor@5.0.0: - dependencies: - restore-cursor: 5.1.0 - - cli-truncate@5.1.1: - dependencies: - slice-ansi: 7.1.2 - string-width: 8.1.0 - - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - - clsx@2.1.1: {} - - 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 - - comma-separated-tokens@2.0.3: {} - - commander@14.0.2: {} - - comment-parser@1.4.1: {} - - comment-parser@1.4.4: {} - - compare-versions@6.1.1: {} - - concat-map@0.0.1: {} - - confbox@0.1.8: {} - - confbox@0.2.2: {} - - convert-source-map@2.0.0: {} - - cookie-es@2.0.0: {} - - core-js-compat@3.47.0: - dependencies: - browserslist: 4.28.1 - - cosmiconfig@8.3.6(typescript@5.9.3): - dependencies: - import-fresh: 3.3.1 - js-yaml: 4.1.1 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 5.9.3 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - css-selector-parser@3.3.0: {} - - cssesc@3.0.0: {} - - csstype@3.2.3: {} - - culori@4.0.2: {} - - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-color@3.1.0: {} - - d3-ease@3.0.1: {} - - d3-format@3.1.2: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@3.1.0: {} - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - 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: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decamelize@1.2.0: {} - - decimal.js-light@2.5.1: {} - - decode-named-character-reference@1.3.0: - dependencies: - character-entities: 2.0.2 - - deep-is@0.1.4: {} - - delayed-stream@1.0.0: {} - - dequal@2.0.3: {} - - detect-libc@2.1.2: {} - - detect-node-es@1.1.0: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - diff-sequences@27.5.1: {} - - diff@8.0.3: {} - - dijkstrajs@1.0.3: {} - - direction@2.0.1: {} - - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.28.6 - csstype: 3.2.3 - - dot-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - electron-to-chromium@1.5.267: {} - - emoji-regex@10.6.0: {} - - emoji-regex@8.0.0: {} - - empathic@2.0.0: {} - - enhanced-resolve@5.18.4: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - entities@4.5.0: {} - - entities@6.0.1: {} - - entities@7.0.0: {} - - environment@1.1.0: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.27.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.2 - '@esbuild/android-arm': 0.27.2 - '@esbuild/android-arm64': 0.27.2 - '@esbuild/android-x64': 0.27.2 - '@esbuild/darwin-arm64': 0.27.2 - '@esbuild/darwin-x64': 0.27.2 - '@esbuild/freebsd-arm64': 0.27.2 - '@esbuild/freebsd-x64': 0.27.2 - '@esbuild/linux-arm': 0.27.2 - '@esbuild/linux-arm64': 0.27.2 - '@esbuild/linux-ia32': 0.27.2 - '@esbuild/linux-loong64': 0.27.2 - '@esbuild/linux-mips64el': 0.27.2 - '@esbuild/linux-ppc64': 0.27.2 - '@esbuild/linux-riscv64': 0.27.2 - '@esbuild/linux-s390x': 0.27.2 - '@esbuild/linux-x64': 0.27.2 - '@esbuild/netbsd-arm64': 0.27.2 - '@esbuild/netbsd-x64': 0.27.2 - '@esbuild/openbsd-arm64': 0.27.2 - '@esbuild/openbsd-x64': 0.27.2 - '@esbuild/openharmony-arm64': 0.27.2 - '@esbuild/sunos-x64': 0.27.2 - '@esbuild/win32-arm64': 0.27.2 - '@esbuild/win32-ia32': 0.27.2 - '@esbuild/win32-x64': 0.27.2 - - escalade@3.2.0: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - escape-string-regexp@5.0.0: {} - - eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - semver: 7.7.3 - - eslint-compat-utils@0.6.5(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - semver: 7.7.3 - - eslint-config-flat-gitignore@2.1.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) - - eslint-flat-config-utils@2.1.4: - dependencies: - pathe: 2.0.3 - - eslint-json-compat-utils@0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - esquery: 1.7.0 - jsonc-eslint-parser: 2.4.2 - - eslint-merge-processors@2.0.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - - eslint-plugin-antfu@3.1.3(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - - eslint-plugin-command@3.4.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@es-joy/jsdoccomment': 0.78.0 - eslint: 9.39.2(jiti@2.6.1) - - eslint-plugin-es-x@7.8.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) - - eslint-plugin-import-lite@0.4.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - optionalDependencies: - typescript: 5.9.3 - - eslint-plugin-jsdoc@61.7.1(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@es-joy/jsdoccomment': 0.78.0 - '@es-joy/resolve.exports': 1.2.0 - are-docs-informative: 0.0.2 - comment-parser: 1.4.1 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - espree: 11.1.0 - esquery: 1.7.0 - html-entities: 2.6.0 - object-deep-merge: 2.0.0 - parse-imports-exports: 0.2.4 - semver: 7.7.3 - spdx-expression-parse: 4.0.0 - to-valid-identifier: 1.0.0 - transitivePeerDependencies: - - supports-color - - eslint-plugin-jsonc@2.21.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - diff-sequences: 27.5.1 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - eslint-json-compat-utils: 0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2) - espree: 10.4.0 - graphemer: 1.4.0 - jsonc-eslint-parser: 2.4.2 - natural-compare: 1.4.0 - synckit: 0.11.12 - transitivePeerDependencies: - - '@eslint/json' - - eslint-plugin-n@17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - enhanced-resolve: 5.18.4 - eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) - get-tsconfig: 4.13.0 - globals: 15.15.0 - globrex: 0.1.2 - ignore: 5.3.2 - semver: 7.7.3 - ts-declaration-location: 1.0.7(typescript@5.9.3) - transitivePeerDependencies: - - typescript - - eslint-plugin-no-only-tests@3.3.0: {} - - eslint-plugin-perfectionist@4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - natural-orderby: 5.0.0 - transitivePeerDependencies: - - supports-color - - typescript - - eslint-plugin-pnpm@1.5.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - empathic: 2.0.0 - eslint: 9.39.2(jiti@2.6.1) - jsonc-eslint-parser: 2.4.2 - pathe: 2.0.3 - pnpm-workspace-yaml: 1.5.0 - tinyglobby: 0.2.15 - yaml: 2.8.2 - yaml-eslint-parser: 2.0.0 - - eslint-plugin-react-dom@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - compare-versions: 6.1.1 - eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-hooks-extra@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 - eslint: 9.39.2(jiti@2.6.1) - hermes-parser: 0.25.1 - zod: 4.3.5 - zod-validation-error: 4.0.2(zod@4.3.5) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-naming-convention@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - compare-versions: 6.1.1 - eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-refresh@0.4.26(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - - eslint-plugin-react-web-api@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-react-x@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.1 - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.1 - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - compare-versions: 6.1.1 - eslint: 9.39.2(jiti@2.6.1) - is-immutable-type: 5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - string-ts: 2.3.1 - ts-api-utils: 2.4.0(typescript@5.9.3) - ts-pattern: 5.9.0 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - comment-parser: 1.4.4 - eslint: 9.39.2(jiti@2.6.1) - jsdoc-type-pratt-parser: 4.8.0 - refa: 0.12.1 - regexp-ast-analysis: 0.7.1 - scslre: 0.3.0 - - eslint-plugin-toml@0.12.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - lodash: 4.17.21 - toml-eslint-parser: 0.10.1 - transitivePeerDependencies: - - supports-color - - eslint-plugin-unicorn@62.0.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@eslint/plugin-kit': 0.4.1 - change-case: 5.4.4 - ci-info: 4.3.1 - clean-regexp: 1.0.0 - core-js-compat: 3.47.0 - eslint: 9.39.2(jiti@2.6.1) - esquery: 1.7.0 - find-up-simple: 1.0.1 - globals: 16.5.0 - indent-string: 5.0.0 - is-builtin-module: 5.0.0 - jsesc: 3.1.0 - pluralize: 8.0.0 - regexp-tree: 0.1.27 - regjsparser: 0.13.0 - semver: 7.7.3 - strip-indent: 4.1.1 - - eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): - dependencies: - eslint: 9.39.2(jiti@2.6.1) - optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - - eslint-plugin-vue@10.7.0(@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1)))(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - eslint: 9.39.2(jiti@2.6.1) - natural-compare: 1.4.0 - nth-check: 2.1.1 - postcss-selector-parser: 7.1.1 - semver: 7.7.3 - vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) - xml-name-validator: 4.0.0 - optionalDependencies: - '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - - eslint-plugin-yml@1.19.1(eslint@9.39.2(jiti@2.6.1)): - dependencies: - debug: 4.4.3 - diff-sequences: 27.5.1 - escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@2.6.1) - eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) - natural-compare: 1.4.0 - yaml-eslint-parser: 1.3.2 - transitivePeerDependencies: - - supports-color - - eslint-processor-vue-blocks@2.0.0(@vue/compiler-sfc@3.5.27)(eslint@9.39.2(jiti@2.6.1)): - dependencies: - '@vue/compiler-sfc': 3.5.27 - eslint: 9.39.2(jiti@2.6.1) - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint-visitor-keys@5.0.0: {} - - eslint@9.39.2(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - - espree@11.1.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 5.0.0 - - espree@9.6.1: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 - - esprima@4.0.1: {} - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-util-is-identifier-name@3.0.0: {} - - estree-walker@2.0.2: {} - - esutils@2.0.3: {} - - eventemitter3@4.0.7: {} - - eventemitter3@5.0.4: {} - - exsolve@1.0.8: {} - - extend@3.0.2: {} - - fast-deep-equal@3.1.3: {} - - fast-equals@5.4.0: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fault@2.0.1: - dependencies: - format: 0.2.2 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up-simple@1.0.1: {} - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - - flatted@3.3.3: {} - - follow-redirects@1.15.11: {} - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - format@0.2.2: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-east-asian-width@1.4.0: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-nonce@1.0.1: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-tsconfig@4.13.0: - dependencies: - resolve-pkg-maps: 1.0.0 - - github-slugger@2.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - globals@14.0.0: {} - - globals@15.15.0: {} - - globals@16.5.0: {} - - globrex@0.1.2: {} - - goober@2.1.18(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - graphemer@1.4.0: {} - - has-flag@4.0.0: {} - - 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 - - hast-util-from-html@2.0.3: - dependencies: - '@types/hast': 3.0.4 - devlop: 1.1.0 - hast-util-from-parse5: 8.0.3 - parse5: 7.3.0 - vfile: 6.0.3 - vfile-message: 4.0.3 - - hast-util-from-parse5@8.0.3: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - devlop: 1.1.0 - hastscript: 9.0.1 - property-information: 7.1.0 - vfile: 6.0.3 - vfile-location: 5.0.3 - web-namespaces: 2.0.1 - - hast-util-has-property@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-heading-rank@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-is-element@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-parse-selector@3.1.1: - dependencies: - '@types/hast': 2.3.10 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-raw@9.1.0: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - '@ungap/structured-clone': 1.3.0 - hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.1 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - parse5: 7.3.0 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-select@6.0.4: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - bcp-47-match: 2.0.3 - comma-separated-tokens: 2.0.3 - css-selector-parser: 3.3.0 - devlop: 1.1.0 - direction: 2.0.1 - hast-util-has-property: 3.0.0 - hast-util-to-string: 3.0.1 - hast-util-whitespace: 3.0.0 - nth-check: 2.1.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - unist-util-visit: 5.0.0 - zwitch: 2.0.4 - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-to-jsx-runtime@2.3.6: - dependencies: - '@types/estree': 1.0.8 - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - style-to-js: 1.1.21 - unist-util-position: 5.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - hast-util-to-parse5@8.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-to-string@3.0.1: - dependencies: - '@types/hast': 3.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hastscript@7.2.0: - dependencies: - '@types/hast': 2.3.10 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 3.1.1 - property-information: 6.5.0 - space-separated-tokens: 2.0.2 - - hastscript@9.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - - hermes-estree@0.25.1: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - html-entities@2.6.0: {} - - html-url-attributes@3.0.1: {} - - html-void-elements@3.0.0: {} - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - immer@11.1.3: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - indent-string@5.0.0: {} - - inline-style-parser@0.2.7: {} - - internmap@2.0.3: {} - - is-alphabetical@2.0.1: {} - - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - - is-arrayish@0.2.1: {} - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-builtin-module@5.0.0: - dependencies: - builtin-modules: 5.0.0 - - is-decimal@2.0.1: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-fullwidth-code-point@5.1.0: - dependencies: - get-east-asian-width: 1.4.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-hexadecimal@2.0.1: {} - - is-immutable-type@5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@typescript-eslint/type-utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) - ts-declaration-location: 1.0.7(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - is-number@7.0.0: {} - - is-plain-obj@4.1.0: {} - - isbot@5.1.33: {} - - isexe@2.0.0: {} - - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsdoc-type-pratt-parser@4.8.0: {} - - jsdoc-type-pratt-parser@7.0.0: {} - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - jsonc-eslint-parser@2.4.2: - dependencies: - acorn: 8.15.0 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - semver: 7.7.3 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lightningcss-android-arm64@1.30.2: - optional: true - - lightningcss-darwin-arm64@1.30.2: - optional: true - - lightningcss-darwin-x64@1.30.2: - optional: true - - lightningcss-freebsd-x64@1.30.2: - optional: true - - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - - lightningcss-linux-arm64-musl@1.30.2: - optional: true - - lightningcss-linux-x64-gnu@1.30.2: - optional: true - - lightningcss-linux-x64-musl@1.30.2: - optional: true - - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - - lightningcss-win32-x64-msvc@1.30.2: - optional: true - - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - - lines-and-columns@1.2.4: {} - - lint-staged@16.2.7: - dependencies: - commander: 14.0.2 - listr2: 9.0.5 - micromatch: 4.0.8 - nano-spawn: 2.0.0 - pidtree: 0.6.0 - string-argv: 0.3.2 - yaml: 2.8.2 - - listr2@9.0.5: - dependencies: - cli-truncate: 5.1.1 - colorette: 2.0.20 - eventemitter3: 5.0.4 - log-update: 6.1.0 - rfdc: 1.4.1 - wrap-ansi: 9.0.2 - - local-pkg@1.1.2: - dependencies: - mlly: 1.8.0 - pkg-types: 2.3.0 - quansync: 0.2.11 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash-es@4.17.22: {} - - lodash.merge@4.6.2: {} - - lodash@4.17.21: {} - - log-update@6.1.0: - dependencies: - ansi-escapes: 7.2.0 - cli-cursor: 5.0.0 - slice-ansi: 7.1.2 - strip-ansi: 7.1.2 - wrap-ansi: 9.0.2 - - longest-streak@3.1.0: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lucide-react@0.562.0(react@19.2.3): - dependencies: - react: 19.2.3 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - markdown-table@3.0.4: {} - - math-intrinsics@1.1.0: {} - - mdast-util-find-and-replace@3.0.2: - dependencies: - '@types/mdast': 4.0.4 - escape-string-regexp: 5.0.0 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - mdast-util-from-markdown@2.0.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-decode-string: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - - mdast-util-frontmatter@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - micromark-extension-frontmatter: 2.0.0 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-autolink-literal@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-find-and-replace: 3.0.2 - micromark-util-character: 2.1.1 - - mdast-util-gfm-footnote@2.1.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - micromark-util-normalize-identifier: 2.0.1 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-strikethrough@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-table@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-task-list-item@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm@3.1.0: - dependencies: - mdast-util-from-markdown: 2.0.2 - mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-expression@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-jsx@3.2.0: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - mdast-util-mdxjs-esm@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-phrasing@4.1.0: - dependencies: - '@types/mdast': 4.0.4 - unist-util-is: 6.0.1 - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - - mdast-util-to-markdown@2.1.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - longest-streak: 3.1.0 - mdast-util-phrasing: 4.1.0 - mdast-util-to-string: 4.0.0 - micromark-util-classify-character: 2.0.1 - micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 - zwitch: 2.0.4 - - mdast-util-to-string@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - - micromark-core-commonmark@2.0.3: - dependencies: - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-factory-destination: 2.0.1 - micromark-factory-label: 2.0.1 - micromark-factory-space: 2.0.1 - micromark-factory-title: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-html-tag-name: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-frontmatter@2.0.0: - dependencies: - fault: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-autolink-literal@2.1.0: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-footnote@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-strikethrough@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-table@2.1.1: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-tagfilter@2.0.0: - dependencies: - micromark-util-types: 2.0.2 - - micromark-extension-gfm-task-list-item@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm@3.0.0: - dependencies: - micromark-extension-gfm-autolink-literal: 2.1.0 - micromark-extension-gfm-footnote: 2.1.0 - micromark-extension-gfm-strikethrough: 2.1.0 - micromark-extension-gfm-table: 2.1.1 - micromark-extension-gfm-tagfilter: 2.0.0 - micromark-extension-gfm-task-list-item: 2.1.0 - micromark-util-combine-extensions: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-destination@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-label@2.0.1: - dependencies: - devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-space@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-types: 2.0.2 - - micromark-factory-title@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-whitespace@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-chunked@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-classify-character@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-combine-extensions@2.0.1: - dependencies: - micromark-util-chunked: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-decode-numeric-character-reference@2.0.2: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-decode-string@2.0.1: - dependencies: - decode-named-character-reference: 1.3.0 - micromark-util-character: 2.1.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-symbol: 2.0.1 - - micromark-util-encode@2.0.1: {} - - micromark-util-html-tag-name@2.0.1: {} - - micromark-util-normalize-identifier@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-resolve-all@2.0.1: - dependencies: - micromark-util-types: 2.0.2 - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-subtokenize@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - micromark@4.0.2: - dependencies: - '@types/debug': 4.1.12 - debug: 4.4.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-combine-extensions: 2.0.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-encode: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - transitivePeerDependencies: - - supports-color - - 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 - - mimic-function@5.0.1: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - mlly@1.8.0: - dependencies: - acorn: 8.15.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - - ms@2.1.3: {} - - nano-spawn@2.0.0: {} - - nanoid@3.3.11: {} - - natural-compare@1.4.0: {} - - natural-orderby@5.0.0: {} - - next-themes@0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - - node-releases@2.0.27: {} - - normalize-path@3.0.0: {} - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - object-assign@4.1.1: {} - - object-deep-merge@2.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 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-try@2.2.0: {} - - package-manager-detector@1.6.0: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-entities@4.0.2: - dependencies: - '@types/unist': 2.0.11 - character-entities-legacy: 3.0.0 - character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.3.0 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - is-hexadecimal: 2.0.1 - - parse-gitignore@2.0.0: {} - - parse-imports-exports@0.2.4: - dependencies: - parse-statements: 1.0.11 - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.28.6 - error-ex: 1.3.4 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parse-numeric-range@1.3.0: {} - - parse-statements@1.0.11: {} - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-type@4.0.0: {} - - pathe@2.0.3: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pidtree@0.6.0: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.8.0 - pathe: 2.0.3 - - pkg-types@2.3.0: - dependencies: - confbox: 0.2.2 - exsolve: 1.0.8 - pathe: 2.0.3 - - pluralize@8.0.0: {} - - pngjs@5.0.0: {} - - pnpm-workspace-yaml@1.5.0: - dependencies: - yaml: 2.8.2 - - postcss-selector-parser@6.0.10: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-selector-parser@7.1.1: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - prettier@3.8.0: {} - - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - - property-information@6.5.0: {} - - property-information@7.1.0: {} - - proxy-from-env@1.1.0: {} - - punycode@2.3.1: {} - - qrcode@1.5.4: - dependencies: - dijkstrajs: 1.0.3 - pngjs: 5.0.0 - yargs: 15.4.1 - - quansync@0.2.11: {} - - react-dom@19.2.3(react@19.2.3): - dependencies: - react: 19.2.3 - scheduler: 0.27.0 - - react-hook-form@7.71.1(react@19.2.3): - dependencies: - react: 19.2.3 - - react-is@16.13.1: {} - - react-is@18.3.1: {} - - react-markdown@10.1.0(@types/react@19.2.8)(react@19.2.3): - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/react': 19.2.8 - devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 - html-url-attributes: 3.0.1 - mdast-util-to-hast: 13.2.1 - react: 19.2.3 - remark-parse: 11.0.0 - remark-rehype: 11.1.2 - unified: 11.0.5 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - - react-markdown@9.0.3(@types/react@19.2.8)(react@19.2.3): - dependencies: - '@types/hast': 3.0.4 - '@types/react': 19.2.8 - devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 - html-url-attributes: 3.0.1 - mdast-util-to-hast: 13.2.1 - react: 19.2.3 - remark-parse: 11.0.0 - remark-rehype: 11.1.2 - unified: 11.0.5 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - - react-refresh@0.18.0: {} - - react-remove-scroll-bar@2.3.8(@types/react@19.2.8)(react@19.2.3): - dependencies: - react: 19.2.3 - react-style-singleton: 2.2.3(@types/react@19.2.8)(react@19.2.3) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.8 - - react-remove-scroll@2.7.2(@types/react@19.2.8)(react@19.2.3): - dependencies: - react: 19.2.3 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.8)(react@19.2.3) - react-style-singleton: 2.2.3(@types/react@19.2.8)(react@19.2.3) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.8)(react@19.2.3) - use-sidecar: 1.1.3(@types/react@19.2.8)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.8 - - react-smooth@4.0.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - fast-equals: 5.4.0 - prop-types: 15.8.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-transition-group: 4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - - react-style-singleton@2.2.3(@types/react@19.2.8)(react@19.2.3): - dependencies: - get-nonce: 1.0.1 - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.8 - - react-transition-group@4.4.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@babel/runtime': 7.28.6 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - react@19.2.3: {} - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - - recharts-scale@0.4.5: - dependencies: - decimal.js-light: 2.5.1 - - recharts@2.15.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - clsx: 2.1.1 - eventemitter3: 4.0.7 - lodash: 4.17.21 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-is: 18.3.1 - react-smooth: 4.0.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - recharts-scale: 0.4.5 - tiny-invariant: 1.3.3 - victory-vendor: 36.9.2 - - refa@0.12.1: - dependencies: - '@eslint-community/regexpp': 4.12.2 - - refractor@4.9.0: - dependencies: - '@types/hast': 2.3.10 - '@types/prismjs': 1.26.5 - hastscript: 7.2.0 - parse-entities: 4.0.2 - - regexp-ast-analysis@0.7.1: - dependencies: - '@eslint-community/regexpp': 4.12.2 - refa: 0.12.1 - - regexp-tree@0.1.27: {} - - regjsparser@0.13.0: - dependencies: - jsesc: 3.1.0 - - rehype-attr@3.0.3: - dependencies: - unified: 11.0.5 - unist-util-visit: 5.0.0 - - rehype-autolink-headings@7.1.0: - dependencies: - '@types/hast': 3.0.4 - '@ungap/structured-clone': 1.3.0 - hast-util-heading-rank: 3.0.0 - hast-util-is-element: 3.0.0 - unified: 11.0.5 - unist-util-visit: 5.0.0 - - rehype-ignore@2.0.3: - dependencies: - hast-util-select: 6.0.4 - unified: 11.0.5 - unist-util-visit: 5.0.0 - - rehype-parse@9.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-from-html: 2.0.3 - unified: 11.0.5 - - rehype-prism-plus@2.0.0: - dependencies: - hast-util-to-string: 3.0.1 - parse-numeric-range: 1.3.0 - refractor: 4.9.0 - rehype-parse: 9.0.1 - unist-util-filter: 5.0.1 - unist-util-visit: 5.0.0 - - rehype-prism-plus@2.0.1: - dependencies: - hast-util-to-string: 3.0.1 - parse-numeric-range: 1.3.0 - refractor: 4.9.0 - rehype-parse: 9.0.1 - unist-util-filter: 5.0.1 - unist-util-visit: 5.0.0 - - rehype-raw@7.0.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-raw: 9.1.0 - vfile: 6.0.3 - - rehype-rewrite@4.0.4: - dependencies: - hast-util-select: 6.0.4 - unified: 11.0.5 - unist-util-visit: 5.0.0 - - rehype-slug@6.0.0: - dependencies: - '@types/hast': 3.0.4 - github-slugger: 2.0.0 - hast-util-heading-rank: 3.0.0 - hast-util-to-string: 3.0.1 - unist-util-visit: 5.0.0 - - rehype-stringify@10.0.1: - dependencies: - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - unified: 11.0.5 - - rehype@13.0.2: - dependencies: - '@types/hast': 3.0.4 - rehype-parse: 9.0.1 - rehype-stringify: 10.0.1 - unified: 11.0.5 - - remark-gfm@4.0.1: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 - micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-github-blockquote-alert@1.3.1: - dependencies: - unist-util-visit: 5.0.0 - - remark-parse@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 - micromark-util-types: 2.0.2 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-rehype@11.1.2: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - mdast-util-to-hast: 13.2.1 - unified: 11.0.5 - vfile: 6.0.3 - - remark-stringify@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-to-markdown: 2.1.2 - unified: 11.0.5 - - require-directory@2.1.1: {} - - require-main-filename@2.0.0: {} - - reserved-identifiers@1.2.0: {} - - resolve-from@4.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - restore-cursor@5.1.0: - dependencies: - onetime: 7.0.0 - signal-exit: 4.1.0 - - rfdc@1.4.1: {} - - rollup@4.55.2: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.55.2 - '@rollup/rollup-android-arm64': 4.55.2 - '@rollup/rollup-darwin-arm64': 4.55.2 - '@rollup/rollup-darwin-x64': 4.55.2 - '@rollup/rollup-freebsd-arm64': 4.55.2 - '@rollup/rollup-freebsd-x64': 4.55.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.55.2 - '@rollup/rollup-linux-arm-musleabihf': 4.55.2 - '@rollup/rollup-linux-arm64-gnu': 4.55.2 - '@rollup/rollup-linux-arm64-musl': 4.55.2 - '@rollup/rollup-linux-loong64-gnu': 4.55.2 - '@rollup/rollup-linux-loong64-musl': 4.55.2 - '@rollup/rollup-linux-ppc64-gnu': 4.55.2 - '@rollup/rollup-linux-ppc64-musl': 4.55.2 - '@rollup/rollup-linux-riscv64-gnu': 4.55.2 - '@rollup/rollup-linux-riscv64-musl': 4.55.2 - '@rollup/rollup-linux-s390x-gnu': 4.55.2 - '@rollup/rollup-linux-x64-gnu': 4.55.2 - '@rollup/rollup-linux-x64-musl': 4.55.2 - '@rollup/rollup-openbsd-x64': 4.55.2 - '@rollup/rollup-openharmony-arm64': 4.55.2 - '@rollup/rollup-win32-arm64-msvc': 4.55.2 - '@rollup/rollup-win32-ia32-msvc': 4.55.2 - '@rollup/rollup-win32-x64-gnu': 4.55.2 - '@rollup/rollup-win32-x64-msvc': 4.55.2 - fsevents: 2.3.3 - - scheduler@0.27.0: {} - - scslre@0.3.0: - dependencies: - '@eslint-community/regexpp': 4.12.2 - refa: 0.12.1 - regexp-ast-analysis: 0.7.1 - - semver@6.3.1: {} - - semver@7.7.3: {} - - seroval-plugins@1.4.2(seroval@1.4.2): - dependencies: - seroval: 1.4.2 - - seroval@1.4.2: {} - - set-blocking@2.0.0: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - signal-exit@4.1.0: {} - - simple-git-hooks@2.13.1: {} - - sisteransi@1.0.5: {} - - slice-ansi@7.1.2: - dependencies: - ansi-styles: 6.2.3 - is-fullwidth-code-point: 5.1.0 - - snake-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 - - sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - - source-map-js@1.2.1: {} - - source-map@0.6.1: {} - - source-map@0.7.6: {} - - space-separated-tokens@2.0.2: {} - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@4.0.0: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.22 - - spdx-license-ids@3.0.22: {} - - string-argv@0.3.2: {} - - string-ts@2.3.1: {} - - 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@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 - - string-width@8.1.0: - dependencies: - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.2: - dependencies: - ansi-regex: 6.2.2 - - strip-indent@4.1.1: {} - - strip-json-comments@3.1.1: {} - - style-to-js@1.1.21: - dependencies: - style-to-object: 1.0.14 - - style-to-object@1.0.14: - dependencies: - inline-style-parser: 0.2.7 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - svg-parser@2.0.4: {} - - synckit@0.11.12: - dependencies: - '@pkgr/core': 0.2.9 - - tagged-tag@1.0.0: {} - - tailwind-merge@3.4.0: {} - - tailwindcss@4.1.18: {} - - tapable@2.3.0: {} - - tiny-invariant@1.3.3: {} - - tiny-warning@1.0.3: {} - - tinyexec@1.0.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - to-valid-identifier@1.0.0: - dependencies: - '@sindresorhus/base62': 1.0.0 - reserved-identifiers: 1.2.0 - - toml-eslint-parser@0.10.1: - dependencies: - eslint-visitor-keys: 3.4.3 - - trim-lines@3.0.1: {} - - trough@2.2.0: {} - - ts-api-utils@2.4.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - ts-declaration-location@1.0.7(typescript@5.9.3): - dependencies: - picomatch: 4.0.3 - typescript: 5.9.3 - - ts-pattern@5.9.0: {} - - tslib@2.8.1: {} - - tsx@4.21.0: - dependencies: - esbuild: 0.27.2 - get-tsconfig: 4.13.0 - optionalDependencies: - fsevents: 2.3.3 - - tw-animate-css@1.4.0: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@5.4.1: - dependencies: - tagged-tag: 1.0.0 - - typescript-eslint@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.53.1(@typescript-eslint/parser@8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.53.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - ufo@1.6.3: {} - - undici-types@7.16.0: {} - - unified@11.0.5: - dependencies: - '@types/unist': 3.0.3 - bail: 2.0.2 - devlop: 1.1.0 - extend: 3.0.2 - is-plain-obj: 4.1.0 - trough: 2.2.0 - vfile: 6.0.3 - - unist-util-filter@5.0.1: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.0.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - unplugin@2.3.11: - dependencies: - '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 - picomatch: 4.0.3 - webpack-virtual-modules: 0.6.2 - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-callback-ref@1.3.3(@types/react@19.2.8)(react@19.2.3): - dependencies: - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.8 - - use-sidecar@1.1.3(@types/react@19.2.8)(react@19.2.3): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.8 - - use-sync-external-store@1.6.0(react@19.2.3): - dependencies: - react: 19.2.3 - - utf8@3.0.0: {} - - util-deprecate@1.0.2: {} - - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - vfile-location@5.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile: 6.0.3 - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - victory-vendor@36.9.2: - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-ease': 3.0.2 - '@types/d3-interpolate': 3.0.4 - '@types/d3-scale': 4.0.9 - '@types/d3-shape': 3.1.8 - '@types/d3-time': 3.0.4 - '@types/d3-timer': 3.0.2 - d3-array: 3.2.4 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-scale: 4.0.2 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-timer: 3.0.1 - - vite-plugin-svgr@4.5.0(rollup@4.55.2)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2)): - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.55.2) - '@svgr/core': 8.1.0(typescript@5.9.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2) - transitivePeerDependencies: - - rollup - - supports-color - - typescript - - vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.55.2 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.0.9 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - tsx: 4.21.0 - yaml: 2.8.2 - - vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): - dependencies: - debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - semver: 7.7.3 - transitivePeerDependencies: - - supports-color - - web-namespaces@2.0.1: {} - - webpack-virtual-modules@0.6.2: {} - - which-module@2.0.1: {} - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - 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@9.0.2: - dependencies: - ansi-styles: 6.2.3 - string-width: 7.2.0 - strip-ansi: 7.1.2 - - xml-name-validator@4.0.0: {} - - y18n@4.0.3: {} - - yallist@3.1.1: {} - - yaml-eslint-parser@1.3.2: - dependencies: - eslint-visitor-keys: 3.4.3 - yaml: 2.8.2 - - yaml-eslint-parser@2.0.0: - dependencies: - eslint-visitor-keys: 5.0.0 - yaml: 2.8.2 - - yaml@2.8.2: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - - yocto-queue@0.1.0: {} - - zod-validation-error@4.0.2(zod@4.3.5): - dependencies: - zod: 4.3.5 - - zod@3.25.76: {} - - zod@4.3.5: {} - - zustand@5.0.10(@types/react@19.2.8)(immer@11.1.3)(react@19.2.3)(use-sync-external-store@1.6.0(react@19.2.3)): - optionalDependencies: - '@types/react': 19.2.8 - immer: 11.1.3 - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) - - zwitch@2.0.4: {} diff --git a/client/cms/src/App.tsx b/client/cms/src/App.tsx deleted file mode 100644 index 71c1efb..0000000 --- a/client/cms/src/App.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { ThemeProvider } from '@/components/theme-provider'; - -function App() { - return ( - -

Hello world

-
- ); -} - -export { App }; diff --git a/client/cms/src/assets/nixos.svg b/client/cms/src/assets/nixos.svg deleted file mode 100644 index 92f670b..0000000 --- a/client/cms/src/assets/nixos.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/cms/src/components/checkin/qr-dialog.tsx b/client/cms/src/components/checkin/qr-dialog.tsx deleted file mode 100644 index f4bb318..0000000 --- a/client/cms/src/components/checkin/qr-dialog.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { useState } from 'react'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@/components/ui/dialog'; -import { QRCode } from '@/components/ui/shadcn-io/qr-code'; -import { useCheckinCode } from '@/hooks/data/useGetCheckInCode'; -import { Button } from '../ui/button'; - -export function QrDialog( - { eventId }: { eventId: string }, -) { - const [open, setOpen] = useState(false); - return ( - - - - - - - QR Code - - 请工作人员扫描下面的二维码为你签到。 - - - - - - ); -} - -function QrSection({ eventId, enabled }: { eventId: string; enabled: boolean }) { - const { data } = useCheckinCode(eventId, enabled); - return data - ? ( - <> -
- -
- -
- {data.data.checkin_code} -
-
- - ) - : ( - - ); -} - -function QrSectionSkeleton() { - return ( - <> -
- -
- -
- Loading... -
-
- - ); -} diff --git a/client/cms/src/components/hoc/with-fallback.tsx b/client/cms/src/components/hoc/with-fallback.tsx deleted file mode 100644 index 5d4c0e6..0000000 --- a/client/cms/src/components/hoc/with-fallback.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { ReactNode } from 'react'; -import React, { Suspense } from 'react'; - -export function withFallback

( - Component: React.ComponentType

, - fallback: ReactNode, -) { - const Wrapped: React.FC

= (props) => { - return ( - - - - ); - }; - - Wrapped.displayName = `withFallback(${Component.displayName! || Component.name || 'Component' - })`; - - return Wrapped; -} diff --git a/client/cms/src/components/login-form.tsx b/client/cms/src/components/login-form.tsx deleted file mode 100644 index 8ef955b..0000000 --- a/client/cms/src/components/login-form.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import type { TurnstileInstance } from '@marsidev/react-turnstile'; -import type { AuthorizeSearchParams } from '@/routes/authorize'; -import { Turnstile } from '@marsidev/react-turnstile'; -import { useNavigate } from '@tanstack/react-router'; -import { useRef, useState } from 'react'; -import { toast } from 'sonner'; -import NixOSLogo from '@/assets/nixos.svg?react'; -import { Button } from '@/components/ui/button'; -import { - Field, - FieldGroup, - FieldLabel, -} from '@/components/ui/field'; -import { Input } from '@/components/ui/input'; -import { useGetMagicLink } from '@/hooks/data/useGetMagicLink'; -import { cn } from '@/lib/utils'; - -export function LoginForm({ - oauthParams, - className, - ...props -}: React.ComponentProps<'div'> & { - oauthParams: AuthorizeSearchParams; -}) { - const formRef = useRef(null); - const turnstileRef = useRef(null); - const [token, setToken] = useState(null); - const { mutateAsync, isPending } = useGetMagicLink(); - const navigate = useNavigate(); - - const handleSubmit = (event: React.FormEvent) => { - event.preventDefault(); - const formData = new FormData(formRef.current!); - const email = formData.get('email')! as string; - mutateAsync({ email, turnstile_token: token!, ...oauthParams }).then(() => { - void navigate({ to: '/magicLinkSent', search: { email } }); - }).catch((error) => { - console.error(error); - toast.error('请求登录链接失败'); - turnstileRef.current?.reset(); - }); - }; - - return ( -

-
- -
-
- -
- Nix CN Meetup #2 -

欢迎来到 Nix CN Meetup #2

-
- - 参会登记Email - - - - - -
-
- { - setToken(token); - }} - /> -
- ); -} diff --git a/client/cms/src/components/profile/edit-profile-dialog.tsx b/client/cms/src/components/profile/edit-profile-dialog.tsx deleted file mode 100644 index e9efd34..0000000 --- a/client/cms/src/components/profile/edit-profile-dialog.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { useForm } from '@tanstack/react-form'; -import { toast } from 'sonner'; -import z from 'zod'; -import { Button } from '@/components/ui/button'; -import { - Dialog, - DialogClose, - DialogContent, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@/components/ui/dialog'; -import { - Field, - FieldError, - FieldLabel, -} from '@/components/ui/field'; -import { - Input, -} from '@/components/ui/input'; -import { useUpdateUser } from '@/hooks/data/useUpdateUser'; -import { useUserInfo } from '@/hooks/data/useUserInfo'; - -const formSchema = z.object({ - username: z.string().min(5), - nickname: z.string().min(1), - subtitle: z.string().min(1), - avatar: z.url().min(1), -}); -export function EditProfileDialog() { - const { data: user } = useUserInfo(); - const { mutateAsync } = useUpdateUser(); - - const form = useForm({ - defaultValues: { - avatar: user.avatar, - username: user.username, - nickname: user.nickname, - subtitle: user.subtitle, - }, - validators: { - onBlur: formSchema, - }, - onSubmit: async ({ - value, - }) => { - try { - await mutateAsync(value); - toast.success('个人资料更新成功'); - } - catch (error) { - console.error('Form submission error', error); - toast.error('更新个人资料失败,请重试'); - } - }, - }); - - return ( - - - - - -
{ - e.preventDefault(); - e.stopPropagation(); - void form.handleSubmit(); - }} - className="grid gap-4" - > - - 编辑个人资料 - - - {field => ( - - 用户名 - field.handleChange(e.target.value)} - /> - - - )} - - - {field => ( - - 昵称 - field.handleChange(e.target.value)} - /> - - - )} - - - {field => ( - - 副标题 - field.handleChange(e.target.value)} - /> - - - )} - - - {field => ( - - 头像链接 - field.handleChange(e.target.value)} - /> - - - )} - - - - - - - - - -
-
-
- ); -} diff --git a/client/cms/src/components/profile/main-profile.tsx b/client/cms/src/components/profile/main-profile.tsx deleted file mode 100644 index 573f3e5..0000000 --- a/client/cms/src/components/profile/main-profile.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import MDEditor from '@uiw/react-md-editor'; -import { isNil } from 'lodash-es'; -import { Mail, Pencil } from 'lucide-react'; -import { useState } from 'react'; -import Markdown from 'react-markdown'; -import { toast } from 'sonner'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { useUpdateUser } from '@/hooks/data/useUpdateUser'; -import { useUserInfo } from '@/hooks/data/useUserInfo'; -import { base64ToUtf8, utf8ToBase64 } from '@/lib/utils'; -import { Button } from '../ui/button'; -import { EditProfileDialog } from './edit-profile-dialog'; - -export function MainProfile() { - const { data: user } = useUserInfo(); - const [bio, setBio] = useState(() => base64ToUtf8(user.bio)); - const [enableBioEdit, setEnableBioEdit] = useState(false); - const { mutateAsync } = useUpdateUser(); - - return ( -
-
-
-
-
- - - CN - -
- - -
-
-
- - {user.email} -
-
- -
-
-
- {/* Bio */} - {enableBioEdit - ? ( - - ) - :
{bio}
} - -
-
- ); -} diff --git a/client/cms/src/components/sidebar/app-sidebar.tsx b/client/cms/src/components/sidebar/app-sidebar.tsx deleted file mode 100644 index 0d1a945..0000000 --- a/client/cms/src/components/sidebar/app-sidebar.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -import NixOSLogo from '@/assets/nixos.svg?react'; -import { NavMain } from '@/components/sidebar/nav-main'; -import { NavSecondary } from '@/components/sidebar/nav-secondary'; -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarHeader, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from '@/components/ui/sidebar'; -import { navData } from '@/lib/navData'; -import { NavUser } from './nav-user'; - -export function AppSidebar({ ...props }: React.ComponentProps) { - return ( - - - - - - - - Nix CN CMS - - - - - - - - - - - - - - ); -} diff --git a/client/cms/src/components/sidebar/nav-main.tsx b/client/cms/src/components/sidebar/nav-main.tsx deleted file mode 100644 index fc7c13b..0000000 --- a/client/cms/src/components/sidebar/nav-main.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import type { Icon } from '@tabler/icons-react'; - -import { Link } from '@tanstack/react-router'; -import { - SidebarGroup, - SidebarGroupContent, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from '@/components/ui/sidebar'; - -export function NavMain({ - items, -}: { - items: { - title: string; - url: string; - icon?: Icon; - }[]; -}) { - return ( - - - - {items.map(item => ( - - - {({ isActive }) => { - return ( - - {item.icon && } - {item.title} - - ); - }} - - - ))} - - - - ); -} diff --git a/client/cms/src/components/sidebar/nav-secondary.tsx b/client/cms/src/components/sidebar/nav-secondary.tsx deleted file mode 100644 index b0da89c..0000000 --- a/client/cms/src/components/sidebar/nav-secondary.tsx +++ /dev/null @@ -1,47 +0,0 @@ -'use client'; - -import type { Icon } from '@tabler/icons-react'; -import { Link } from '@tanstack/react-router'; - -import * as React from 'react'; -import { - SidebarGroup, - SidebarGroupContent, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, -} from '@/components/ui/sidebar'; - -export function NavSecondary({ - items, - ...props -}: { - items: { - title: string; - url: string; - icon: Icon; - }[]; -} & React.ComponentPropsWithoutRef) { - return ( - - - - {items.map(item => ( - - - {({ isActive }) => { - return ( - - - {item.title} - - ); - }} - - - ))} - - - - ); -} diff --git a/client/cms/src/components/sidebar/nav-user.tsx b/client/cms/src/components/sidebar/nav-user.tsx deleted file mode 100644 index 8356344..0000000 --- a/client/cms/src/components/sidebar/nav-user.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { - IconDotsVertical, - IconLogout, -} from '@tabler/icons-react'; - -import { - Avatar, - AvatarFallback, - AvatarImage, -} from '@/components/ui/avatar'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - useSidebar, -} from '@/components/ui/sidebar'; -import { useUserInfo } from '@/hooks/data/useUserInfo'; -import { useLogout } from '@/hooks/useLogout'; -import { withFallback } from '../hoc/with-fallback'; -import { Skeleton } from '../ui/skeleton'; - -function NavUser_() { - const { isMobile } = useSidebar(); - const { data: user } = useUserInfo(); - const { logout } = useLogout(); - - return ( - - - - - - - - CN - -
- {user.nickname} - - {user.email} - -
- -
-
- - -
- - - CN - -
- {user.nickname} - - {user.email} - -
-
-
- - - - 登出 - -
-
-
-
- ); -} - -function NavUserSkeleton() { - return ( - - -
- - -
- -
- ); -} - -export const NavUser = withFallback(NavUser_, ); diff --git a/client/cms/src/components/site-header.tsx b/client/cms/src/components/site-header.tsx deleted file mode 100644 index 9ecc44b..0000000 --- a/client/cms/src/components/site-header.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useRouterState } from '@tanstack/react-router'; -import { Separator } from '@/components/ui/separator'; -import { SidebarTrigger } from '@/components/ui/sidebar'; -import { navData } from '@/lib/navData'; - -export function SiteHeader() { - const pathname = useRouterState({ select: state => state.location.pathname }); - const allNavItems = [...navData.navMain, ...navData.navSecondary]; - const currentTitle - = allNavItems.find(item => - item.url === '/' - ? pathname === '/' - : pathname.startsWith(item.url), - )?.title ?? '工作台'; - - return ( -
-
- - -

{currentTitle}

-
-
- ); -} diff --git a/client/cms/src/components/theme-provider.tsx b/client/cms/src/components/theme-provider.tsx deleted file mode 100644 index 14bc663..0000000 --- a/client/cms/src/components/theme-provider.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import type { Theme } from '@/hooks/useTheme'; -import { useEffect, useState } from 'react'; -import { ThemeProviderContext } from '@/hooks/useTheme'; - -interface ThemeProviderProps { - children: React.ReactNode; - defaultTheme?: Theme; - storageKey?: string; -} - -export function ThemeProvider({ - children, - defaultTheme = 'dark', - storageKey = 'vite-ui-theme', - ...props -}: ThemeProviderProps) { - const [theme, setTheme] = useState( - () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, - ); - - useEffect(() => { - const root = window.document.documentElement; - - root.classList.remove('light', 'dark'); - - if (theme === 'system') { - const systemTheme = window.matchMedia('(prefers-color-scheme: dark)') - .matches - ? 'dark' - : 'light'; - - root.classList.add(systemTheme); - return; - } - - root.classList.add(theme); - }, [theme]); - - // eslint-disable-next-line react/no-unstable-context-value - const value = { - theme, - setTheme: (theme: Theme) => { - localStorage.setItem(storageKey, theme); - setTheme(theme); - }, - }; - - return ( - - {children} - - ); -} diff --git a/client/cms/src/components/ui/avatar.tsx b/client/cms/src/components/ui/avatar.tsx deleted file mode 100644 index 71e428b..0000000 --- a/client/cms/src/components/ui/avatar.tsx +++ /dev/null @@ -1,53 +0,0 @@ -"use client" - -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" - -import { cn } from "@/lib/utils" - -function Avatar({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AvatarImage({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -function AvatarFallback({ - className, - ...props -}: React.ComponentProps) { - return ( - - ) -} - -export { Avatar, AvatarImage, AvatarFallback } diff --git a/client/cms/src/components/ui/badge.tsx b/client/cms/src/components/ui/badge.tsx deleted file mode 100644 index fd3a406..0000000 --- a/client/cms/src/components/ui/badge.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const badgeVariants = cva( - "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", - { - variants: { - variant: { - default: - "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", - secondary: - "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", - destructive: - "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", - outline: - "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -function Badge({ - className, - variant, - asChild = false, - ...props -}: React.ComponentProps<"span"> & - VariantProps & { asChild?: boolean }) { - const Comp = asChild ? Slot : "span" - - return ( - - ) -} - -export { Badge, badgeVariants } diff --git a/client/cms/src/components/ui/breadcrumb.tsx b/client/cms/src/components/ui/breadcrumb.tsx deleted file mode 100644 index eb88f32..0000000 --- a/client/cms/src/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { ChevronRight, MoreHorizontal } from "lucide-react" - -import { cn } from "@/lib/utils" - -function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { - return