diff --git a/Makefile b/Makefile index cf3fd43..29d73b9 100644 --- a/Makefile +++ b/Makefile @@ -24,5 +24,6 @@ api-frontend: ## Convert to OpenAPI 3, generate TS types and Zod schemas @cd apps/web && bunx kubb generate @echo "Cleaning up..." + @cd apps/web && bun format @rm apps/web/src/lib/api/openapi.json @echo "Frontend generation complete!" diff --git a/apps/api/docs/docs.go b/apps/api/docs/docs.go index fb3a113..f13964a 100644 --- a/apps/api/docs/docs.go +++ b/apps/api/docs/docs.go @@ -654,6 +654,12 @@ const docTemplate = `{ ] } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -711,6 +717,12 @@ const docTemplate = `{ ] } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -744,6 +756,12 @@ const docTemplate = `{ "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.Response" } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -1925,9 +1943,6 @@ const docTemplate = `{ "service_id" ], "properties": { - "bitmask": { - "type": "integer" - }, "description": { "type": "string" }, @@ -1939,6 +1954,12 @@ const docTemplate = `{ "maxLength": 64, "minLength": 3 }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermissionRequest" + } + }, "priority": { "type": "integer" }, @@ -1951,12 +1972,13 @@ const docTemplate = `{ "type": "object", "properties": { "bitmask": { + "description": "Deprecated for granular resources, used for global", "type": "integer" }, - "createdAt": { + "created_at": { "type": "string" }, - "deletedAt": { + "deleted_at": { "$ref": "#/definitions/gorm.DeletedAt" }, "description": { @@ -1965,19 +1987,26 @@ const docTemplate = `{ "id": { "type": "string" }, - "isDefault": { + "is_default": { "type": "boolean" }, "name": { "type": "string" }, + "permissions": { + "description": "Associations", + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermission" + } + }, "priority": { "type": "integer" }, - "serviceID": { + "service_id": { "type": "string" }, - "updatedAt": { + "updated_at": { "type": "string" } } @@ -1990,6 +2019,47 @@ const docTemplate = `{ } } }, + "internal_domain_role.RolePermission": { + "type": "object", + "properties": { + "bitmask": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "deleted_at": { + "$ref": "#/definitions/gorm.DeletedAt" + }, + "id": { + "type": "string" + }, + "resource": { + "description": "NULL = global", + "type": "string" + }, + "role_id": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "internal_domain_role.RolePermissionRequest": { + "type": "object", + "required": [ + "bitmask" + ], + "properties": { + "bitmask": { + "type": "integer" + }, + "resource": { + "type": "string" + } + } + }, "internal_domain_role.RolesDataResponse": { "type": "object", "properties": { @@ -2004,9 +2074,6 @@ const docTemplate = `{ "internal_domain_role.UpdateRoleRequest": { "type": "object", "properties": { - "bitmask": { - "type": "integer" - }, "description": { "type": "string" }, @@ -2018,6 +2085,12 @@ const docTemplate = `{ "maxLength": 64, "minLength": 3 }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermissionRequest" + } + }, "priority": { "type": "integer" } @@ -2041,6 +2114,9 @@ const docTemplate = `{ "type": "string" } }, + "confidential": { + "type": "boolean" + }, "description": { "type": "string", "maxLength": 1000 diff --git a/apps/api/docs/swagger.json b/apps/api/docs/swagger.json index 97b3704..67bd784 100644 --- a/apps/api/docs/swagger.json +++ b/apps/api/docs/swagger.json @@ -647,6 +647,12 @@ ] } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -704,6 +710,12 @@ ] } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -737,6 +749,12 @@ "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.Response" } }, + "400": { + "description": "Invalid ID format", + "schema": { + "$ref": "#/definitions/github_com_Anvoria_authly_internal_utils.APIError" + } + }, "404": { "description": "Service not found", "schema": { @@ -1918,9 +1936,6 @@ "service_id" ], "properties": { - "bitmask": { - "type": "integer" - }, "description": { "type": "string" }, @@ -1932,6 +1947,12 @@ "maxLength": 64, "minLength": 3 }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermissionRequest" + } + }, "priority": { "type": "integer" }, @@ -1944,12 +1965,13 @@ "type": "object", "properties": { "bitmask": { + "description": "Deprecated for granular resources, used for global", "type": "integer" }, - "createdAt": { + "created_at": { "type": "string" }, - "deletedAt": { + "deleted_at": { "$ref": "#/definitions/gorm.DeletedAt" }, "description": { @@ -1958,19 +1980,26 @@ "id": { "type": "string" }, - "isDefault": { + "is_default": { "type": "boolean" }, "name": { "type": "string" }, + "permissions": { + "description": "Associations", + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermission" + } + }, "priority": { "type": "integer" }, - "serviceID": { + "service_id": { "type": "string" }, - "updatedAt": { + "updated_at": { "type": "string" } } @@ -1983,6 +2012,47 @@ } } }, + "internal_domain_role.RolePermission": { + "type": "object", + "properties": { + "bitmask": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "deleted_at": { + "$ref": "#/definitions/gorm.DeletedAt" + }, + "id": { + "type": "string" + }, + "resource": { + "description": "NULL = global", + "type": "string" + }, + "role_id": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "internal_domain_role.RolePermissionRequest": { + "type": "object", + "required": [ + "bitmask" + ], + "properties": { + "bitmask": { + "type": "integer" + }, + "resource": { + "type": "string" + } + } + }, "internal_domain_role.RolesDataResponse": { "type": "object", "properties": { @@ -1997,9 +2067,6 @@ "internal_domain_role.UpdateRoleRequest": { "type": "object", "properties": { - "bitmask": { - "type": "integer" - }, "description": { "type": "string" }, @@ -2011,6 +2078,12 @@ "maxLength": 64, "minLength": 3 }, + "permissions": { + "type": "array", + "items": { + "$ref": "#/definitions/internal_domain_role.RolePermissionRequest" + } + }, "priority": { "type": "integer" } @@ -2034,6 +2107,9 @@ "type": "string" } }, + "confidential": { + "type": "boolean" + }, "description": { "type": "string", "maxLength": 1000 diff --git a/apps/api/docs/swagger.yaml b/apps/api/docs/swagger.yaml index 92c4259..ba74948 100644 --- a/apps/api/docs/swagger.yaml +++ b/apps/api/docs/swagger.yaml @@ -372,8 +372,6 @@ definitions: type: object internal_domain_role.CreateRoleRequest: properties: - bitmask: - type: integer description: type: string is_default: @@ -382,6 +380,10 @@ definitions: maxLength: 64 minLength: 3 type: string + permissions: + items: + $ref: '#/definitions/internal_domain_role.RolePermissionRequest' + type: array priority: type: integer service_id: @@ -393,24 +395,30 @@ definitions: internal_domain_role.Role: properties: bitmask: + description: Deprecated for granular resources, used for global type: integer - createdAt: + created_at: type: string - deletedAt: + deleted_at: $ref: '#/definitions/gorm.DeletedAt' description: type: string id: type: string - isDefault: + is_default: type: boolean name: type: string + permissions: + description: Associations + items: + $ref: '#/definitions/internal_domain_role.RolePermission' + type: array priority: type: integer - serviceID: + service_id: type: string - updatedAt: + updated_at: type: string type: object internal_domain_role.RoleDataResponse: @@ -418,6 +426,33 @@ definitions: role: $ref: '#/definitions/internal_domain_role.Role' type: object + internal_domain_role.RolePermission: + properties: + bitmask: + type: integer + created_at: + type: string + deleted_at: + $ref: '#/definitions/gorm.DeletedAt' + id: + type: string + resource: + description: NULL = global + type: string + role_id: + type: string + updated_at: + type: string + type: object + internal_domain_role.RolePermissionRequest: + properties: + bitmask: + type: integer + resource: + type: string + required: + - bitmask + type: object internal_domain_role.RolesDataResponse: properties: roles: @@ -427,8 +462,6 @@ definitions: type: object internal_domain_role.UpdateRoleRequest: properties: - bitmask: - type: integer description: type: string is_default: @@ -437,6 +470,10 @@ definitions: maxLength: 64 minLength: 3 type: string + permissions: + items: + $ref: '#/definitions/internal_domain_role.RolePermissionRequest' + type: array priority: type: integer type: object @@ -448,6 +485,8 @@ definitions: maxItems: 10 minItems: 1 type: array + confidential: + type: boolean description: maxLength: 1000 type: string @@ -1002,6 +1041,10 @@ paths: description: Service deleted successfully schema: $ref: '#/definitions/github_com_Anvoria_authly_internal_utils.Response' + "400": + description: Invalid ID format + schema: + $ref: '#/definitions/github_com_Anvoria_authly_internal_utils.APIError' "404": description: Service not found schema: @@ -1029,6 +1072,10 @@ paths: data: $ref: '#/definitions/internal_domain_service.ServiceDataResponse' type: object + "400": + description: Invalid ID format + schema: + $ref: '#/definitions/github_com_Anvoria_authly_internal_utils.APIError' "404": description: Service not found schema: @@ -1064,6 +1111,10 @@ paths: data: $ref: '#/definitions/internal_domain_service.ServiceDataResponse' type: object + "400": + description: Invalid ID format + schema: + $ref: '#/definitions/github_com_Anvoria_authly_internal_utils.APIError' "404": description: Service not found schema: diff --git a/apps/api/internal/database/base.go b/apps/api/internal/database/base.go index d38dc19..6bc87dd 100644 --- a/apps/api/internal/database/base.go +++ b/apps/api/internal/database/base.go @@ -8,8 +8,8 @@ import ( ) type BaseModel struct { - ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()"` - CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"` - UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"` - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"` + ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"` + CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"` + UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index" json:"deleted_at,omitempty"` } diff --git a/apps/api/internal/domain/permission/model.go b/apps/api/internal/domain/permission/model.go index 14ef957..2190dd8 100644 --- a/apps/api/internal/domain/permission/model.go +++ b/apps/api/internal/domain/permission/model.go @@ -80,7 +80,7 @@ type CreatePermissionRequest struct { ServiceID string `json:"service_id" validate:"required,uuid"` Name string `json:"name" validate:"required,min=3,max=64"` Bit uint8 `json:"bit"` - Resource *string `json:"resource"` + Resource *string `json:"resource,omitempty"` } // UpdatePermissionRequest represents the input for updating a permission diff --git a/apps/api/internal/domain/permission/repository.go b/apps/api/internal/domain/permission/repository.go index d364e83..8dbc8de 100644 --- a/apps/api/internal/domain/permission/repository.go +++ b/apps/api/internal/domain/permission/repository.go @@ -24,6 +24,9 @@ type Repository interface { FindUserPermissionsByUserID(userID string) ([]*UserPermission, error) FindUserPermissionsByUserIDAndServiceID(userID, serviceID string) ([]*UserPermission, error) FindUserPermissionsByRoleID(roleID string) ([]*UserPermission, error) + GetUsersByRoleID(roleID string) ([]string, error) + BulkUpdateUserPermissionsByRole(roleID string, resource *string, addedBits, removedBits uint64) error + BulkDeleteUserPermissionsByRole(roleID string, resource *string) error UpdateUserPermission(userPerm *UserPermission) error DeleteUserPermission(userID, serviceID string, resource *string) error IncrementPermissionVersion(userID string) error @@ -206,6 +209,41 @@ func (r *repository) FindUserPermissionsByRoleID(roleID string) ([]*UserPermissi return userPerms, nil } +// GetUsersByRoleID gets distinct user IDs associated with a specific role +func (r *repository) GetUsersByRoleID(roleID string) ([]string, error) { + var userIDs []string + if err := r.db.Model(&UserPermission{}).Where("role_id = ?", roleID).Distinct("user_id").Pluck("user_id", &userIDs).Error; err != nil { + return nil, err + } + return userIDs, nil +} + +// BulkUpdateUserPermissionsByRole updates bitmasks for all users with a specific role and resource +func (r *repository) BulkUpdateUserPermissionsByRole(roleID string, resource *string, addedBits, removedBits uint64) error { + query := r.db.Model(&UserPermission{}).Where("role_id = ?", roleID) + + if resource == nil { + query = query.Where("resource IS NULL") + } else { + query = query.Where("resource = ?", *resource) + } + + return query.Update("bitmask", gorm.Expr("(bitmask | ?) & ~?", addedBits, removedBits)).Error +} + +// BulkDeleteUserPermissionsByRole deletes user permissions for a specific role and resource +func (r *repository) BulkDeleteUserPermissionsByRole(roleID string, resource *string) error { + query := r.db.Where("role_id = ?", roleID) + + if resource == nil { + query = query.Where("resource IS NULL") + } else { + query = query.Where("resource = ?", *resource) + } + + return query.Delete(&UserPermission{}).Error +} + // UpdateUserPermission updates a user permission func (r *repository) UpdateUserPermission(userPerm *UserPermission) error { return r.db.Save(userPerm).Error diff --git a/apps/api/internal/domain/role/handler.go b/apps/api/internal/domain/role/handler.go index ac5a949..24ea618 100644 --- a/apps/api/internal/domain/role/handler.go +++ b/apps/api/internal/domain/role/handler.go @@ -74,9 +74,16 @@ func (h *Handler) CreateRole(c *fiber.Ctx) error { ServiceID: serviceUUID, Name: req.Name, Description: req.Description, - Bitmask: req.Bitmask, IsDefault: req.IsDefault, Priority: req.Priority, + Permissions: make([]RolePermission, len(req.Permissions)), + } + + for i, p := range req.Permissions { + role.Permissions[i] = RolePermission{ + Resource: p.Resource, + Bitmask: p.Bitmask, + } } if err := h.roleService.CreateRole(role); err != nil { @@ -134,9 +141,6 @@ func (h *Handler) UpdateRole(c *fiber.Ctx) error { if req.Description != nil { role.Description = *req.Description } - if req.Bitmask != nil { - role.Bitmask = *req.Bitmask - } if req.IsDefault != nil { role.IsDefault = *req.IsDefault } @@ -144,6 +148,16 @@ func (h *Handler) UpdateRole(c *fiber.Ctx) error { role.Priority = *req.Priority } + if req.Permissions != nil { + role.Permissions = make([]RolePermission, len(req.Permissions)) + for i, p := range req.Permissions { + role.Permissions[i] = RolePermission{ + Resource: p.Resource, + Bitmask: p.Bitmask, + } + } + } + if err := h.roleService.UpdateRole(role); err != nil { return utils.ErrorResponse(c, utils.NewAPIError("INTERNAL_SERVER_ERROR", err.Error(), fiber.StatusInternalServerError)) } diff --git a/apps/api/internal/domain/role/model.go b/apps/api/internal/domain/role/model.go index 2540f27..dee9857 100644 --- a/apps/api/internal/domain/role/model.go +++ b/apps/api/internal/domain/role/model.go @@ -8,12 +8,28 @@ import ( // Role represents a role within a service type Role struct { database.BaseModel - ServiceID uuid.UUID `gorm:"column:service_id;type:uuid;not null;index"` - Name string `gorm:"column:name;type:varchar(255);not null"` - Description string `gorm:"column:description;type:text"` - Bitmask uint64 `gorm:"column:bitmask;type:numeric(20);not null;default:0"` - IsDefault bool `gorm:"column:is_default;type:boolean;not null;default:false"` - Priority int `gorm:"column:priority;type:integer;not null;default:0"` + ServiceID uuid.UUID `gorm:"column:service_id;type:uuid;not null;index" json:"service_id"` + Name string `gorm:"column:name;type:varchar(255);not null" json:"name"` + Description string `gorm:"column:description;type:text" json:"description"` + Bitmask uint64 `gorm:"column:bitmask;type:numeric(20);not null;default:0" json:"bitmask"` // Deprecated for granular resources, used for global + IsDefault bool `gorm:"column:is_default;type:boolean;not null;default:false" json:"is_default"` + Priority int `gorm:"column:priority;type:integer;not null;default:0" json:"priority"` + + // Associations + Permissions []RolePermission `gorm:"foreignKey:RoleID" json:"permissions,omitempty"` +} + +// RolePermission represents a bitmask for a specific resource within a role +type RolePermission struct { + database.BaseModel + RoleID uuid.UUID `gorm:"column:role_id;type:uuid;not null;index" json:"role_id"` + Resource *string `gorm:"column:resource;type:varchar(100)" json:"resource,omitempty"` // NULL = global + Bitmask uint64 `gorm:"column:bitmask;type:numeric(20);not null;default:0" json:"bitmask"` +} + +// TableName returns the table name for Gorm +func (RolePermission) TableName() string { + return "role_permissions" } // TableName returns the table name for Gorm @@ -21,23 +37,29 @@ func (Role) TableName() string { return "roles" } +// RolePermissionRequest represents a permission assignment for a resource +type RolePermissionRequest struct { + Resource *string `json:"resource,omitempty"` + Bitmask uint64 `json:"bitmask" validate:"required"` +} + // CreateRoleRequest represents the input for creating a role type CreateRoleRequest struct { - ServiceID string `json:"service_id" validate:"required,uuid"` - Name string `json:"name" validate:"required,min=3,max=64"` - Description string `json:"description"` - Bitmask uint64 `json:"bitmask"` - IsDefault bool `json:"is_default"` - Priority int `json:"priority"` + ServiceID string `json:"service_id" validate:"required,uuid"` + Name string `json:"name" validate:"required,min=3,max=64"` + Description string `json:"description"` + IsDefault bool `json:"is_default"` + Priority int `json:"priority"` + Permissions []RolePermissionRequest `json:"permissions"` } // UpdateRoleRequest represents the input for updating a role type UpdateRoleRequest struct { - Name *string `json:"name" validate:"omitempty,min=3,max=64"` - Description *string `json:"description"` - Bitmask *uint64 `json:"bitmask"` - IsDefault *bool `json:"is_default"` - Priority *int `json:"priority"` + Name *string `json:"name" validate:"omitempty,min=3,max=64"` + Description *string `json:"description"` + IsDefault *bool `json:"is_default"` + Priority *int `json:"priority"` + Permissions []RolePermissionRequest `json:"permissions"` } // AssignRoleRequest represents the input for assigning a role to a user diff --git a/apps/api/internal/domain/role/repository.go b/apps/api/internal/domain/role/repository.go index b7ddf80..a4b30ed 100644 --- a/apps/api/internal/domain/role/repository.go +++ b/apps/api/internal/domain/role/repository.go @@ -43,7 +43,7 @@ func (r *repository) Create(role *Role) error { func (r *repository) FindByID(id string) (*Role, error) { var role Role - if err := r.db.Where("id = ?", id).First(&role).Error; err != nil { + if err := r.db.Preload("Permissions").Where("id = ?", id).First(&role).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrRoleNotFound } @@ -54,7 +54,7 @@ func (r *repository) FindByID(id string) (*Role, error) { func (r *repository) FindByName(serviceID, name string) (*Role, error) { var role Role - if err := r.db.Where("service_id = ? AND name = ?", serviceID, name).First(&role).Error; err != nil { + if err := r.db.Preload("Permissions").Where("service_id = ? AND name = ?", serviceID, name).First(&role).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrRoleNotFound } @@ -65,7 +65,7 @@ func (r *repository) FindByName(serviceID, name string) (*Role, error) { func (r *repository) FindByServiceID(serviceID string) ([]*Role, error) { var roles []*Role - if err := r.db.Where("service_id = ?", serviceID).Order("priority DESC").Find(&roles).Error; err != nil { + if err := r.db.Preload("Permissions").Where("service_id = ?", serviceID).Order("priority DESC").Find(&roles).Error; err != nil { return nil, err } return roles, nil @@ -73,7 +73,7 @@ func (r *repository) FindByServiceID(serviceID string) ([]*Role, error) { func (r *repository) FindDefaultByServiceID(serviceID string) (*Role, error) { var role Role - if err := r.db.Where("service_id = ? AND is_default = ?", serviceID, true).First(&role).Error; err != nil { + if err := r.db.Preload("Permissions").Where("service_id = ? AND is_default = ?", serviceID, true).First(&role).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrRoleNotFound } @@ -84,7 +84,7 @@ func (r *repository) FindDefaultByServiceID(serviceID string) (*Role, error) { func (r *repository) FindAllDefaults() ([]*Role, error) { var roles []*Role - if err := r.db.Where("is_default = ?", true).Find(&roles).Error; err != nil { + if err := r.db.Preload("Permissions").Where("is_default = ?", true).Find(&roles).Error; err != nil { return nil, err } return roles, nil diff --git a/apps/api/internal/domain/role/service.go b/apps/api/internal/domain/role/service.go index 1afecd7..6f1f28a 100644 --- a/apps/api/internal/domain/role/service.go +++ b/apps/api/internal/domain/role/service.go @@ -1,6 +1,7 @@ package role import ( + "errors" "fmt" "github.com/Anvoria/authly/internal/domain/permission" @@ -89,7 +90,7 @@ func (s *service) UpdateRole(updatedRole *Role) error { return fmt.Errorf("internal error: failed to cast service") } - oldRole, err := txSvc.repo.FindByID(updatedRole.ID.String()) + oldRole, err := txSvc.repo.FindByID(updatedRole.ID.String()) // FindByID already preloads Permissions if err != nil { return err } @@ -104,17 +105,147 @@ func (s *service) UpdateRole(updatedRole *Role) error { return err } - addedBits := updatedRole.Bitmask &^ oldRole.Bitmask - removedBits := oldRole.Bitmask &^ updatedRole.Bitmask - - if addedBits == 0 && removedBits == 0 { - return nil + // Update permissions associations only when explicitly provided + if updatedRole.Permissions != nil { + if err := tx.Model(updatedRole).Association("Permissions").Replace(updatedRole.Permissions); err != nil { + return err + } } - return txSvc.propagateRoleChanges(updatedRole.ID.String(), addedBits, removedBits) + return txSvc.propagateRoleChanges(oldRole, updatedRole) }) } +// propagateRoleChanges updates user permissions based on changes in role permissions +func (s *service) propagateRoleChanges(oldRole, newRole *Role) error { + oldMap := make(map[string]uint64) + if oldRole.Bitmask > 0 { + oldMap["__global__"] = oldRole.Bitmask + } + for _, p := range oldRole.Permissions { + key := "__global__" + if p.Resource != nil { + key = *p.Resource + } + oldMap[key] = p.Bitmask + } + + newMap := make(map[string]uint64) + if newRole.Permissions == nil { + for _, p := range oldRole.Permissions { + key := "__global__" + if p.Resource != nil { + key = *p.Resource + } + newMap[key] = p.Bitmask + } + if newRole.Bitmask > 0 { + newMap["__global__"] = newRole.Bitmask + } + } else { + if newRole.Bitmask > 0 { + newMap["__global__"] = newRole.Bitmask + } + for _, p := range newRole.Permissions { + key := "__global__" + if p.Resource != nil { + key = *p.Resource + } + newMap[key] = p.Bitmask + } + } + + for key, oldMask := range oldMap { + var resourcePtr *string + if key != "__global__" { + k := key + resourcePtr = &k + } + + if newMask, exists := newMap[key]; exists { + addedBits := newMask &^ oldMask + removedBits := oldMask &^ newMask + + if addedBits > 0 || removedBits > 0 { + if err := s.permissionRepo.BulkUpdateUserPermissionsByRole(oldRole.ID.String(), resourcePtr, addedBits, removedBits); err != nil { + return err + } + } + } else { + if err := s.permissionRepo.BulkDeleteUserPermissionsByRole(oldRole.ID.String(), resourcePtr); err != nil { + return err + } + } + } + + var addedResources []string + for key := range newMap { + if _, exists := oldMap[key]; !exists { + addedResources = append(addedResources, key) + } + } + + if len(addedResources) > 0 { + userIDs, err := s.permissionRepo.GetUsersByRoleID(oldRole.ID.String()) + if err != nil { + return err + } + + for _, userID := range userIDs { + uid, err := uuid.Parse(userID) + if err != nil { + continue + } + rid := oldRole.ID // Role ID hasn't changed + + for _, resKey := range addedResources { + mask := newMap[resKey] + var resPtr *string + if resKey != "__global__" { + k := resKey + resPtr = &k + } + + userPerm, err := s.permissionRepo.FindUserPermission(userID, oldRole.ServiceID.String(), resPtr) + if err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + newPerm := &permission.UserPermission{ + UserID: uid, + ServiceID: oldRole.ServiceID, + RoleID: &rid, + Resource: resPtr, + Bitmask: mask, + PermissionV: 1, + } + if err := s.permissionRepo.CreateUserPermission(newPerm); err != nil { + return err + } + } else { + userPerm.RoleID = &rid + userPerm.Bitmask = userPerm.Bitmask | mask + if err := s.permissionRepo.UpdateUserPermission(userPerm); err != nil { + return err + } + } + } + } + } + + userIDs, err := s.permissionRepo.GetUsersByRoleID(oldRole.ID.String()) + if err != nil { + return err + } + for _, uid := range userIDs { + if err := s.permissionRepo.IncrementPermissionVersion(uid); err != nil { + return fmt.Errorf("failed to increment permission version for user %s in role %s: %w", uid, oldRole.ID.String(), err) + } + } + + return nil +} + func (s *service) DeleteRole(id string) error { return s.db.Transaction(func(tx *gorm.DB) error { txSvc := s.WithTx(tx) @@ -165,62 +296,122 @@ func (s *service) AssignRole(userID, roleID string) error { return err } - userPerms, err := txSvc.permissionRepo.FindUserPermissionsByUserIDAndServiceID(userID, role.ServiceID.String()) + uid, err := uuid.Parse(userID) + if err != nil { + return err + } + rid, err := uuid.Parse(roleID) if err != nil { return err } - var userPerm *permission.UserPermission - // Find the global permission (resource is null) - for _, p := range userPerms { - if p.Resource == nil { - userPerm = p - break - } + userPerms, err := txSvc.permissionRepo.FindUserPermissionsByUserIDAndServiceID(userID, role.ServiceID.String()) + if err != nil { + return err } - if userPerm == nil { - // Create new permission - uid, err := uuid.Parse(userID) - if err != nil { - return err + processedResources := make(map[string]bool) + + for _, up := range userPerms { + if up.RoleID != nil { + oldRole, err := txSvc.repo.FindByID(up.RoleID.String()) + if err != nil { + up.RoleID = nil + } else { + var oldRoleMask uint64 + if up.Resource == nil { + oldRoleMask = oldRole.Bitmask + } else { + for _, rp := range oldRole.Permissions { + if rp.Resource != nil && *rp.Resource == *up.Resource { + oldRoleMask = rp.Bitmask + break + } + } + } + up.Bitmask = up.Bitmask &^ oldRoleMask + up.RoleID = nil + } + if err := txSvc.permissionRepo.UpdateUserPermission(up); err != nil { + return err + } } + } - rid, err := uuid.Parse(roleID) - if err != nil { - return err + if role.Bitmask > 0 { + var globalPerm *permission.UserPermission + for _, up := range userPerms { + if up.Resource == nil { + globalPerm = up + break + } } - userPerm = &permission.UserPermission{ - UserID: uid, - ServiceID: role.ServiceID, - RoleID: &rid, - Bitmask: role.Bitmask, - Resource: nil, + if globalPerm == nil { + globalPerm = &permission.UserPermission{ + UserID: uid, + ServiceID: role.ServiceID, + RoleID: &rid, + Bitmask: role.Bitmask, + Resource: nil, + } + if err := txSvc.permissionRepo.CreateUserPermission(globalPerm); err != nil { + return err + } + } else { + globalPerm.RoleID = &rid + globalPerm.Bitmask = globalPerm.Bitmask | role.Bitmask + if err := txSvc.permissionRepo.UpdateUserPermission(globalPerm); err != nil { + return err + } } - return txSvc.permissionRepo.CreateUserPermission(userPerm) + processedResources["__global__"] = true } - // Update existing permission - if userPerm.RoleID != nil { - oldRole, err := txSvc.repo.FindByID(userPerm.RoleID.String()) - if err != nil { - return fmt.Errorf("failed to fetch old role %s for user %s: %w", userPerm.RoleID, userID, err) + for _, rp := range role.Permissions { + var resourceKey string + if rp.Resource != nil { + resourceKey = *rp.Resource + } else { + resourceKey = "__global__" } - // Remove old role's bits - userPerm.Bitmask = userPerm.Bitmask &^ oldRole.Bitmask - } - userPerm.Bitmask = userPerm.Bitmask | role.Bitmask + if resourceKey == "__global__" && processedResources["__global__"] { + continue + } - rid, err := uuid.Parse(roleID) - if err != nil { - return err - } - userPerm.RoleID = &rid + var targetPerm *permission.UserPermission + for _, up := range userPerms { + if resourceKey == "__global__" { + if up.Resource == nil { + targetPerm = up + break + } + } else if up.Resource != nil && *up.Resource == resourceKey { + targetPerm = up + break + } + } - if err := txSvc.permissionRepo.UpdateUserPermission(userPerm); err != nil { - return err + if targetPerm == nil { + resPtr := rp.Resource + targetPerm = &permission.UserPermission{ + UserID: uid, + ServiceID: role.ServiceID, + RoleID: &rid, + Bitmask: rp.Bitmask, + Resource: resPtr, + } + if err := txSvc.permissionRepo.CreateUserPermission(targetPerm); err != nil { + return err + } + } else { + targetPerm.RoleID = &rid + targetPerm.Bitmask = targetPerm.Bitmask | rp.Bitmask + if err := txSvc.permissionRepo.UpdateUserPermission(targetPerm); err != nil { + return err + } + } } // Increment permission version to invalidate tokens @@ -250,28 +441,6 @@ func (s *service) AssignDefaultRoles(userID string) error { }) } -func (s *service) propagateRoleChanges(roleID string, addedBits, removedBits uint64) error { - userPerms, err := s.permissionRepo.FindUserPermissionsByRoleID(roleID) - if err != nil { - return err - } - - for _, perm := range userPerms { - // Apply delta - perm.Bitmask = perm.Bitmask | addedBits - perm.Bitmask = perm.Bitmask &^ removedBits - - if err := s.permissionRepo.UpdateUserPermission(perm); err != nil { - return err - } - // Increment version to invalidate tokens - if err := s.permissionRepo.IncrementPermissionVersion(perm.UserID.String()); err != nil { - return err - } - } - return nil -} - func (s *service) unsetOtherDefaults(serviceID, excludeRoleID string) error { roles, err := s.repo.FindByServiceID(serviceID) if err != nil { diff --git a/apps/api/internal/domain/service/handler.go b/apps/api/internal/domain/service/handler.go index b13ccdf..bdf5196 100644 --- a/apps/api/internal/domain/service/handler.go +++ b/apps/api/internal/domain/service/handler.go @@ -3,17 +3,33 @@ package service import ( "github.com/Anvoria/authly/internal/utils" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" ) type Handler struct { serviceService ServiceInterface } -// NewHandler creates a Handler configured with the provided ServiceInterface. +// NewHandler creates a new Handler using the provided ServiceInterface. func NewHandler(s ServiceInterface) *Handler { return &Handler{serviceService: s} } +// validateServiceID validates the service ID parameter from the request. +// It checks if the ID is present and has a valid UUID format. +// validateServiceID validates the "id" route parameter and returns it. +// If the parameter is missing or not a valid UUID, it sends a 400 validation error response and returns a non-nil error. +func validateServiceID(c *fiber.Ctx) (string, error) { + id := c.Params("id") + if id == "" { + return "", utils.ErrorResponse(c, utils.NewAPIError("VALIDATION_ERROR", "ID is required", fiber.StatusBadRequest)) + } + if _, err := uuid.Parse(id); err != nil { + return "", utils.ErrorResponse(c, utils.NewAPIError("VALIDATION_ERROR", "Invalid ID format", fiber.StatusBadRequest)) + } + return id, nil +} + // CreateService godoc // @Summary Create a new service // @Description Creates a new client/service application @@ -56,12 +72,13 @@ func (h *Handler) CreateService(c *fiber.Ctx) error { // @Produce json // @Param id path string true "Service ID" // @Success 200 {object} utils.Response{data=ServiceDataResponse} "Service details" +// @Failure 400 {object} utils.APIError "Invalid ID format" // @Failure 404 {object} utils.APIError "Service not found" // @Router /admin/services/{id} [get] func (h *Handler) GetService(c *fiber.Ctx) error { - id := c.Params("id") - if id == "" { - return utils.ErrorResponse(c, utils.NewAPIError("VALIDATION_ERROR", "ID is required", fiber.StatusBadRequest)) + id, err := validateServiceID(c) + if err != nil { + return err } svc, err := h.serviceService.FindByID(id) @@ -121,12 +138,14 @@ func (h *Handler) ListServices(c *fiber.Ctx) error { // @Param id path string true "Service ID" // @Param request body UpdateServiceRequest true "Update Details" // @Success 200 {object} utils.Response{data=ServiceDataResponse} "Service updated successfully" +// @Failure 400 {object} utils.APIError "Invalid request body" +// @Failure 400 {object} utils.APIError "Invalid ID format" // @Failure 404 {object} utils.APIError "Service not found" // @Router /admin/services/{id} [put] func (h *Handler) UpdateService(c *fiber.Ctx) error { - id := c.Params("id") - if id == "" { - return utils.ErrorResponse(c, utils.NewAPIError("VALIDATION_ERROR", "ID is required", fiber.StatusBadRequest)) + id, err := validateServiceID(c) + if err != nil { + return err } var req UpdateServiceRequest @@ -162,15 +181,16 @@ func (h *Handler) UpdateService(c *fiber.Ctx) error { // @Produce json // @Param id path string true "Service ID" // @Success 200 {object} utils.Response "Service deleted successfully" +// @Failure 400 {object} utils.APIError "Invalid ID format" // @Failure 404 {object} utils.APIError "Service not found" // @Router /admin/services/{id} [delete] func (h *Handler) DeleteService(c *fiber.Ctx) error { - id := c.Params("id") - if id == "" { - return utils.ErrorResponse(c, utils.NewAPIError("VALIDATION_ERROR", "ID is required", fiber.StatusBadRequest)) + id, err := validateServiceID(c) + if err != nil { + return err } - err := h.serviceService.Delete(id) + err = h.serviceService.Delete(id) if err != nil { if err == ErrServiceNotFound { return utils.ErrorResponse(c, utils.NewAPIError("RESOURCE_NOT_FOUND", err.Error(), fiber.StatusNotFound)) @@ -182,4 +202,4 @@ func (h *Handler) DeleteService(c *fiber.Ctx) error { } return utils.SuccessResponse(c, nil, "Service deleted successfully") -} +} \ No newline at end of file diff --git a/apps/api/internal/domain/user/repository.go b/apps/api/internal/domain/user/repository.go index 266c4eb..80a13b9 100644 --- a/apps/api/internal/domain/user/repository.go +++ b/apps/api/internal/domain/user/repository.go @@ -87,7 +87,7 @@ func (r *repository) FindAll(limit, offset int, search string) ([]*User, int64, return nil, 0, err } - if err := query.Limit(limit).Offset(offset).Find(&users).Error; err != nil { + if err := query.Order("created_at ASC").Limit(limit).Offset(offset).Find(&users).Error; err != nil { return nil, 0, err } diff --git a/apps/api/internal/migrations/000020_create_role_permissions_table.down.sql b/apps/api/internal/migrations/000020_create_role_permissions_table.down.sql new file mode 100644 index 0000000..ce067b3 --- /dev/null +++ b/apps/api/internal/migrations/000020_create_role_permissions_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS role_permissions; diff --git a/apps/api/internal/migrations/000020_create_role_permissions_table.up.sql b/apps/api/internal/migrations/000020_create_role_permissions_table.up.sql new file mode 100644 index 0000000..6897f16 --- /dev/null +++ b/apps/api/internal/migrations/000020_create_role_permissions_table.up.sql @@ -0,0 +1,12 @@ +CREATE TABLE role_permissions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP WITH TIME ZONE, + role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE, + resource VARCHAR(100), + bitmask NUMERIC(20) NOT NULL DEFAULT 0, + UNIQUE(role_id, resource) +); + +CREATE INDEX idx_role_permissions_role_id ON role_permissions(role_id); diff --git a/apps/apps/web/.husky/pre-commit b/apps/apps/web/.husky/pre-commit new file mode 100644 index 0000000..c7020d8 --- /dev/null +++ b/apps/apps/web/.husky/pre-commit @@ -0,0 +1,8 @@ +#!/bin/sh +cd apps/web || exit 1 + +if ! command -v bun >/dev/null 2>&1; then + export PATH="$HOME/.bun/bin:$PATH" +fi + +bun lint-staged \ No newline at end of file diff --git a/apps/web/.husky/pre-commit b/apps/web/.husky/pre-commit new file mode 100755 index 0000000..c7020d8 --- /dev/null +++ b/apps/web/.husky/pre-commit @@ -0,0 +1,8 @@ +#!/bin/sh +cd apps/web || exit 1 + +if ! command -v bun >/dev/null 2>&1; then + export PATH="$HOME/.bun/bin:$PATH" +fi + +bun lint-staged \ No newline at end of file diff --git a/apps/web/.prettierrc.json b/apps/web/.prettierrc.json deleted file mode 100644 index bb91991..0000000 --- a/apps/web/.prettierrc.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "semi": true, - "printWidth": 120, - "useTabs": false, - "tabWidth": 4, - "arrowParens": "always", - "singleQuote": false, - "trailingComma": "all", - "endOfLine": "auto", - "overrides": [ - { - "files": "**/*.{json,jsonc}", - "options": { - "trailingComma": "none" - } - } - ] -} diff --git a/apps/web/biome.json b/apps/web/biome.json new file mode 100644 index 0000000..ad2f2c9 --- /dev/null +++ b/apps/web/biome.json @@ -0,0 +1,318 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 4, + "lineEnding": "lf", + "lineWidth": 120, + "attributePosition": "auto", + "bracketSameLine": false, + "bracketSpacing": true, + "expand": "auto", + "useEditorconfig": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": false, + "complexity": { + "noBannedTypes": "error", + "noUselessThisAlias": "error", + "noUselessTypeConstraint": "error" + }, + "correctness": { + "noUnusedVariables": "error" + }, + "performance": { + "noImgElement": "warn", + "noUnwantedPolyfillio": "warn", + "useGoogleFontPreconnect": "warn" + }, + "style": { + "noCommonJs": "error", + "noHeadElement": "warn", + "noNamespace": "error", + "useArrayLiterals": "error", + "useAsConstAssertion": "error" + }, + "suspicious": { + "noDocumentImportInPage": "error", + "noExplicitAny": "error", + "noExtraNonNullAssertion": "error", + "noHeadImportInDocument": "error", + "noMisleadingInstantiator": "error", + "noNonNullAssertedOptionalChain": "error", + "noTsIgnore": "error", + "noUnsafeDeclarationMerging": "error", + "useGoogleFontDisplay": "warn", + "useNamespaceKeyword": "error" + } + }, + "includes": ["**", "!.next/**", "!out/**", "!build/**", "!next-env.d.ts"] + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSameLine": false, + "quoteStyle": "double", + "attributePosition": "auto", + "bracketSpacing": true + }, + "globals": [] + }, + "html": { + "formatter": { + "indentScriptAndStyle": false, + "selfCloseVoidElements": "always" + } + }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "overrides": [ + { + "includes": ["**/*.{js,jsx,mjs,ts,tsx,mts,cts}"], + "javascript": { + "globals": [ + "onanimationend", + "exports", + "ongamepadconnected", + "onlostpointercapture", + "onanimationiteration", + "onkeyup", + "onmousedown", + "onanimationstart", + "onslotchange", + "onprogress", + "ontransitionstart", + "onpause", + "onended", + "onpointerover", + "onscrollend", + "onformdata", + "ontransitionrun", + "onanimationcancel", + "ondrag", + "onchange", + "onbeforeinstallprompt", + "onbeforexrselect", + "onmessage", + "ontransitioncancel", + "onpointerdown", + "onabort", + "onpointerout", + "oncuechange", + "ongotpointercapture", + "onscrollsnapchanging", + "onsearch", + "onsubmit", + "onstalled", + "onsuspend", + "onreset", + "onerror", + "onresize", + "onmouseenter", + "ongamepaddisconnected", + "ondragover", + "onbeforetoggle", + "onmouseover", + "onpagehide", + "onmousemove", + "onratechange", + "oncommand", + "onmessageerror", + "onwheel", + "ondevicemotion", + "onauxclick", + "ontransitionend", + "onpaste", + "onpageswap", + "ononline", + "ondeviceorientationabsolute", + "onkeydown", + "onclose", + "onselect", + "onpageshow", + "onpointercancel", + "onbeforematch", + "onpointerrawupdate", + "ondragleave", + "onscrollsnapchange", + "onseeked", + "onwaiting", + "onbeforeunload", + "onplaying", + "onvolumechange", + "ondragend", + "onstorage", + "onloadeddata", + "onfocus", + "onoffline", + "onplay", + "onafterprint", + "onclick", + "oncut", + "onmouseout", + "ondblclick", + "oncanplay", + "onloadstart", + "onappinstalled", + "onpointermove", + "ontoggle", + "oncontextmenu", + "onblur", + "oncancel", + "onbeforeprint", + "oncontextrestored", + "onloadedmetadata", + "onpointerup", + "onlanguagechange", + "oncopy", + "onselectstart", + "onscroll", + "onload", + "ondragstart", + "onbeforeinput", + "oncanplaythrough", + "oninput", + "oninvalid", + "ontimeupdate", + "ondurationchange", + "onselectionchange", + "onmouseup", + "location", + "onkeypress", + "onpointerleave", + "oncontextlost", + "ondrop", + "onsecuritypolicyviolation", + "oncontentvisibilityautostatechange", + "ondeviceorientation", + "onseeking", + "onrejectionhandled", + "onunload", + "onmouseleave", + "onhashchange", + "onpointerenter", + "onmousewheel", + "onunhandledrejection", + "ondragenter", + "onpopstate", + "onpagereveal", + "onemptied" + ] + }, + "linter": { + "rules": { + "a11y": { + "noAriaUnsupportedElements": "warn", + "useAltText": "warn", + "useAriaPropsForRole": "warn", + "useAriaPropsSupportedByRole": "warn", + "useValidAriaProps": "warn", + "useValidAriaValues": "warn" + }, + "correctness": { + "noChildrenProp": "error", + "useExhaustiveDependencies": "warn", + "useHookAtTopLevel": "error", + "useJsxKeyInIterable": "error" + }, + "performance": { + "noImgElement": "warn", + "noUnwantedPolyfillio": "warn", + "useGoogleFontPreconnect": "warn" + }, + "security": { + "noBlankTarget": "warn", + "noDangerouslySetInnerHtmlWithChildren": "error" + }, + "style": { + "noHeadElement": "warn" + }, + "suspicious": { + "noCommentText": "error", + "noDocumentImportInPage": "error", + "noDuplicateJsxProps": "error", + "noHeadImportInDocument": "error", + "useGoogleFontDisplay": "warn" + } + } + } + }, + { + "includes": ["**/*.ts", "**/*.tsx"], + "javascript": { + "globals": [] + } + }, + { + "includes": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + "linter": { + "rules": { + "complexity": { + "noArguments": "error" + }, + "correctness": { + "noConstAssign": "off", + "noGlobalObjectCalls": "off", + "noInvalidBuiltinInstantiation": "off", + "noInvalidConstructorSuper": "off", + "noSetterReturn": "off", + "noUndeclaredVariables": "off", + "noUnreachable": "off", + "noUnreachableSuper": "off" + }, + "style": { + "useConst": "error" + }, + "suspicious": { + "noClassAssign": "off", + "noDuplicateClassMembers": "off", + "noDuplicateObjectKeys": "off", + "noDuplicateParameters": "off", + "noFunctionAssign": "off", + "noImportAssign": "off", + "noRedeclare": "off", + "noUnsafeNegation": "off", + "noVar": "error", + "noWith": "off", + "useGetterReturn": "off" + } + } + } + }, + { + "includes": ["**/*.{json,jsonc}"], + "javascript": { + "formatter": { + "trailingCommas": "none" + } + } + } + ], + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/apps/web/bun.lock b/apps/web/bun.lock index 43f8550..39a5047 100644 --- a/apps/web/bun.lock +++ b/apps/web/bun.lock @@ -9,6 +9,7 @@ "@hugeicons/react": "^1.1.4", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-tabs": "^1.1.13", "@tanstack/react-query": "^5.90.12", "@tanstack/react-query-devtools": "^5.91.1", "axios": "^1.13.2", @@ -22,10 +23,12 @@ "react-hook-form": "^7.70.0", "react-syntax-highlighter": "^16.1.0", "recharts": "^3.6.0", + "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "zod": "^4.1.13", }, "devDependencies": { + "@biomejs/biome": "2.3.11", "@kubb/cli": "^4.15.0", "@kubb/plugin-oas": "^4.15.0", "@kubb/plugin-ts": "^4.15.0", @@ -36,10 +39,9 @@ "@types/react-dom": "^19", "@types/react-syntax-highlighter": "^15.5.13", "ajv": "^8.17.1", - "eslint": "^9", - "eslint-config-next": "16.0.10", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", "openapi-typescript": "^7.10.1", - "prettier": "^3.7.4", "swagger2openapi": "^7.0.8", "tailwindcss": "^4", "typescript": "^5", @@ -53,66 +55,34 @@ "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], - - "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], - - "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], - - "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], - - "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], - - "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], - "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + "@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], - "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="], - "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="], - "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="], - "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="], - "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="], - "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="], - "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], "@clack/core": ["@clack/core@1.0.0-alpha.7", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-3vdh6Ar09D14rVxJZIm3VQJkU+ZOKKT5I5cC0cOVazy70CNyYYjiwRj9unwalhESndgxx6bGc/m6Hhs4EKF5XQ=="], "@clack/prompts": ["@clack/prompts@1.0.0-alpha.8", "", { "dependencies": { "@clack/core": "1.0.0-alpha.7", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-YZGC4BmTKSF5OturNKEz/y4xNjYGmGk6NI785CQucJ7OEdX0qbMmL/zok+9bL6c7qE3WSYffyK5grh2RnkGNtQ=="], - "@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], - "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], - - "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], - - "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], - - "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], - - "@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], - - "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], - - "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], - "@exodus/schemasafe": ["@exodus/schemasafe@1.3.0", "", {}, "sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw=="], "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], @@ -129,16 +99,8 @@ "@hugeicons/react": ["@hugeicons/react@1.1.4", "", { "peerDependencies": { "react": ">=16.0.0" } }, "sha512-gsc3eZyd2fGqRUThW9+lfjxxsOkz6KNVmRXRgJjP32GL0OnnLJnl3hytKt47CBbiQj2xE2kCw+rnP3UQCThcKw=="], - "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], - - "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - "@humanwhocodes/momoa": ["@humanwhocodes/momoa@2.0.4", "", {}, "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA=="], - "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], - "@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="], "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], @@ -219,12 +181,8 @@ "@kubb/react-fabric": ["@kubb/react-fabric@0.9.2", "", { "dependencies": { "@kubb/fabric-core": "0.9.2", "dedent": "^1.7.1", "execa": "^9.6.1", "indent-string": "^5.0.0", "natural-orderby": "^5.0.0", "react-devtools-core": "6.1.2", "signal-exit": "^4.1.0", "ws": "8.18.0" } }, "sha512-67Bkn2+w0Ij8pDHsIHl8Y+0Db8pbQhS9FQy3oCAVaZAITs18Dc95TPOL36ZD7qqBzxlu9QxLlzEjFLUG69NgXA=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], - "@next/env": ["@next/env@16.0.10", "", {}, "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang=="], - "@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.0.10", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-b2NlWN70bbPLmfyoLvvidPKWENBYYIe017ZGUpElvQjDytCWgxPJx7L9juxHt0xHvNVA08ZHJdOyhGzon/KJuw=="], - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg=="], "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw=="], @@ -241,14 +199,6 @@ "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.10", "", { "os": "win32", "cpu": "x64" }, "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], - "@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="], "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="], @@ -293,6 +243,8 @@ "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], @@ -327,8 +279,6 @@ "@reduxjs/toolkit": ["@reduxjs/toolkit@2.11.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ=="], - "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], - "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], "@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="], @@ -377,8 +327,6 @@ "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.91.1", "", { "dependencies": { "@tanstack/query-devtools": "5.91.1" }, "peerDependencies": { "@tanstack/react-query": "^5.90.10", "react": "^18 || ^19" } }, "sha512-tRnJYwEbH0kAOuToy8Ew7bJw1lX3AjkkgSlf/vzb+NpnqmHPdWM+lA2DSdGQSLi1SU0PDRrrCI1vnZnci96CsQ=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], @@ -397,14 +345,10 @@ "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], - "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], - "@types/node": ["@types/node@20.19.26", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg=="], "@types/prismjs": ["@types/prismjs@1.26.5", "", {}, "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ=="], @@ -421,68 +365,6 @@ "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.49.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.49.0", "@typescript-eslint/type-utils": "8.49.0", "@typescript-eslint/utils": "8.49.0", "@typescript-eslint/visitor-keys": "8.49.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.49.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.49.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.49.0", "@typescript-eslint/types": "8.49.0", "@typescript-eslint/typescript-estree": "8.49.0", "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.49.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.49.0", "@typescript-eslint/types": "^8.49.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.49.0", "", { "dependencies": { "@typescript-eslint/types": "8.49.0", "@typescript-eslint/visitor-keys": "8.49.0" } }, "sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.49.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.49.0", "", { "dependencies": { "@typescript-eslint/types": "8.49.0", "@typescript-eslint/typescript-estree": "8.49.0", "@typescript-eslint/utils": "8.49.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.49.0", "", {}, "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.49.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.49.0", "@typescript-eslint/tsconfig-utils": "8.49.0", "@typescript-eslint/types": "8.49.0", "@typescript-eslint/visitor-keys": "8.49.0", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.49.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.49.0", "@typescript-eslint/types": "8.49.0", "@typescript-eslint/typescript-estree": "8.49.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.49.0", "", { "dependencies": { "@typescript-eslint/types": "8.49.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA=="], - - "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], - - "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], - - "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g=="], - - "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ=="], - - "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.11.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw=="], - - "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw=="], - - "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw=="], - - "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ=="], - - "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w=="], - - "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.11.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA=="], - - "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ=="], - - "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew=="], - - "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.11.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg=="], - - "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w=="], - - "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA=="], - - "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.11.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.11" }, "cpu": "none" }, "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ=="], - - "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw=="], - - "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ=="], - - "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], - - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - - "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], - "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], @@ -493,64 +375,30 @@ "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - - "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], - - "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], - - "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], - - "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], - - "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], - - "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], - - "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], - - "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - - "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], - - "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - - "axe-core": ["axe-core@4.11.0", "", {}, "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ=="], - "axios": ["axios@1.13.2", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA=="], - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.9.7", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg=="], - - "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], - "bytes": ["bytes@3.0.0", "", {}, "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="], - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="], "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], @@ -559,7 +407,7 @@ "caniuse-lite": ["caniuse-lite@1.0.30001760", "", {}, "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw=="], - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], "change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="], @@ -573,6 +421,10 @@ "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + + "cli-truncate": ["cli-truncate@5.1.1", "", { "dependencies": { "slice-ansi": "^7.1.0", "string-width": "^8.0.0" } }, "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], @@ -583,12 +435,14 @@ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], - "colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + "commander": ["commander@14.0.2", "", {}, "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ=="], + "compute-gcd": ["compute-gcd@1.2.1", "", { "dependencies": { "validate.io-array": "^1.0.3", "validate.io-function": "^1.0.2", "validate.io-integer-array": "^1.0.0" } }, "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg=="], "compute-lcm": ["compute-lcm@1.1.2", "", { "dependencies": { "compute-gcd": "^1.2.1", "validate.io-array": "^1.0.3", "validate.io-function": "^1.0.2", "validate.io-integer-array": "^1.0.0" } }, "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ=="], @@ -601,8 +455,6 @@ "content-disposition": ["content-disposition@0.5.2", "", {}, "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA=="], - "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - "cosmiconfig": ["cosmiconfig@9.0.0", "", { "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", "parse-json": "^5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -633,14 +485,6 @@ "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], - "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], - - "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], - - "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], - - "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], @@ -651,48 +495,32 @@ "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], - "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], - "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="], - - "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], - "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], - "es-abstract": ["es-abstract@1.24.1", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], - - "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], - "es-toolkit": ["es-toolkit@1.43.0", "", {}, "sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA=="], "es5-ext": ["es5-ext@0.10.64", "", { "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", "esniff": "^2.0.1", "next-tick": "^1.1.0" } }, "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg=="], @@ -707,42 +535,8 @@ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - - "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "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.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], - - "eslint-config-next": ["eslint-config-next@16.0.10", "", { "dependencies": { "@next/eslint-plugin-next": "16.0.10", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-BxouZUm0I45K4yjOOIzj24nTi0H2cGo0y7xUmk+Po/PYtJXFBYVDS1BguE7t28efXjKdcN0tmiLivxQy//SsZg=="], - - "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], - - "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.1", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", "tinyglobby": "^0.2.13", "unrs-resolver": "^1.6.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ=="], - - "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], - - "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], - - "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], - - "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], - - "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="], - - "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], - - "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], - "esniff": ["esniff@2.0.1", "", { "dependencies": { "d": "^1.0.1", "es5-ext": "^0.10.62", "event-emitter": "^0.3.5", "type": "^2.7.2" } }, "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg=="], - "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], - - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], - "event-emitter": ["event-emitter@0.3.5", "", { "dependencies": { "d": "1", "es5-ext": "~0.10.14" } }, "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA=="], "eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="], @@ -753,38 +547,20 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], "fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - "fault": ["fault@1.0.4", "", { "dependencies": { "format": "^0.2.0" } }, "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA=="], - "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], - "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], - - "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + "find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="], "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], - "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "form-data": ["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.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], "format": ["format@0.2.2", "", {}, "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww=="], @@ -795,16 +571,10 @@ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], - - "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], - - "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], - - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + "get-intrinsic": ["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" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], @@ -813,30 +583,12 @@ "get-stream": ["get-stream@9.0.1", "", { "dependencies": { "@sec-ant/readable-stream": "^0.4.1", "is-stream": "^4.0.1" } }, "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA=="], - "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - - "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], - - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - - "globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], - - "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], "gradient-string": ["gradient-string@3.0.0", "", { "dependencies": { "chalk": "^5.3.0", "tinygradient": "^1.1.5" } }, "sha512-frdKI4Qi8Ihp4C6wZNB565de/THpIaw3DjP5ku87M+N9rNSGmPTjfkq61SdRXB7eCaL8O1hkKDvf6CDMtOzIAg=="], - "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], - - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], - - "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], @@ -847,10 +599,6 @@ "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-parse-selector": "^4.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], - "hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], - - "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], - "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], "highlightjs-vue": ["highlightjs-vue@1.0.0", "", {}, "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA=="], @@ -861,102 +609,44 @@ "human-signals": ["human-signals@8.0.1", "", {}, "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ=="], - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "indent-string": ["indent-string@5.0.0", "", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], "index-to-position": ["index-to-position@1.2.0", "", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="], "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], - "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], - - "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], - - "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], - - "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], - - "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], - - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - - "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], - - "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], - "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "^1.0.4", "generator-function": "^2.0.0", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], - "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], - - "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], "is-promise": ["is-promise@2.2.2", "", {}, "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="], - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], - - "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - "is-stream": ["is-stream@4.0.1", "", {}, "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A=="], - "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], - - "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], - - "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], - "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], - "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], - - "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], - - "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], - "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="], @@ -969,10 +659,6 @@ "jsep": ["jsep@1.4.0", "", {}, "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw=="], - "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], "json-schema-compare": ["json-schema-compare@0.2.2", "", { "dependencies": { "lodash": "^4.17.4" } }, "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ=="], @@ -983,10 +669,6 @@ "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - - "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], - "jsonc-parser": ["jsonc-parser@3.2.0", "", {}, "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="], "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], @@ -995,22 +677,12 @@ "jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="], - "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - "ky": ["ky@1.14.2", "", {}, "sha512-q3RBbsO5A5zrPhB6CaCS8ZUv+NWCXv6JJT4Em0i264G9W0fdPB8YRfnnEi7Dm7X7omAkBIPojzYJ2D1oHTHqug=="], - "language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="], - - "language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="], - "latest-version": ["latest-version@9.0.0", "", { "dependencies": { "package-json": "^10.0.0" } }, "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA=="], "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "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" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], @@ -1037,20 +709,20 @@ "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + "lint-staged": ["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.1" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow=="], + + "listr2": ["listr2@9.0.5", "", { "dependencies": { "cli-truncate": "^5.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g=="], + + "locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], - "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], "lowlight": ["lowlight@1.20.0", "", { "dependencies": { "fault": "^1.0.0", "highlight.js": "~10.7.0" } }, "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw=="], - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "lru-queue": ["lru-queue@0.1.0", "", { "dependencies": { "es5-ext": "~0.10.2" } }, "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], @@ -1061,15 +733,15 @@ "memoizee": ["memoizee@0.4.17", "", { "dependencies": { "d": "^1.0.2", "es5-ext": "^0.10.64", "es6-weak-map": "^2.0.3", "event-emitter": "^0.3.5", "is-promise": "^2.2.2", "lru-queue": "^0.1.0", "next-tick": "^1.1.0", "timers-ext": "^0.1.7" } }, "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA=="], - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -1081,11 +753,9 @@ "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "nano-spawn": ["nano-spawn@2.0.0", "", {}, "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw=="], - "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], - - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "natural-orderby": ["natural-orderby@5.0.0", "", {}, "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg=="], @@ -1099,8 +769,6 @@ "node-readfiles": ["node-readfiles@0.2.0", "", { "dependencies": { "es6-promise": "^3.2.1" } }, "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA=="], - "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], - "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], "oas": ["oas@28.8.3", "", { "dependencies": { "@readme/openapi-parser": "^5.5.0", "@types/json-schema": "^7.0.11", "json-schema-merge-allof": "^0.8.1", "jsonpath-plus": "^10.0.0", "jsonpointer": "^5.0.0", "memoizee": "^0.4.16", "openapi-types": "^12.1.1", "path-to-regexp": "^8.1.0", "remove-undefined-objects": "^7.0.0" } }, "sha512-9cAUBz6BomISCoClqJ09aBjBklhNIXC3Ax4F1HVWskfgnmzBsJECSXzQSXBDumusoD/ee2PNVUuMjw0MA+fieQ=="], @@ -1117,21 +785,7 @@ "oas-validator": ["oas-validator@5.0.8", "", { "dependencies": { "call-me-maybe": "^1.0.1", "oas-kit-common": "^1.0.8", "oas-linter": "^3.2.2", "oas-resolver": "^2.5.6", "oas-schema-walker": "^1.1.5", "reftools": "^1.1.9", "should": "^13.2.1", "yaml": "^1.10.0" } }, "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw=="], - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - - "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - - "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - - "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], - - "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], - - "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], - - "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "openapi-fetch": ["openapi-fetch@0.15.0", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-OjQUdi61WO4HYhr9+byCPMj0+bgste/LtSBEcV6FzDdONTs7x0fWn8/ndoYwzqCsKWIxEZwo4FN/TG1c1rI8IQ=="], @@ -1143,13 +797,9 @@ "openapi-typescript-helpers": ["openapi-typescript-helpers@0.0.15", "", {}, "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw=="], - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "p-limit": ["p-limit@7.2.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-ATHLtwoTNDloHRFFxFJdHnG6n2WUeFjaR8XQMFdKIv0xkXjrER8/iG9iu265jOM95zXHAfv9oTkqhrfbIzosrQ=="], - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + "p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], "package-json": ["package-json@10.0.1", "", { "dependencies": { "ky": "^1.2.0", "registry-auth-token": "^5.0.2", "registry-url": "^6.0.1", "semver": "^7.6.0" } }, "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg=="], @@ -1161,46 +811,34 @@ "parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], "path-is-inside": ["path-is-inside@1.0.2", "", {}, "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], - "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], + "pidtree": ["pidtree@0.6.0", "", { "bin": { "pidtree": "bin/pidtree.js" } }, "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g=="], - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + "pluralize": ["pluralize@8.0.0", "", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], - "pretty-ms": ["pretty-ms@9.3.0", "", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], - "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], - "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "range-parser": ["range-parser@1.2.0", "", {}, "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A=="], "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], @@ -1233,14 +871,10 @@ "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], - "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], - "refractor": ["refractor@5.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/prismjs": "^1.0.0", "hastscript": "^9.0.0", "parse-entities": "^4.0.0" } }, "sha512-QXOrHQF5jOpjjLfiNk5GFnWhRXvxjUVnlFxkeDmewR5sXkr3iM46Zo+CnRR8B+MDVqkULW4EcLVcRBNOPXHosw=="], "reftools": ["reftools@1.1.9", "", {}, "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w=="], - "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], - "registry-auth-token": ["registry-auth-token@5.1.0", "", { "dependencies": { "@pnpm/npm-conf": "^2.1.0" } }, "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw=="], "registry-url": ["registry-url@6.0.1", "", { "dependencies": { "rc": "1.2.8" } }, "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q=="], @@ -1255,21 +889,11 @@ "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], - "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], - "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], - - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], @@ -1279,12 +903,6 @@ "serve-handler": ["serve-handler@6.1.6", "", { "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ=="], - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - - "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], - - "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1305,56 +923,32 @@ "should-util": ["should-util@1.0.1", "", {}, "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g=="], - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], - - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], - - "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], - - "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], - "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], - "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], - "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], - - "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], - - "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], - - "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], - - "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], - - "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], - - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - - "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "strip-final-newline": ["strip-final-newline@4.0.0", "", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], - "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "swagger2openapi": ["swagger2openapi@7.0.8", "", { "dependencies": { "call-me-maybe": "^1.0.1", "node-fetch": "^2.6.1", "node-fetch-h2": "^2.3.0", "node-readfiles": "^0.2.0", "oas-kit-common": "^1.0.8", "oas-resolver": "^2.5.6", "oas-schema-walker": "^1.1.5", "oas-validator": "^5.0.8", "reftools": "^1.1.9", "yaml": "^1.10.0", "yargs": "^17.0.1" }, "bin": { "swagger2openapi": "swagger2openapi.js", "oas-validate": "oas-validate.js", "boast": "boast.js" } }, "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g=="], "tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="], @@ -1369,8 +963,6 @@ "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], - "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "tinygradient": ["tinygradient@1.1.5", "", { "dependencies": { "@types/tinycolor2": "^1.4.0", "tinycolor2": "^1.0.0" } }, "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -1379,44 +971,20 @@ "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - - "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], "type": ["type@2.7.3", "", {}, "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ=="], - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], - "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], - - "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], - - "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], - - "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "typescript-eslint": ["typescript-eslint@8.49.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.49.0", "@typescript-eslint/parser": "8.49.0", "@typescript-eslint/typescript-estree": "8.49.0", "@typescript-eslint/utils": "8.49.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg=="], - - "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], - - "update-browserslist-db": ["update-browserslist-db@1.2.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA=="], - - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], @@ -1441,25 +1009,13 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], - - "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], - - "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - - "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - - "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], "yaml-ast-parser": ["yaml-ast-parser@0.0.43", "", {}, "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A=="], @@ -1473,29 +1029,13 @@ "zod": ["zod@4.1.13", "", {}, "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig=="], - "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], - - "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], - - "@eslint/eslintrc/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - - "@kubb/core/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="], - "@kubb/fabric-core/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], "@kubb/oas/@redocly/openapi-core": ["@redocly/openapi-core@2.14.4", "", { "dependencies": { "@redocly/ajv": "^8.17.1", "@redocly/config": "^0.41.1", "ajv-formats": "^3.0.1", "colorette": "^1.2.0", "js-levenshtein": "^1.1.6", "js-yaml": "^4.1.0", "picomatch": "^4.0.3", "pluralize": "^8.0.0", "yaml-ast-parser": "0.0.43" } }, "sha512-FqYf8pBXrZlbhjgcqEpgWrYk3E5j04I4nx0Pn2rMMlDe9S8N9T6axemJGHC6HvrzVJrTWLsUIsV6ndpBICnR2g=="], "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], - "@redocly/openapi-core/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + "@redocly/openapi-core/colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], "@reduxjs/toolkit/immer": ["immer@11.1.3", "", {}, "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q=="], @@ -1511,77 +1051,65 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + "cli-truncate/string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="], - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "cosmiconfig/parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], - "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - - "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], - - "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - - "gradient-string/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], - - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "npm-run-path/unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], - "p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + "oas-linter/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], - "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + "oas-resolver/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + + "oas-validator/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], - "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], "serve-handler/mime-types": ["mime-types@2.1.18", "", { "dependencies": { "mime-db": "~1.33.0" } }, "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ=="], + "serve-handler/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + "serve-handler/path-to-regexp": ["path-to-regexp@3.3.0", "", {}, "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw=="], - "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], - "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "@kubb/core/find-up/locate-path": ["locate-path@7.2.0", "", { "dependencies": { "p-locate": "^6.0.0" } }, "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA=="], + "swagger2openapi/yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], - "@kubb/core/find-up/path-exists": ["path-exists@5.0.0", "", {}, "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ=="], + "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "@kubb/oas/@redocly/openapi-core/@redocly/config": ["@redocly/config@0.41.1", "", { "dependencies": { "json-schema-to-ts": "2.7.2" } }, "sha512-LcMCzFbP/sqkCLSG3YswmeScP4fM5SjDCQizwa+psZ0PhYrKOMF7azZ6ZBkWs115uv5RfOk+jYAWLdKkZGGGXg=="], - "@redocly/openapi-core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@kubb/oas/@redocly/openapi-core/colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@kubb/oas/@redocly/openapi-core/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "serve-handler/mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], - "@kubb/core/find-up/locate-path/p-locate": ["p-locate@6.0.0", "", { "dependencies": { "p-limit": "^4.0.0" } }, "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw=="], + "serve-handler/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], - "@kubb/oas/@redocly/openapi-core/@redocly/config/json-schema-to-ts": ["json-schema-to-ts@2.7.2", "", { "dependencies": { "@babel/runtime": "^7.18.3", "@types/json-schema": "^7.0.9", "ts-algebra": "^1.2.0" } }, "sha512-R1JfqKqbBR4qE8UyBR56Ms30LL62/nlhoz+1UkfI/VE7p54Awu919FZ6ZUPG8zIa3XB65usPJgr1ONVncUGSaQ=="], + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], - "@kubb/core/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="], + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "@kubb/oas/@redocly/openapi-core/@redocly/config/json-schema-to-ts": ["json-schema-to-ts@2.7.2", "", { "dependencies": { "@babel/runtime": "^7.18.3", "@types/json-schema": "^7.0.9", "ts-algebra": "^1.2.0" } }, "sha512-R1JfqKqbBR4qE8UyBR56Ms30LL62/nlhoz+1UkfI/VE7p54Awu919FZ6ZUPG8zIa3XB65usPJgr1ONVncUGSaQ=="], "@kubb/oas/@redocly/openapi-core/@redocly/config/json-schema-to-ts/ts-algebra": ["ts-algebra@1.2.2", "", {}, "sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA=="], } diff --git a/apps/web/eslint.config.mjs b/apps/web/eslint.config.mjs index 05e726d..cf66092 100644 --- a/apps/web/eslint.config.mjs +++ b/apps/web/eslint.config.mjs @@ -3,16 +3,16 @@ import nextVitals from "eslint-config-next/core-web-vitals"; import nextTs from "eslint-config-next/typescript"; const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - ".next/**", - "out/**", - "build/**", - "next-env.d.ts", - ]), + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), ]); export default eslintConfig; diff --git a/apps/web/kubb.config.ts b/apps/web/kubb.config.ts index 059cffa..0e4c43e 100644 --- a/apps/web/kubb.config.ts +++ b/apps/web/kubb.config.ts @@ -1,32 +1,32 @@ -import { defineConfig } from '@kubb/core'; -import { pluginOas } from '@kubb/plugin-oas'; -import { pluginZod } from '@kubb/plugin-zod'; +import { defineConfig } from "@kubb/core"; +import { pluginOas } from "@kubb/plugin-oas"; +import { pluginZod } from "@kubb/plugin-zod"; export default defineConfig({ - root: '.', - input: { - path: './src/lib/api/openapi.json', - }, - output: { - path: './src/lib/api/generated', - clean: true, - extension: { - '.ts': '', + root: ".", + input: { + path: "./src/lib/api/openapi.json", }, - }, - plugins: [ - pluginOas(), - pluginZod({ - output: { - path: './zod.ts', - }, - importPath: 'zod', - unknownType: 'any', - mapper: { - int: 'z.number().int()', - integer: 'z.number().int()', - email: 'z.email()', - } - }), - ], -}); \ No newline at end of file + output: { + path: "./src/lib/api/generated", + clean: true, + extension: { + ".ts": "", + }, + }, + plugins: [ + pluginOas(), + pluginZod({ + output: { + path: "./zod.ts", + }, + importPath: "zod", + unknownType: "any", + mapper: { + int: "z.number().int()", + integer: "z.number().int()", + email: "z.email()", + }, + }), + ], +}); diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index a77f3fc..1945bb7 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -1,35 +1,35 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - async headers() { - return [ - { - source: "/(.*)", - headers: [ - { - key: "X-Frame-Options", - value: "DENY", - }, - { - key: "X-Content-Type-Options", - value: "nosniff", - }, - { - key: "Referrer-Policy", - value: "strict-origin-when-cross-origin", - }, - { - key: "Permissions-Policy", - value: "camera=(), microphone=(), geolocation=(), browsing-topics=()", - }, - { - key: "Strict-Transport-Security", - value: "max-age=63072000; includeSubDomains; preload", - }, - ], - }, - ]; - }, + async headers() { + return [ + { + source: "/(.*)", + headers: [ + { + key: "X-Frame-Options", + value: "DENY", + }, + { + key: "X-Content-Type-Options", + value: "nosniff", + }, + { + key: "Referrer-Policy", + value: "strict-origin-when-cross-origin", + }, + { + key: "Permissions-Policy", + value: "camera=(), microphone=(), geolocation=(), browsing-topics=()", + }, + { + key: "Strict-Transport-Security", + value: "max-age=63072000; includeSubDomains; preload", + }, + ], + }, + ]; + }, }; export default nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json index fb2e65d..e57bcda 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,55 +1,61 @@ { - "name": "frontend", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "bunx next dev --turbopack", - "build": "bunx next build", - "start": "bunx next start", - "lint": "bunx eslint .", - "lint:fix": "bunx eslint --fix .", - "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,md}\" --config .prettierrc.json", - "generate:api": "bunx swagger2openapi ../api/docs/swagger.json --outfile src/lib/api/openapi.json && bunx openapi-typescript src/lib/api/openapi.json -o src/lib/api/schema.d.ts && rm src/lib/api/openapi.json" - }, - "dependencies": { - "@hookform/resolvers": "^5.2.2", - "@hugeicons/core-free-icons": "^3.1.1", - "@hugeicons/react": "^1.1.4", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@tanstack/react-query": "^5.90.12", - "@tanstack/react-query-devtools": "^5.91.1", - "axios": "^1.13.2", - "clsx": "^2.1.1", - "framer-motion": "^12.24.7", - "next": "16.0.10", - "openapi-fetch": "^0.15.0", - "openapi-react-query": "^0.5.1", - "react": "19.2.1", - "react-dom": "19.2.1", - "react-hook-form": "^7.70.0", - "react-syntax-highlighter": "^16.1.0", - "recharts": "^3.6.0", - "tailwind-merge": "^3.4.0", - "zod": "^4.1.13" - }, - "devDependencies": { - "@kubb/cli": "^4.15.0", - "@kubb/plugin-oas": "^4.15.0", - "@kubb/plugin-ts": "^4.15.0", - "@kubb/plugin-zod": "^4.15.0", - "@tailwindcss/postcss": "^4", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "@types/react-syntax-highlighter": "^15.5.13", - "ajv": "^8.17.1", - "eslint": "^9", - "eslint-config-next": "16.0.10", - "openapi-typescript": "^7.10.1", - "prettier": "^3.7.4", - "swagger2openapi": "^7.0.8", - "tailwindcss": "^4", - "typescript": "^5" - } + "name": "frontend", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "bunx next dev --turbopack", + "build": "bunx next build", + "start": "bunx next start", + "lint": "biome check", + "lint:fix": "biome check --write", + "format": "biome format --write", + "prepare": "git config core.hooksPath apps/web/.husky", + "generate:api": "bunx swagger2openapi ../api/docs/swagger.json --outfile src/lib/api/openapi.json && bunx openapi-typescript src/lib/api/openapi.json -o src/lib/api/schema.d.ts && rm src/lib/api/openapi.json" + }, + "lint-staged": { + "**/*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc,md}": ["biome check --write --no-errors-on-unmatched"] + }, + "dependencies": { + "@hookform/resolvers": "^5.2.2", + "@hugeicons/core-free-icons": "^3.1.1", + "@hugeicons/react": "^1.1.4", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-tabs": "^1.1.13", + "@tanstack/react-query": "^5.90.12", + "@tanstack/react-query-devtools": "^5.91.1", + "axios": "^1.13.2", + "clsx": "^2.1.1", + "framer-motion": "^12.24.7", + "next": "16.0.10", + "openapi-fetch": "^0.15.0", + "openapi-react-query": "^0.5.1", + "react": "19.2.1", + "react-dom": "19.2.1", + "react-hook-form": "^7.70.0", + "react-syntax-highlighter": "^16.1.0", + "recharts": "^3.6.0", + "sonner": "^2.0.7", + "tailwind-merge": "^3.4.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@biomejs/biome": "2.3.11", + "@kubb/cli": "^4.15.0", + "@kubb/plugin-oas": "^4.15.0", + "@kubb/plugin-ts": "^4.15.0", + "@kubb/plugin-zod": "^4.15.0", + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "@types/react-syntax-highlighter": "^15.5.13", + "ajv": "^8.17.1", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", + "openapi-typescript": "^7.10.1", + "swagger2openapi": "^7.0.8", + "tailwindcss": "^4", + "typescript": "^5" + } } diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs index 61e3684..148a80b 100644 --- a/apps/web/postcss.config.mjs +++ b/apps/web/postcss.config.mjs @@ -1,7 +1,7 @@ const config = { - plugins: { - "@tailwindcss/postcss": {}, - }, + plugins: { + "@tailwindcss/postcss": {}, + }, }; export default config; diff --git a/apps/web/src/app/auth/login/page.tsx b/apps/web/src/app/auth/login/page.tsx index a12b6b4..9da5d51 100644 --- a/apps/web/src/app/auth/login/page.tsx +++ b/apps/web/src/app/auth/login/page.tsx @@ -1,23 +1,29 @@ "use client"; -import { useSearchParams, useRouter } from "next/navigation"; -import { Suspense, useState, useCallback } from "react"; -import Input from "@/authly/components/ui/Input"; -import Button from "@/authly/components/ui/Button"; -import { generateCodeVerifier, generateCodeChallenge } from "@/authly/lib/oidc"; -import LocalStorageTokenService from "@/authly/lib/services/TokenService"; -import Loader from "@/authly/components/ui/Loader"; - -import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; +import { useRouter, useSearchParams } from "next/navigation"; +import { Suspense, useCallback, useState } from "react"; +import { useForm } from "react-hook-form"; import { z } from "zod"; +import Button from "@/authly/components/ui/Button"; +import Input from "@/authly/components/ui/Input"; +import Loader from "@/authly/components/ui/Loader"; import { githubComAnvoriaAuthlyInternalDomainUserLoginRequestSchema } from "@/authly/lib/api/generated"; import { handleApiErrors } from "@/authly/lib/api/utils"; -import { useLogin } from "@/authly/lib/hooks/useAuth"; import { OIDC_CONFIG } from "@/authly/lib/config"; +import { useLogin } from "@/authly/lib/hooks/useAuth"; +import { generateCodeChallenge, generateCodeVerifier } from "@/authly/lib/oidc"; +import LocalStorageTokenService from "@/authly/lib/services/TokenService"; type LoginFormData = z.infer; +/** + * Renders the login form UI and handles user authentication plus optional OpenID Connect (OIDC) redirect flow. + * + * The component validates credentials, calls the login mutation, displays API and field errors, and upon successful login initiates an OIDC authorization redirect (including PKCE code verifier generation when needed). It also provides a link to the registration page that preserves OIDC parameters when present. + * + * @returns The JSX element for the sign-in page content + */ function LoginPageContent() { const searchParams = useSearchParams(); const router = useRouter(); @@ -144,8 +150,7 @@ function LoginPageContent() {

- Don't have an account?{" "} - {(() => { + Don't have an account? {(() => { const oidcParams = searchParams.get("oidc_params"); return ( ); -} +} \ No newline at end of file diff --git a/apps/web/src/app/auth/register/page.tsx b/apps/web/src/app/auth/register/page.tsx index cc3f912..3d7c408 100644 --- a/apps/web/src/app/auth/register/page.tsx +++ b/apps/web/src/app/auth/register/page.tsx @@ -1,16 +1,15 @@ "use client"; -import { useSearchParams, useRouter } from "next/navigation"; -import { Suspense, useState } from "react"; -import Input from "@/authly/components/ui/Input"; -import Button from "@/authly/components/ui/Button"; -import { HugeiconsIcon } from "@hugeicons/react"; +import { zodResolver } from "@hookform/resolvers/zod"; import { CheckmarkCircle01Icon } from "@hugeicons/core-free-icons"; -import Loader from "@/authly/components/ui/Loader"; - +import { HugeiconsIcon } from "@hugeicons/react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { Suspense, useState } from "react"; import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; +import Button from "@/authly/components/ui/Button"; +import Input from "@/authly/components/ui/Input"; +import Loader from "@/authly/components/ui/Loader"; import { githubComAnvoriaAuthlyInternalDomainUserRegisterRequestSchema } from "@/authly/lib/api/generated"; import { handleApiErrors } from "@/authly/lib/api/utils"; import { useRegister } from "@/authly/lib/hooks/useAuth"; diff --git a/apps/web/src/app/authorize/page.tsx b/apps/web/src/app/authorize/page.tsx index b71e139..cc8582e 100644 --- a/apps/web/src/app/authorize/page.tsx +++ b/apps/web/src/app/authorize/page.tsx @@ -1,20 +1,20 @@ "use client"; -import { useSearchParams, useRouter } from "next/navigation"; -import { Suspense, useEffect, useMemo } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { Suspense, useCallback, useEffect, useMemo } from "react"; import AuthorizeLayout from "@/authly/components/authorize/AuthorizeLayout"; import ConsentScreen from "@/authly/components/authorize/ConsentScreen"; -import { validateAuthorizationParams, buildErrorRedirect } from "@/authly/lib/oidc"; -import { useValidateAuthorization, useConfirmAuthorization } from "@/authly/lib/hooks/useOidc"; -import { useIdPSession } from "@/authly/lib/hooks/useAuth"; -import Loader from "@/authly/components/ui/Loader"; import Button from "@/authly/components/ui/Button"; +import Loader from "@/authly/components/ui/Loader"; +import { OIDC_CONFIG } from "@/authly/lib/config"; +import { useIdPSession } from "@/authly/lib/hooks/useAuth"; +import { useConfirmAuthorization, useValidateAuthorization } from "@/authly/lib/hooks/useOidc"; +import { buildErrorRedirect, validateAuthorizationParams } from "@/authly/lib/oidc"; import { - type ValidateAuthorizationRequestResponse, - type ConfirmAuthorizationResponse, type ApiError, + type ConfirmAuthorizationResponse, + type ValidateAuthorizationRequestResponse, } from "@/authly/lib/schemas/oidc"; -import { OIDC_CONFIG } from "@/authly/lib/config"; interface ErrorState { title: string; @@ -28,6 +28,15 @@ type AuthPageState = | { type: "consent"; client: { name: string; logo_url?: string; client_id: string }; scopes: string[] } | { type: "redirecting" }; +/** + * Render the OIDC authorization page UI and manage the authorization flow lifecycle. + * + * This component validates the incoming OIDC request, checks the IdP session, redirects to login when required, + * presents an error view for invalid requests or clients, shows a consent screen for user approval, and performs + * the confirm/deny actions that ultimately redirect back to the client application. + * + * @returns The component's UI: a loading layout during validation/redirecting or auto-approval, an error view when validation fails, a consent screen when user approval is required, or `null` if no view applies. + */ function AuthorizePageContent() { const searchParams = useSearchParams(); const router = useRouter(); @@ -127,7 +136,7 @@ function AuthorizePageContent() { } }, [state.type, validationParams.params, router]); - const handleApprove = async () => { + const handleApprove = useCallback(async () => { if (!validationParams.params) return; const params = validationParams.params; @@ -168,7 +177,7 @@ function AuthorizePageContent() { }, }, ); - }; + }, [validationParams.params, confirmMutation]); const handleDeny = () => { if (!validationParams.params) return; @@ -181,16 +190,13 @@ function AuthorizePageContent() { window.location.href = errorRedirect; }; + const consentClientId = state.type === "consent" ? state.client.client_id : undefined; + useEffect(() => { - if ( - state.type === "consent" && - state.client.client_id === OIDC_CONFIG.client_id && - !confirmMutation.isPending - ) { + if (state.type === "consent" && consentClientId === OIDC_CONFIG.client_id && !confirmMutation.isPending) { handleApprove(); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [state.type]); + }, [state.type, confirmMutation.isPending, handleApprove, consentClientId]); if ( state.type === "validating" || @@ -263,4 +269,4 @@ export default function AuthorizePage() { ); -} +} \ No newline at end of file diff --git a/apps/web/src/app/callback/page.tsx b/apps/web/src/app/callback/page.tsx index 937b9ca..0fe1bb9 100644 --- a/apps/web/src/app/callback/page.tsx +++ b/apps/web/src/app/callback/page.tsx @@ -1,13 +1,12 @@ "use client"; -import { useEffect, useRef, useState, Suspense } from "react"; import { useRouter, useSearchParams } from "next/navigation"; -import LocalStorageTokenService from "@/authly/lib/services/TokenService"; -import { OIDC_CONFIG } from "@/authly/lib/config"; +import { Suspense, useEffect, useRef, useState } from "react"; import AuthorizeLayout from "@/authly/components/authorize/AuthorizeLayout"; import Button from "@/authly/components/ui/Button"; import Loader from "@/authly/components/ui/Loader"; -import { $api } from "@/authly/lib/api/client"; +import { OIDC_CONFIG } from "@/authly/lib/config"; +import LocalStorageTokenService from "@/authly/lib/services/TokenService"; /** * Handles the OIDC authorization callback by validating callback parameters, exchanging the authorization code for tokens, storing the access token, and navigating on success or presenting an error UI on failure. @@ -18,8 +17,6 @@ function CallbackPageContent() { const [error, setError] = useState(null); const processedRef = useRef(false); - const { mutateAsync: exchangeToken } = $api.useMutation("post", "/oauth/token"); - useEffect(() => { if (processedRef.current) return; processedRef.current = true; @@ -86,7 +83,7 @@ function CallbackPageContent() { }; handleCallback(); - }, [router, searchParams, exchangeToken]); + }, [router, searchParams]); if (error) { return ( diff --git a/apps/web/src/app/dashboard/admin/layout.tsx b/apps/web/src/app/dashboard/admin/layout.tsx index 4ff373b..2df6c8f 100644 --- a/apps/web/src/app/dashboard/admin/layout.tsx +++ b/apps/web/src/app/dashboard/admin/layout.tsx @@ -1,14 +1,13 @@ "use client"; -import AuthlyAdminGuard from "@/authly/components/auth/AuthlyAdminGuard"; -import Sidebar from "@/authly/components/dashboard/Sidebar"; -import { HugeiconsIcon } from "@hugeicons/react"; import { Menu01Icon, User02Icon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import Link from "next/link"; +import { usePathname, useRouter } from "next/navigation"; import { useState } from "react"; +import AuthlyAdminGuard from "@/authly/components/auth/AuthlyAdminGuard"; +import Sidebar from "@/authly/components/dashboard/Sidebar"; import { useAuth } from "@/authly/components/providers/AuthProvider"; -import { usePathname } from "next/navigation"; -import { useRouter } from "next/navigation"; -import Link from "next/link"; const labels: Record = { dashboard: "Dashboard", diff --git a/apps/web/src/app/dashboard/admin/page.tsx b/apps/web/src/app/dashboard/admin/page.tsx index 8caeeaa..64223c9 100644 --- a/apps/web/src/app/dashboard/admin/page.tsx +++ b/apps/web/src/app/dashboard/admin/page.tsx @@ -1,18 +1,18 @@ "use client"; -import { useDashboardStats } from "@/authly/lib/hooks/admin/useStats"; -import { useAuditLogs } from "@/authly/lib/hooks/admin/useAuditLogs"; -import { useDebounce } from "@/authly/lib/hooks/useDebounce"; -import Loader from "@/authly/components/ui/Loader"; -import { StatsCards } from "@/authly/components/dashboard/overview/StatsCards"; +import { AlertCircleIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { useState } from "react"; import { ActivityChart } from "@/authly/components/dashboard/overview/ActivityChart"; import { RecentActivityTable } from "@/authly/components/dashboard/overview/RecentActivityTable"; import { RecentActivityToolbar } from "@/authly/components/dashboard/overview/RecentActivityToolbar"; -import { Pagination } from "@/authly/components/ui/Pagination"; -import { AlertCircleIcon } from "@hugeicons/core-free-icons"; -import { HugeiconsIcon } from "@hugeicons/react"; +import { StatsCards } from "@/authly/components/dashboard/overview/StatsCards"; import Button from "@/authly/components/ui/Button"; -import { useState } from "react"; +import Loader from "@/authly/components/ui/Loader"; +import { Pagination } from "@/authly/components/ui/Pagination"; +import { useAuditLogs } from "@/authly/lib/hooks/admin/useAuditLogs"; +import { useDashboardStats } from "@/authly/lib/hooks/admin/useStats"; +import { useDebounce } from "@/authly/lib/hooks/useDebounce"; /** * Admin dashboard overview page. diff --git a/apps/web/src/app/dashboard/admin/services/[id]/page.tsx b/apps/web/src/app/dashboard/admin/services/[id]/page.tsx new file mode 100644 index 0000000..a39672e --- /dev/null +++ b/apps/web/src/app/dashboard/admin/services/[id]/page.tsx @@ -0,0 +1,122 @@ +"use client"; + +import { ArrowLeft01Icon, SecurityCheckIcon, Settings01Icon, UserGroupIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import Link from "next/link"; +import { use } from "react"; +import { OverviewTab } from "@/authly/components/dashboard/admin/services/OverviewTab"; +import Button from "@/authly/components/ui/Button"; +import Loader from "@/authly/components/ui/Loader"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/authly/components/ui/Tabs"; +import { useAdminService } from "@/authly/lib/hooks/admin/useServices"; + +interface ServicePageProps { + params: Promise<{ id: string }>; +} + +/** + * Renders the admin service detail page for the service identified by the route `id`. + * + * @param params - Promise resolving to an object with the route `id` string used to load the service + * @returns The React element for the service details view, including loading and error states and tabbed content + */ +export default function ServicePage({ params }: ServicePageProps) { + const { id } = use(params); + const { data: response, isLoading, isError } = useAdminService(id); + const service = response?.data?.service; + + if (isLoading) { + return ( +

+ +
+ ); + } + + if (isError || !service) { + return ( +
+

Service not found

+ + + +
+ ); + } + + return ( +
+
+ + + Back to Services + +
+
+
+

{service.name}

+ {service.is_system && ( + + SYSTEM + + )} + + {service.active ? "ACTIVE" : "DISABLED"} + +
+

{service.client_id}

+
+
+
+ + + + + + Overview + + + + Permissions + + + + Roles + + + +
+ + + + {/* TODO: Add Permissions Tab */} + {/* TODO: Add Roles Tab */} +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/app/dashboard/admin/services/page.tsx b/apps/web/src/app/dashboard/admin/services/page.tsx index 518619d..6aa387c 100644 --- a/apps/web/src/app/dashboard/admin/services/page.tsx +++ b/apps/web/src/app/dashboard/admin/services/page.tsx @@ -1,20 +1,20 @@ "use client"; -import { useAdminServices } from "@/authly/lib/hooks/admin/useServices"; +import { AlertCircleIcon, Link01Icon, PlusSignIcon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { PlusSignIcon, AlertCircleIcon, Link01Icon } from "@hugeicons/core-free-icons"; -import Button from "@/authly/components/ui/Button"; -import Loader from "@/authly/components/ui/Loader"; -import { useState, useMemo } from "react"; -import { Modal, ModalTrigger } from "@/authly/components/ui/Modal"; +import { useMemo, useState } from "react"; import { CreateServiceModalContent } from "@/authly/components/dashboard/admin/services/CreateServiceModal"; -import { ServicesTable } from "@/authly/components/dashboard/admin/services/ServicesTable"; import { ServicesEmptyState } from "@/authly/components/dashboard/admin/services/ServicesEmptyState"; +import { ServicesTable } from "@/authly/components/dashboard/admin/services/ServicesTable"; import { - ServicesToolbar, type FilterStatus, + ServicesToolbar, type SortOrder, } from "@/authly/components/dashboard/admin/services/ServicesToolbar"; +import Button from "@/authly/components/ui/Button"; +import Loader from "@/authly/components/ui/Loader"; +import { Modal, ModalTrigger } from "@/authly/components/ui/Modal"; +import { useAdminServices } from "@/authly/lib/hooks/admin/useServices"; /** * Admin page for managing services (OIDC Clients). diff --git a/apps/web/src/app/dashboard/admin/users/page.tsx b/apps/web/src/app/dashboard/admin/users/page.tsx index fed4c6f..ef0f55c 100644 --- a/apps/web/src/app/dashboard/admin/users/page.tsx +++ b/apps/web/src/app/dashboard/admin/users/page.tsx @@ -1,14 +1,14 @@ "use client"; -import { useAdminUsers } from "@/authly/lib/hooks/admin/useUsers"; -import { HugeiconsIcon } from "@hugeicons/react"; import { AlertCircleIcon, UserGroupIcon } from "@hugeicons/core-free-icons"; -import Button from "@/authly/components/ui/Button"; -import Loader from "@/authly/components/ui/Loader"; -import { useState, useEffect } from "react"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { useEffect, useState } from "react"; import { UsersTable } from "@/authly/components/dashboard/admin/users/UsersTable"; import { UsersToolbar } from "@/authly/components/dashboard/admin/users/UsersToolbar"; +import Button from "@/authly/components/ui/Button"; +import Loader from "@/authly/components/ui/Loader"; import { Pagination } from "@/authly/components/ui/Pagination"; +import { useAdminUsers } from "@/authly/lib/hooks/admin/useUsers"; import { useDebounce } from "@/authly/lib/hooks/useDebounce"; const PAGE_SIZE = 50; @@ -16,7 +16,7 @@ const PAGE_SIZE = 50; /** * Render the admin Users management page with a searchable, paginated list of users. * - * The component maintains local search and page state, debounces the search input, resets to page 1 when the debounced search changes, and fetches users with page-size pagination. The UI adapts to loading, error, empty, and populated states and provides controls for searching, clearing the search, retrying failed loads, and changing pages. + * The component maintains local `search` and `page` state, applies a debounced search input for data fetching, and displays appropriate UI for loading, error, empty, and populated states. It provides controls for searching, clearing the search, retrying failed loads, and changing pages. * * @returns The Users management page UI as a JSX element */ @@ -31,7 +31,7 @@ export default function UsersPage() { setPage(1); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [debouncedSearch]); + }, [page]); const offset = (page - 1) * PAGE_SIZE; @@ -99,4 +99,4 @@ export default function UsersPage() {
); -} +} \ No newline at end of file diff --git a/apps/web/src/app/dashboard/page.tsx b/apps/web/src/app/dashboard/page.tsx index 6ef5e3f..6ceaa99 100644 --- a/apps/web/src/app/dashboard/page.tsx +++ b/apps/web/src/app/dashboard/page.tsx @@ -1,7 +1,7 @@ "use client"; -import { useEffect } from "react"; import { useRouter } from "next/navigation"; +import { useEffect } from "react"; import Loader from "@/authly/components/ui/Loader"; /** diff --git a/apps/web/src/app/dashboard/profile/page.tsx b/apps/web/src/app/dashboard/profile/page.tsx index 4858728..4f547c3 100644 --- a/apps/web/src/app/dashboard/profile/page.tsx +++ b/apps/web/src/app/dashboard/profile/page.tsx @@ -1,13 +1,13 @@ "use client"; -import { useMe } from "@/authly/lib/hooks/useAuth"; -import Input from "@/authly/components/ui/Input"; +import { ArrowLeft01Icon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; -import { HugeiconsIcon } from "@hugeicons/react"; -import { ArrowLeft01Icon } from "@hugeicons/core-free-icons"; import Button from "@/authly/components/ui/Button"; +import Input from "@/authly/components/ui/Input"; import Loader from "@/authly/components/ui/Loader"; +import { useMe } from "@/authly/lib/hooks/useAuth"; /** * Render the profile page for the current user and enforce access control. diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 925a8cf..8533389 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -54,16 +54,3 @@ html { background-color: rgba(255, 255, 255, 0.2); color: var(--foreground); } - -/* Focus styles for accessibility */ -:focus-visible { - outline: 2px solid rgba(255, 255, 255, 0.5); - outline-offset: 2px; - border-radius: 2px; -} - -/* Sharp/square icons from Lucide */ -.lucide { - stroke-linecap: square; - stroke-linejoin: miter; -} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index bceb28a..23b1808 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,8 +1,9 @@ import type { Metadata, Viewport } from "next"; -import { Sora, JetBrains_Mono } from "next/font/google"; +import { JetBrains_Mono, Sora } from "next/font/google"; +import { Toaster } from "sonner"; import "./globals.css"; -import QueryProvider from "@/authly/components/providers/QueryProvider"; import AuthProvider from "@/authly/components/providers/AuthProvider"; +import QueryProvider from "@/authly/components/providers/QueryProvider"; const sora = Sora({ subsets: ["latin"], @@ -38,19 +39,22 @@ export const viewport: Viewport = { }; /** - * Provide the application's root HTML structure, apply global font variables, and wrap page content with the QueryProvider. + * Render the application's root HTML structure, apply global font variables, and wrap page content with QueryProvider and AuthProvider. * * @param children - The application content to render inside the layout. - * @returns The `` element (lang="en") containing a `` whose children are wrapped by the QueryProvider. + * @returns The `` element (lang="en") whose `` applies the global font variables and contains `children` wrapped by `QueryProvider` and `AuthProvider`; includes a top-right `Toaster`. */ export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - {children} + + {children} + + ); -} +} \ No newline at end of file diff --git a/apps/web/src/app/not-found.tsx b/apps/web/src/app/not-found.tsx index a3f8272..d62b789 100644 --- a/apps/web/src/app/not-found.tsx +++ b/apps/web/src/app/not-found.tsx @@ -1,8 +1,8 @@ "use client"; -import Image from "next/image"; +import { Alert01Icon, ArrowLeft01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { ArrowLeft01Icon, Alert01Icon } from "@hugeicons/core-free-icons"; +import Image from "next/image"; import Button from "@/authly/components/ui/Button"; /** diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 61483d5..f90127b 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,9 +1,14 @@ -import Navbar from "@/authly/components/landing/Navbar"; -import Hero from "@/authly/components/landing/Hero"; +import CodeExamples from "@/authly/components/landing/CodeExamples"; import Features from "@/authly/components/landing/Features"; import Footer from "@/authly/components/landing/Footer"; -import CodeExamples from "@/authly/components/landing/CodeExamples"; +import Hero from "@/authly/components/landing/Hero"; +import Navbar from "@/authly/components/landing/Navbar"; +/** + * Top-level home page component that composes the landing page layout. + * + * @returns The page's root JSX element containing Navbar, Hero, Features, CodeExamples, and Footer arranged vertically within a main container. + */ export default function Home() { return (
@@ -18,4 +23,4 @@ export default function Home() {
); -} +} \ No newline at end of file diff --git a/apps/web/src/components/auth/AuthGuard.tsx b/apps/web/src/components/auth/AuthGuard.tsx index 81d3e9a..63147fb 100644 --- a/apps/web/src/components/auth/AuthGuard.tsx +++ b/apps/web/src/components/auth/AuthGuard.tsx @@ -1,8 +1,8 @@ "use client"; -import { useAuth } from "@/authly/components/providers/AuthProvider"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; +import { useAuth } from "@/authly/components/providers/AuthProvider"; import Loader from "../ui/Loader"; interface AuthGuardProps { diff --git a/apps/web/src/components/auth/AuthlyAdminGuard.tsx b/apps/web/src/components/auth/AuthlyAdminGuard.tsx index 22db52c..63b33a9 100644 --- a/apps/web/src/components/auth/AuthlyAdminGuard.tsx +++ b/apps/web/src/components/auth/AuthlyAdminGuard.tsx @@ -1,11 +1,11 @@ "use client"; -import { useAuth } from "@/authly/components/providers/AuthProvider"; -import { Bit } from "@/authly/lib/constants/permissions"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; -import Loader from "../ui/Loader"; +import { useAuth } from "@/authly/components/providers/AuthProvider"; import { OIDC_CONFIG } from "@/authly/lib/config"; +import { Bit } from "@/authly/lib/constants/permissions"; +import Loader from "../ui/Loader"; interface AuthlyAdminGuardProps { children: React.ReactNode; diff --git a/apps/web/src/components/authorize/AuthorizeLayout.tsx b/apps/web/src/components/authorize/AuthorizeLayout.tsx index 2b43d42..33e054e 100644 --- a/apps/web/src/components/authorize/AuthorizeLayout.tsx +++ b/apps/web/src/components/authorize/AuthorizeLayout.tsx @@ -1,7 +1,7 @@ "use client"; -import React, { useEffect } from "react"; import Image from "next/image"; +import React, { useEffect } from "react"; export interface AuthorizeLayoutProps { children: React.ReactNode; diff --git a/apps/web/src/components/authorize/ConsentScreen.tsx b/apps/web/src/components/authorize/ConsentScreen.tsx index 3090273..03bbf4c 100644 --- a/apps/web/src/components/authorize/ConsentScreen.tsx +++ b/apps/web/src/components/authorize/ConsentScreen.tsx @@ -47,7 +47,7 @@ export default function ConsentScreen({ {clientLogoUrl && (
- {/* eslint-disable-next-line @next/next/no-img-element */} + {/* biome-ignore lint: lint/performance/noImgElement*/} {clientName}
)} diff --git a/apps/web/src/components/dashboard/Sidebar.tsx b/apps/web/src/components/dashboard/Sidebar.tsx index f21c22d..5dfc2d2 100644 --- a/apps/web/src/components/dashboard/Sidebar.tsx +++ b/apps/web/src/components/dashboard/Sidebar.tsx @@ -1,17 +1,17 @@ "use client"; -import { usePathname } from "next/navigation"; import { DashboardCircleIcon, - Shield01Icon, - Settings01Icon, - Logout01Icon, Link01Icon, + Logout01Icon, + Settings01Icon, + Shield01Icon, UserGroupIcon, } from "@hugeicons/core-free-icons"; -import { cn } from "@/authly/lib/utils"; -import { useEffect, useSyncExternalStore } from "react"; import Image from "next/image"; +import { usePathname } from "next/navigation"; +import { useEffect, useSyncExternalStore } from "react"; +import { cn } from "@/authly/lib/utils"; import { SidebarItem } from "./SidebarItem"; import { SidebarToggle } from "./SidebarToggle"; @@ -67,6 +67,7 @@ export default function Sidebar({ isMobileOpen, setIsMobileOpen }: SidebarProps) window.dispatchEvent(new Event("storage")); }; + // biome-ignore lint/correctness/useExhaustiveDependencies: we want to close the mobile sidebar when the route changes useEffect(() => { setIsMobileOpen(false); }, [pathname, setIsMobileOpen]); diff --git a/apps/web/src/components/dashboard/SidebarItem.tsx b/apps/web/src/components/dashboard/SidebarItem.tsx index 6888358..5187bf9 100644 --- a/apps/web/src/components/dashboard/SidebarItem.tsx +++ b/apps/web/src/components/dashboard/SidebarItem.tsx @@ -1,7 +1,7 @@ "use client"; -import Link from "next/link"; import { HugeiconsIcon, HugeiconsIconProps } from "@hugeicons/react"; +import Link from "next/link"; import { cn } from "@/authly/lib/utils"; interface SidebarItemProps { diff --git a/apps/web/src/components/dashboard/SidebarToggle.tsx b/apps/web/src/components/dashboard/SidebarToggle.tsx index 42e4547..96b5ce4 100644 --- a/apps/web/src/components/dashboard/SidebarToggle.tsx +++ b/apps/web/src/components/dashboard/SidebarToggle.tsx @@ -1,7 +1,7 @@ "use client"; -import { HugeiconsIcon } from "@hugeicons/react"; import { SidebarLeftIcon, SidebarRightIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; import { cn } from "@/authly/lib/utils"; interface SidebarToggleProps { diff --git a/apps/web/src/components/dashboard/admin/services/CreateServiceModal.tsx b/apps/web/src/components/dashboard/admin/services/CreateServiceModal.tsx index 8516f36..fa13021 100644 --- a/apps/web/src/components/dashboard/admin/services/CreateServiceModal.tsx +++ b/apps/web/src/components/dashboard/admin/services/CreateServiceModal.tsx @@ -1,12 +1,13 @@ "use client"; -import { useCreateService } from "@/authly/lib/hooks/admin/useServices"; -import { HugeiconsIcon } from "@hugeicons/react"; import { AlertCircleIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { useState } from "react"; import Button from "@/authly/components/ui/Button"; +import { FormField } from "@/authly/components/ui/FormField"; import Input from "@/authly/components/ui/Input"; import { ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle } from "@/authly/components/ui/Modal"; -import { useState } from "react"; +import { useCreateService } from "@/authly/lib/hooks/admin/useServices"; import { createServiceRequestSchema } from "@/authly/lib/schemas/admin/services"; /** @@ -132,81 +133,96 @@ export function CreateServiceModalContent({ onClose }: { onClose: () => void }) )}
+ + + + + + +
+ { + setFormData((prev) => ({ ...prev, description: e.target.value })); + if (errors.description) + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors.description; + return newErrors; + }); + }} + error={!!errors.description} + /> + + + { + setFormData((prev) => ({ ...prev, domain: e.target.value })); + if (errors.domain) + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors.domain; + return newErrors; + }); + }} + error={!!errors.domain} required /> + + { + setFormData((prev) => ({ ...prev, redirectUri: e.target.value })); + if (errors.redirectUri) + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors.redirectUri; + return newErrors; + }); + }} + error={!!errors.redirectUri} required /> - - setFormData((prev) => ({ ...prev, description: e.target.value }))} - /> - { - setFormData((prev) => ({ ...prev, domain: e.target.value })); - if (errors.domain) - setErrors((prev) => { - const newErrors = { ...prev }; - delete newErrors.domain; - return newErrors; - }); - }} - error={errors.domain} - helperText="Verified domain for this service" - required - /> - { - setFormData((prev) => ({ ...prev, redirectUri: e.target.value })); - if (errors.redirectUri) - setErrors((prev) => { - const newErrors = { ...prev }; - delete newErrors.redirectUri; - return newErrors; - }); - }} - error={errors.redirectUri} - helperText="Comma separated for multiple URIs" - required - /> - + { - setFormData((prev) => ({ ...prev, allowedScopes: e.target.value })); - if (errors.allowedScopes) - setErrors((prev) => { - const newErrors = { ...prev }; - delete newErrors.allowedScopes; - return newErrors; - }); - }} error={errors.allowedScopes} - helperText="Comma separated list of OAuth2 scopes" - required - /> + hint="Comma separated list of OAuth2 scopes" + > + { + setFormData((prev) => ({ ...prev, allowedScopes: e.target.value })); + if (errors.allowedScopes) + setErrors((prev) => { + const newErrors = { ...prev }; + delete newErrors.allowedScopes; + return newErrors; + }); + }} + error={!!errors.allowedScopes} + required + /> + - - {" "} - - ); -} diff --git a/apps/web/src/components/dashboard/admin/services/EditServiceModal.tsx b/apps/web/src/components/dashboard/admin/services/EditServiceModal.tsx deleted file mode 100644 index 1eda8b2..0000000 --- a/apps/web/src/components/dashboard/admin/services/EditServiceModal.tsx +++ /dev/null @@ -1,199 +0,0 @@ -"use client"; - -import { useUpdateService } from "@/authly/lib/hooks/admin/useServices"; -import { HugeiconsIcon } from "@hugeicons/react"; -import { AlertCircleIcon } from "@hugeicons/core-free-icons"; -import Button from "@/authly/components/ui/Button"; -import Input from "@/authly/components/ui/Input"; -import { ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle } from "@/authly/components/ui/Modal"; -import { useState } from "react"; -import { Service, updateServiceRequestSchema } from "@/authly/lib/schemas/admin/services"; - -interface EditServiceModalProps { - service: Service; - onClose: () => void; -} - -/** - * Parses a comma-separated string into a trimmed list of non-empty strings. - */ -const parseCommaSeparatedList = (value: string): string[] => { - return value - .split(",") - .map((item) => item.trim()) - .filter((item) => item !== ""); -}; - -/** - * Component for the Service Editing Form modal content. - */ -export function EditServiceModalContent({ service, onClose }: EditServiceModalProps) { - const { mutate: updateService, isPending, error: updateError } = useUpdateService(); - const [formData, setFormData] = useState({ - name: service.name || "", - description: service.description || "", - domain: service.domain || "", - redirectUris: (service.redirect_uris || []).join(", "), - allowedScopes: (service.allowed_scopes || []).join(", "), - active: !!service.active, - }); - const [errors, setErrors] = useState>({}); - - const handleSubmit = () => { - setErrors({}); - - const redirectUris = parseCommaSeparatedList(formData.redirectUris); - const allowedScopes = parseCommaSeparatedList(formData.allowedScopes); - - const validationResult = updateServiceRequestSchema.safeParse({ - name: formData.name, - description: formData.description, - domain: formData.domain, - active: formData.active, - redirect_uris: redirectUris, - allowed_scopes: allowedScopes, - }); - - if (!validationResult.success) { - const fieldErrors: Record = {}; - validationResult.error.issues.forEach((issue) => { - if (issue.path.length === 0) return; - - const path = String(issue.path[0]); - if (path === "redirect_uris") { - fieldErrors.redirectUris = issue.message; - } else if (path === "allowed_scopes") { - fieldErrors.allowedScopes = issue.message; - } else { - fieldErrors[path] = issue.message; - } - }); - setErrors(fieldErrors); - return; - } - - if (!service.id) { - setErrors({ root: "Service ID is missing" }); - return; - } - - updateService( - { - params: { - path: { id: service.id }, - }, - body: validationResult.data, - }, - { - onSuccess: () => { - onClose(); - }, - }, - ); - }; - - return ( - - - Edit Service: {service.name} - Update application details and OIDC configuration. - -
- {(updateError || errors.root) && ( -
- - {errors.root || updateError?.message || "Failed to update service"} -
- )} - -
-
-

- General Information -

- { - setFormData((prev) => ({ ...prev, name: e.target.value })); - if (errors.name) setErrors((prev) => ({ ...prev, name: "" })); - }} - error={errors.name} - required - /> - { - setFormData((prev) => ({ ...prev, description: e.target.value })); - if (errors.description) setErrors((prev) => ({ ...prev, description: "" })); - }} - error={errors.description} - /> - { - setFormData((prev) => ({ ...prev, domain: e.target.value })); - if (errors.domain) setErrors((prev) => ({ ...prev, domain: "" })); - }} - error={errors.domain} - helperText="Verified domain for this service" - /> -
- -
-

- OIDC Configuration -

- { - setFormData((prev) => ({ ...prev, redirectUris: e.target.value })); - if (errors.redirectUris) setErrors((prev) => ({ ...prev, redirectUris: "" })); - }} - error={errors.redirectUris} - helperText="Comma separated list of valid callback URLs" - /> - { - setFormData((prev) => ({ ...prev, allowedScopes: e.target.value })); - if (errors.allowedScopes) setErrors((prev) => ({ ...prev, allowedScopes: "" })); - }} - error={errors.allowedScopes} - helperText="Comma separated list of OAuth2 scopes" - /> -
- setFormData((prev) => ({ ...prev, active: e.target.checked }))} - className="w-4 h-4 rounded border-white/10 bg-white/5 text-primary focus:ring-primary/20" - /> - -
-
-
-
- - - - -
- ); -} diff --git a/apps/web/src/components/dashboard/admin/services/OverviewTab.tsx b/apps/web/src/components/dashboard/admin/services/OverviewTab.tsx new file mode 100644 index 0000000..078ecc1 --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/OverviewTab.tsx @@ -0,0 +1,49 @@ +"use client"; + +import { useEffect } from "react"; +import { toast } from "sonner"; +import Loader from "@/authly/components/ui/Loader"; +import { useAdminService, useUpdateService } from "@/authly/lib/hooks/admin/useServices"; +import { ServiceForm } from "./overview/ServiceForm"; + +interface OverviewTabProps { + serviceId: string; +} + +/** + * Renders the overview tab for an admin service: loads service data, handles loading and error states, and presents an editable ServiceForm. + * + * Shows an error toast when the service fails to load. + * + * @param serviceId - The ID of the service to load and edit. + * @returns The OverviewTab React element. + */ +export function OverviewTab({ serviceId }: OverviewTabProps) { + const { data: response, isLoading, isError } = useAdminService(serviceId); + const { mutate: updateService, isPending: isUpdating } = useUpdateService(); + const service = response?.data?.service; + + useEffect(() => { + if (isError) { + toast.error("Failed to load service. Please try again."); + } + }, [isError]); + + if (isLoading) + return ( +
+ +
+ ); + if (isError || !service) return
Failed to load service
; + + return ( + + ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/ServiceRow.tsx b/apps/web/src/components/dashboard/admin/services/ServiceRow.tsx index d40a2c2..35c95a8 100644 --- a/apps/web/src/components/dashboard/admin/services/ServiceRow.tsx +++ b/apps/web/src/components/dashboard/admin/services/ServiceRow.tsx @@ -1,34 +1,12 @@ "use client"; +import { CpuIcon, Layout01Icon, ViewIcon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { - Settings01Icon, - Delete02Icon, - Copy01Icon, - CpuIcon, - Layout01Icon, - Tick01Icon, - MoreHorizontalIcon, - Key01Icon, - UserGroupIcon, -} from "@hugeicons/core-free-icons"; +import Link from "next/link"; +import Button from "@/authly/components/ui/Button"; +import { CopyButton } from "@/authly/components/ui/CopyButton"; import { TableCell, TableRow } from "@/authly/components/ui/Table"; -import { cn } from "@/authly/lib/utils"; -import { useState } from "react"; import { Service } from "@/authly/lib/schemas/admin/services"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/authly/components/ui/Dropdown"; -import { Modal } from "@/authly/components/ui/Modal"; -import { EditServiceModalContent } from "./EditServiceModal"; -import { ServiceSecretModalContent } from "./ServiceSecretModal"; -import { DeleteServiceModalContent } from "./DeleteServiceModal"; -import { useCopyToClipboard } from "@/authly/lib/hooks/useCopyToClipboard"; interface ServiceRowProps { service: Service; @@ -36,59 +14,38 @@ interface ServiceRowProps { /** * Render a table row for a service including name/description, a copyable client ID with feedback, - * status and type indicators, an actions menu, and per-row modals for edit, credentials, and delete. + * status and type indicators, and a view button to manage the service. * * @param service - The service object used to populate the row (name, description, client_id, active, is_system). - * @returns A JSX element rendering the table row and its related modals for the provided service. + * @returns A JSX element rendering the table row for the provided service. */ export function ServiceRow({ service }: ServiceRowProps) { - const [copied, copy] = useCopyToClipboard(); - const [activeModal, setActiveModal] = useState<"edit" | "secret" | "delete" | null>(null); - - const handleCopy = () => { - copy(service.client_id || ""); - }; - return ( <> -
-

+ +

{service.name || "Unnamed Service"}

{service.description || "No description"}

-
+
- + {service.client_id && ( + + )} + {service.active ? ( @@ -117,56 +74,18 @@ export function ServiceRow({ service }: ServiceRowProps) { )} - - - - - - Actions - - setActiveModal("edit")}> - - Edit Configuration - - setActiveModal("secret")}> - - View Credentials - - - - Manage Roles - - {!service.is_system && ( - <> - - setActiveModal("delete")} - > - - Delete Service - - - )} - - +
- - {/* Modals */} - !open && setActiveModal(null)}> - setActiveModal(null)} /> - - - !open && setActiveModal(null)}> - setActiveModal(null)} /> - - - !open && setActiveModal(null)}> - setActiveModal(null)} /> - ); } diff --git a/apps/web/src/components/dashboard/admin/services/ServiceSecretModal.tsx b/apps/web/src/components/dashboard/admin/services/ServiceSecretModal.tsx deleted file mode 100644 index e419d6e..0000000 --- a/apps/web/src/components/dashboard/admin/services/ServiceSecretModal.tsx +++ /dev/null @@ -1,111 +0,0 @@ -"use client"; - -import { HugeiconsIcon } from "@hugeicons/react"; -import { Copy01Icon, Tick01Icon, ViewIcon, ViewOffIcon, AlertCircleIcon } from "@hugeicons/core-free-icons"; -import Button from "@/authly/components/ui/Button"; -import { ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle } from "@/authly/components/ui/Modal"; -import { useState } from "react"; -import { Service } from "@/authly/lib/schemas/admin/services"; -import { cn } from "@/authly/lib/utils"; -import { useCopyToClipboard } from "@/authly/lib/hooks/useCopyToClipboard"; - -interface ServiceSecretModalProps { - service: Service; - onClose: () => void; -} - -/** - * Renders a modal that displays a service's client credentials with controls to reveal and copy the client secret. - * - * The modal shows the service's client ID and client secret, provides a toggle to show or hide the secret, a copy - * control that temporarily indicates success, and a warning about secret handling. Clicking the Done button invokes - * `onClose`. - * - * @param service - The service whose credentials are displayed. - * @param onClose - Callback invoked when the modal should be closed (e.g., when the Done button is clicked). - * @returns The modal content element for the service credentials. - */ -export function ServiceSecretModalContent({ service, onClose }: ServiceSecretModalProps) { - const [isVisible, setIsVisible] = useState(false); - const [copied, copy] = useCopyToClipboard(); - - const handleCopy = () => { - if (!service.client_secret) return; - copy(service.client_secret); - }; - - return ( - - - Service Credentials - - Client credentials for {service.name || "Unnamed Service"}. Keep the secret safe! - - -
-
- -
- - {service.client_id || "No Client ID"} - -
-
- -
- -
-
- - {service.client_secret || "No secret found"} - -
-
- - -
-
-
- -
- -

- The client secret is used to authenticate this service. Never share it in public repositories or - client-side code. -

-
-
- - - -
- ); -} diff --git a/apps/web/src/components/dashboard/admin/services/ServicesEmptyState.tsx b/apps/web/src/components/dashboard/admin/services/ServicesEmptyState.tsx index b2659b9..f7b1a88 100644 --- a/apps/web/src/components/dashboard/admin/services/ServicesEmptyState.tsx +++ b/apps/web/src/components/dashboard/admin/services/ServicesEmptyState.tsx @@ -1,11 +1,11 @@ "use client"; +import { PlusSignIcon, Shield01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { Shield01Icon, PlusSignIcon } from "@hugeicons/core-free-icons"; +import { useState } from "react"; import Button from "@/authly/components/ui/Button"; import { Modal, ModalTrigger } from "@/authly/components/ui/Modal"; import { CreateServiceModalContent } from "./CreateServiceModal"; -import { useState } from "react"; interface ServicesEmptyStateProps { isFiltered: boolean; diff --git a/apps/web/src/components/dashboard/admin/services/ServicesToolbar.tsx b/apps/web/src/components/dashboard/admin/services/ServicesToolbar.tsx index d8a258f..6d2fd7a 100644 --- a/apps/web/src/components/dashboard/admin/services/ServicesToolbar.tsx +++ b/apps/web/src/components/dashboard/admin/services/ServicesToolbar.tsx @@ -1,9 +1,8 @@ "use client"; +import { ArrowUpDownIcon, FilterHorizontalIcon, Search01Icon } from "@hugeicons/core-free-icons"; import { HugeiconsIcon } from "@hugeicons/react"; -import { Search01Icon, FilterHorizontalIcon, ArrowUpDownIcon } from "@hugeicons/core-free-icons"; import Button from "@/authly/components/ui/Button"; -import Input from "@/authly/components/ui/Input"; import { DropdownMenu, DropdownMenuContent, @@ -13,6 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/authly/components/ui/Dropdown"; +import Input from "@/authly/components/ui/Input"; export type FilterStatus = "all" | "active" | "disabled"; export type SortOrder = "name" | "created_newest" | "created_oldest"; @@ -50,7 +50,7 @@ export function ServicesToolbar({
} + startIcon={} className="bg-transparent border-white/10 h-9 text-sm" value={search} onChange={(e) => onSearchChange(e.target.value)} diff --git a/apps/web/src/components/dashboard/admin/services/overview/AuthenticationSection.tsx b/apps/web/src/components/dashboard/admin/services/overview/AuthenticationSection.tsx new file mode 100644 index 0000000..536e796 --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/AuthenticationSection.tsx @@ -0,0 +1,126 @@ +"use client"; + +import { Delete02Icon, Link01Icon, PlusSignIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { AnimatePresence, motion } from "framer-motion"; +import Button from "@/authly/components/ui/Button"; +import { FormField } from "@/authly/components/ui/FormField"; +import Input from "@/authly/components/ui/Input"; +import { TagInput } from "@/authly/components/ui/TagInput"; + +interface AuthenticationSectionProps { + redirectURIs: string[]; + allowedScopes: string[]; + newRedirectURI: string; + onAllowedScopesChange: (scopes: string[]) => void; + onNewRedirectURIChange: (uri: string) => void; + onAddRedirect: () => void; + onRemoveRedirect: (index: number) => void; + disabled?: boolean; +} + +/** + * Render the Authentication section of the client settings UI, showing and managing redirect URIs and allowed scopes. + * + * Renders an animated list of `redirectURIs` with optional remove buttons, an input and Add control for new redirect URIs (Enter key triggers add), and a TagInput for `allowedScopes`. + * + * @param redirectURIs - List of redirect URIs to display + * @param allowedScopes - Current allowed OAuth scopes + * @param newRedirectURI - Current value of the new redirect URI input + * @param onAllowedScopesChange - Called with the updated scopes when the TagInput changes + * @param onNewRedirectURIChange - Called with the input value when the new redirect URI changes + * @param onAddRedirect - Called to add the value from `newRedirectURI` to the list + * @param onRemoveRedirect - Called with the index of a redirect URI to remove + * @param disabled - When true, disables inputs and hides remove controls (default: false) + * @returns The React element for the Authentication section + */ +export function AuthenticationSection({ + redirectURIs, + allowedScopes, + newRedirectURI, + onAllowedScopesChange, + onNewRedirectURIChange, + onAddRedirect, + onRemoveRedirect, + disabled = false, +}: AuthenticationSectionProps) { + return ( +
+
+

Authentication

+
+ +
+
+ +
+ + {redirectURIs.map((uri, idx) => ( + +
+ + {uri} +
+ {!disabled && ( + + )} +
+ ))} +
+ +
+ onNewRedirectURIChange(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && (e.preventDefault(), onAddRedirect())} + placeholder="https://..." + className="text-xs" + disabled={disabled} + aria-label="Add redirect URI" + /> + +
+

Callback URLs allowed for this client.

+
+
+ + + + +
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/BasicDetailsSection.tsx b/apps/web/src/components/dashboard/admin/services/overview/BasicDetailsSection.tsx new file mode 100644 index 0000000..bae46be --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/BasicDetailsSection.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { Globe02Icon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { FormField } from "@/authly/components/ui/FormField"; +import Input from "@/authly/components/ui/Input"; + +interface BasicDetailsSectionProps { + name: string; + description: string; + domain: string; + onNameChange: (value: string) => void; + onDescriptionChange: (value: string) => void; + onDomainChange: (value: string) => void; + disabled?: boolean; +} + +/** + * Render the Basic Details form section for editing a service's name, description, and primary domain. + * + * @param name - The current service name displayed in the Service Name input. + * @param description - The current service description displayed in the Description input. + * @param domain - The current primary domain displayed in the Primary Domain input. + * @param onNameChange - Callback invoked with the updated name when the Service Name input changes. + * @param onDescriptionChange - Callback invoked with the updated description when the Description input changes. + * @param onDomainChange - Callback invoked with the updated domain when the Primary Domain input changes. + * @param disabled - When `true`, disables all inputs (defaults to `false`). + * @returns A React element containing the titled section with three labeled inputs and associated hints/icons. + */ +export function BasicDetailsSection({ + name, + description, + domain, + onNameChange, + onDescriptionChange, + onDomainChange, + disabled = false, +}: BasicDetailsSectionProps) { + return ( +
+
+

Basic Details

+
+
+ + onNameChange(e.target.value)} + placeholder="My Awesome App" + disabled={disabled} + aria-label="Service Name" + /> + + + onDescriptionChange(e.target.value)} + placeholder="What does this service do?" + disabled={disabled} + aria-label="Description" + /> + + + onDomainChange(e.target.value)} + placeholder="https://app.example.com" + startIcon={} + disabled={disabled} + aria-label="Primary Domain" + /> + +
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/CredentialsCard.tsx b/apps/web/src/components/dashboard/admin/services/overview/CredentialsCard.tsx new file mode 100644 index 0000000..d97e97e --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/CredentialsCard.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { CopyButton } from "@/authly/components/ui/CopyButton"; + +interface CredentialsCardProps { + clientId: string; + clientSecret: string | null; +} + +/** + * Render a credentials card showing the client ID and client secret with optional copy controls. + * + * The client ID is shown in plain text with a copy button. The client secret, when provided, is displayed masked and includes a copy button; when `null`, the card indicates the client is public. + * + * @param clientId - The client identifier to display and copy + * @param clientSecret - The client secret to display (masked) and copy, or `null` to indicate a public client + * @returns The JSX element representing the credentials card + */ +export function CredentialsCard({ clientId, clientSecret }: CredentialsCardProps) { + return ( +
+

Credentials

+ +
+
+ +
+
+ {clientId} +
+ +
+
+ +
+ +
+
+ {clientSecret ? "••••••••••••••••••••••••••••" : "No Secret (Public)"} +
+ {clientSecret && ( + + )} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/MetadataCard.tsx b/apps/web/src/components/dashboard/admin/services/overview/MetadataCard.tsx new file mode 100644 index 0000000..f490f49 --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/MetadataCard.tsx @@ -0,0 +1,50 @@ +"use client"; + +import { CopyButton } from "@/authly/components/ui/CopyButton"; + +interface MetadataCardProps { + createdAt: string; + updatedAt: string; + serviceId: string; +} + +/** + * Render a compact metadata panel showing creation time, last update, and the service identifier with a copy control. + * + * Created and updated timestamps are parsed with the `Date` constructor and displayed using the runtime locale. + * + * @param createdAt - Timestamp string for when the resource was created; displayed as a localized date/time string + * @param updatedAt - Timestamp string for the last update; displayed as a localized date/time string + * @param serviceId - Service identifier shown in a truncated field with a button to copy the value + * @returns A React element that renders the metadata card UI + */ +export function MetadataCard({ createdAt, updatedAt, serviceId }: MetadataCardProps) { + return ( +
+

Metadata

+
+
+ Created At + {new Date(createdAt).toLocaleString()} +
+
+ Updated At + {new Date(updatedAt).toLocaleString()} +
+
+ Service ID +
+
+ {serviceId} +
+ +
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/SaveActions.tsx b/apps/web/src/components/dashboard/admin/services/overview/SaveActions.tsx new file mode 100644 index 0000000..1f9f78f --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/SaveActions.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { FloppyDiskIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import Button from "@/authly/components/ui/Button"; +import Loader from "@/authly/components/ui/Loader"; +import { cn } from "@/authly/lib/utils"; + +interface SaveActionsProps { + hasChanges: boolean; + isSaving: boolean; + onSave: (e: React.FormEvent) => void; + disabled?: boolean; +} + +/** + * Render an action bar that displays an unsaved changes indicator and a save button. + * + * @param hasChanges - Whether there are unsaved changes to save + * @param isSaving - Whether a save operation is currently in progress + * @param onSave - Handler invoked when the save button is clicked (receives the form event) + * @param disabled - If true, disables the save button regardless of change or saving state + * @returns A JSX element containing the save actions bar + */ +export function SaveActions({ hasChanges, isSaving, onSave, disabled = false }: SaveActionsProps) { + return ( +
+
+ {hasChanges ? ( + +
+ Unsaved changes + + ) : ( + "All changes saved" + )} +
+ +
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/ServiceForm.tsx b/apps/web/src/components/dashboard/admin/services/overview/ServiceForm.tsx new file mode 100644 index 0000000..9230010 --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/ServiceForm.tsx @@ -0,0 +1,196 @@ +"use client"; + +import { useMemo, useState } from "react"; +import { toast } from "sonner"; +import { parseApiError } from "@/authly/lib/api/utils"; +import { isDefaultAuthlyService } from "@/authly/lib/config"; +import { useUpdateService } from "@/authly/lib/hooks/admin/useServices"; +import { Service } from "@/authly/lib/schemas/admin/services"; +import { AuthenticationSection } from "./AuthenticationSection"; +import { BasicDetailsSection } from "./BasicDetailsSection"; +import { CredentialsCard } from "./CredentialsCard"; +import { MetadataCard } from "./MetadataCard"; +import { SaveActions } from "./SaveActions"; +import { StatusCard } from "./StatusCard"; + +type UpdateServiceMutation = ReturnType; +type UpdateServiceMutate = UpdateServiceMutation["mutate"]; + +interface ServiceFormProps { + service: Service; + serviceId: string; + updateService: UpdateServiceMutate; + isUpdating: boolean; +} + +/** + * Renders a form for viewing and editing a service's details in the admin UI. + * + * The form initializes fields from `service`, allows adding/removing redirect URIs (with URL format and duplicate validation), + * and submits changes via the provided `updateService` mutation. It disables editing and prevents updates for the default Authly service + * and surfaces success and API error messages via toasts. + * + * @param service - The service object providing initial field values and metadata. + * @param serviceId - The identifier used when submitting updates for the service. + * @param updateService - Mutation function used to persist changes to the service. + * @param isUpdating - Whether an update request is in progress; disables save actions while true. + * + * @returns The React element for the service edit form. + */ +export function ServiceForm({ service, serviceId, updateService, isUpdating }: ServiceFormProps) { + const isDefaultService = isDefaultAuthlyService(service.id) || isDefaultAuthlyService(service.client_id); + + const [name, setName] = useState(service.name || ""); + const [description, setDescription] = useState(service.description || ""); + const [domain, setDomain] = useState(service.domain || ""); + const [isActive, setIsActive] = useState(service.active); + + const [redirectURIs, setRedirectURIs] = useState(service.redirect_uris || []); + const [allowedScopes, setAllowedScopes] = useState(service.allowed_scopes || []); + + const [newRedirectURI, setNewRedirectURI] = useState(""); + + const hasChanges = useMemo(() => { + const currentRedirects = [...redirectURIs].sort().join(","); + const originalRedirects = [...(service.redirect_uris || [])].sort().join(","); + const currentScopes = [...allowedScopes].sort().join(","); + const originalScopes = [...(service.allowed_scopes || [])].sort().join(","); + + return ( + name !== (service.name || "") || + description !== (service.description || "") || + domain !== (service.domain || "") || + isActive !== service.active || + currentRedirects !== originalRedirects || + currentScopes !== originalScopes + ); + }, [name, description, domain, redirectURIs, allowedScopes, isActive, service]); + + const handleAddRedirect = () => { + const uri = newRedirectURI.trim(); + if (!uri) return; + try { + new URL(uri); + } catch { + toast.error("Invalid URL format"); + return; + } + if (redirectURIs.includes(uri)) { + toast.error("URI already exists"); + return; + } + setRedirectURIs([...redirectURIs, uri]); + setNewRedirectURI(""); + toast.success("Redirect URI added"); + }; + + const handleRemoveRedirect = (index: number) => { + setRedirectURIs(redirectURIs.filter((_, i) => i !== index)); + toast.success("Redirect URI removed"); + }; + + const handleSave = (e: React.FormEvent) => { + e.preventDefault(); + + if (isDefaultService) { + toast.error("Cannot modify the default Authly service"); + return; + } + + updateService( + { + params: { path: { id: serviceId } }, + body: { + name, + description, + domain, + active: isActive, + redirect_uris: redirectURIs, + allowed_scopes: allowedScopes, + }, + }, + { + onSuccess: () => { + toast.success("Service updated successfully"); + }, + onError: (err) => { + const { message, details } = parseApiError(err); + + if (Object.keys(details).length > 0) { + Object.values(details).forEach((detailMessage) => { + toast.error(detailMessage); + }); + } else { + toast.error(message || "Failed to update service"); + } + }, + }, + ); + }; + + return ( +
+
+
+ {isDefaultService && ( +
+

Default Authly Service

+

+ This is the default Authly service used by the dashboard. Some settings cannot be + modified to ensure system stability. +

+
+ )} + + + + + +
+ +
+ + + { + if (!isDefaultService) { + setIsActive(!isActive); + toast.success(`Service ${!isActive ? "activated" : "deactivated"}`); + } + }} + disabled={isDefaultService} + /> + + +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/services/overview/StatusCard.tsx b/apps/web/src/components/dashboard/admin/services/overview/StatusCard.tsx new file mode 100644 index 0000000..7803065 --- /dev/null +++ b/apps/web/src/components/dashboard/admin/services/overview/StatusCard.tsx @@ -0,0 +1,38 @@ +"use client"; + +import Switch from "@/authly/components/ui/Switch"; +import { cn } from "@/authly/lib/utils"; + +interface StatusCardProps { + isActive: boolean; + onToggle: () => void; + disabled?: boolean; +} + +/** + * Renders a status card with a label and a toggle switch for activating or deactivating a service. + * + * @param isActive - Whether the service is currently active + * @param onToggle - Callback invoked when the switch is toggled + * @param disabled - If true, disables user interaction with the switch + * @returns The rendered React element for the status card + */ +export function StatusCard({ isActive, onToggle, disabled = false }: StatusCardProps) { + return ( +
+

Status

+ +
+ + {isActive ? "Active" : "Disabled"} + + onToggle()} + disabled={disabled} + aria-label={`Service status is ${isActive ? "active" : "disabled"}. Click to ${isActive ? "deactivate" : "activate"}.`} + /> +
+
+ ); +} \ No newline at end of file diff --git a/apps/web/src/components/dashboard/admin/users/DeleteUserModal.tsx b/apps/web/src/components/dashboard/admin/users/DeleteUserModal.tsx index 201733b..97fae3e 100644 --- a/apps/web/src/components/dashboard/admin/users/DeleteUserModal.tsx +++ b/apps/web/src/components/dashboard/admin/users/DeleteUserModal.tsx @@ -1,11 +1,11 @@ "use client"; -import { HugeiconsIcon } from "@hugeicons/react"; import { AlertCircleIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; import Button from "@/authly/components/ui/Button"; -import { ModalContent, ModalFooter, ModalHeader, ModalTitle, ModalDescription } from "@/authly/components/ui/Modal"; -import { User } from "@/authly/lib/schemas/admin/users"; +import { ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle } from "@/authly/components/ui/Modal"; import { useDeleteUser } from "@/authly/lib/hooks/admin/useUsers"; +import { User } from "@/authly/lib/schemas/admin/users"; interface DeleteUserModalProps { user: User; diff --git a/apps/web/src/components/dashboard/admin/users/EditUserModal.tsx b/apps/web/src/components/dashboard/admin/users/EditUserModal.tsx index 54eceb6..27a96cb 100644 --- a/apps/web/src/components/dashboard/admin/users/EditUserModal.tsx +++ b/apps/web/src/components/dashboard/admin/users/EditUserModal.tsx @@ -1,12 +1,14 @@ "use client"; -import { useUpdateUser } from "@/authly/lib/hooks/admin/useUsers"; -import { HugeiconsIcon } from "@hugeicons/react"; import { AlertCircleIcon } from "@hugeicons/core-free-icons"; +import { HugeiconsIcon } from "@hugeicons/react"; +import { useState } from "react"; import Button from "@/authly/components/ui/Button"; +import { FormField } from "@/authly/components/ui/FormField"; import Input from "@/authly/components/ui/Input"; import { ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle } from "@/authly/components/ui/Modal"; -import { useState } from "react"; +import Switch from "@/authly/components/ui/Switch"; +import { useUpdateUser } from "@/authly/lib/hooks/admin/useUsers"; import { User, updateUserRequestSchema } from "@/authly/lib/schemas/admin/users"; interface EditUserModalProps { @@ -15,15 +17,14 @@ interface EditUserModalProps { } /** - * Renders a modal containing a form to edit a user's username, email, and active status. + * Render a modal form for editing a user's username, email, and active status. * - * Validates input with the updateUserRequestSchema, displays field-level validation messages - * and server update errors, and submits changes via the useUpdateUser hook. Calls `onClose` - * when the update succeeds or when the Cancel button is clicked. + * Validates input, displays field-level and global update errors, submits changes, + * and closes the modal on successful update or when the Cancel button is clicked. * - * @param user - The user object to edit (pre-fills the form). - * @param onClose - Callback invoked to close the modal. - * @returns The modal content element for editing the user. + * @param user - The user to edit; used to pre-fill form fields + * @param onClose - Callback invoked to close the modal + * @returns The modal content element for editing the user */ export function EditUserModalContent({ user, onClose }: EditUserModalProps) { const { mutate: updateUser, isPending, error: updateError } = useUpdateUser(); @@ -88,28 +89,28 @@ export function EditUserModalContent({ user, onClose }: EditUserModalProps) { )}
- setFormData((prev) => ({ ...prev, username: e.target.value }))} - error={errors.username} - required - /> - setFormData((prev) => ({ ...prev, email: e.target.value }))} - error={errors.email} - /> + + setFormData((prev) => ({ ...prev, username: e.target.value }))} + error={!!errors.username} + required + /> + + + setFormData((prev) => ({ ...prev, email: e.target.value }))} + error={!!errors.email} + /> +
- setFormData((prev) => ({ ...prev, isActive: e.target.checked }))} - className="w-4 h-4 rounded border-white/10 bg-white/5 text-primary focus:ring-primary/20" + onCheckedChange={(checked) => setFormData((prev) => ({ ...prev, isActive: checked }))} />