diff --git a/.gitignore b/.gitignore index de5c12e2..6c0e4b7f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,7 @@ scripts/large-data.sql .vitest-attachments **/test-results/ .worktrees/ +.superpowers/ + +# Repo uses npm; yarn.lock is ignored to avoid double-lockfile drift. +frontend/yarn.lock diff --git a/backend/pom.xml b/backend/pom.xml index 5a733e76..6c415956 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -177,6 +177,13 @@ imageio-tiff 3.12.0 + + + + com.googlecode.owasp-java-html-sanitizer + owasp-java-html-sanitizer + 20240325.1 + diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/GeschichteController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/GeschichteController.java new file mode 100644 index 00000000..b73c5840 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/GeschichteController.java @@ -0,0 +1,69 @@ +package org.raddatz.familienarchiv.controller; + +import lombok.RequiredArgsConstructor; +import org.raddatz.familienarchiv.dto.GeschichteUpdateDTO; +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.raddatz.familienarchiv.security.Permission; +import org.raddatz.familienarchiv.security.RequirePermission; +import org.raddatz.familienarchiv.service.GeschichteService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/geschichten") +@RequiredArgsConstructor +public class GeschichteController { + + private final GeschichteService geschichteService; + + @GetMapping + public List list( + @RequestParam(required = false) GeschichteStatus status, + @RequestParam(name = "personId", required = false) List personIds, + @RequestParam(required = false) UUID documentId, + @RequestParam(required = false, defaultValue = "50") int limit) { + return geschichteService.list( + status, + personIds == null ? List.of() : personIds, + documentId, + limit); + } + + @GetMapping("/{id}") + public Geschichte getById(@PathVariable UUID id) { + return geschichteService.getById(id); + } + + @PostMapping + @RequirePermission(Permission.BLOG_WRITE) + public ResponseEntity create(@RequestBody GeschichteUpdateDTO dto) { + Geschichte created = geschichteService.create(dto); + return ResponseEntity.status(HttpStatus.CREATED).body(created); + } + + @PatchMapping("/{id}") + @RequirePermission(Permission.BLOG_WRITE) + public Geschichte update(@PathVariable UUID id, @RequestBody GeschichteUpdateDTO dto) { + return geschichteService.update(id, dto); + } + + @DeleteMapping("/{id}") + @RequirePermission(Permission.BLOG_WRITE) + public ResponseEntity delete(@PathVariable UUID id) { + geschichteService.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dto/GeschichteUpdateDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dto/GeschichteUpdateDTO.java new file mode 100644 index 00000000..016abb22 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dto/GeschichteUpdateDTO.java @@ -0,0 +1,21 @@ +package org.raddatz.familienarchiv.dto; + +import lombok.Data; +import org.raddatz.familienarchiv.model.GeschichteStatus; + +import java.util.List; +import java.util.UUID; + +/** + * Used for both create and update of a Geschichte. All fields are optional; + * the service applies whatever is non-null. {@code body} is rich-text HTML and + * is sanitised against an allow-list before persistence. + */ +@Data +public class GeschichteUpdateDTO { + private String title; + private String body; + private GeschichteStatus status; + private List personIds; + private List documentIds; +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java b/backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java index 517eb1da..63b4afe4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java @@ -103,6 +103,10 @@ public enum ErrorCode { /** A relationship with the same (person, relatedPerson, type) already exists. 409 */ DUPLICATE_RELATIONSHIP, + // --- Geschichten (Stories) --- + /** A Geschichte (story) with the given ID does not exist, or is a DRAFT and the caller lacks BLOG_WRITE. 404 */ + GESCHICHTE_NOT_FOUND, + // --- Tags --- /** A tag with the given ID does not exist. 404 */ TAG_NOT_FOUND, diff --git a/backend/src/main/java/org/raddatz/familienarchiv/model/Geschichte.java b/backend/src/main/java/org/raddatz/familienarchiv/model/Geschichte.java new file mode 100644 index 00000000..1e1c0116 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/model/Geschichte.java @@ -0,0 +1,69 @@ +package org.raddatz.familienarchiv.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.*; +import lombok.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@Entity +@Table(name = "geschichten") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Geschichte { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private UUID id; + + @Column(nullable = false) + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String title; + + @Column(columnDefinition = "TEXT") + private String body; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + @Builder.Default + private GeschichteStatus status = GeschichteStatus.DRAFT; + + @ManyToOne + @JoinColumn(name = "author_id") + private AppUser author; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "geschichten_persons", + joinColumns = @JoinColumn(name = "geschichte_id"), + inverseJoinColumns = @JoinColumn(name = "person_id")) + @Builder.Default + private Set persons = new HashSet<>(); + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "geschichten_documents", + joinColumns = @JoinColumn(name = "geschichte_id"), + inverseJoinColumns = @JoinColumn(name = "document_id")) + @Builder.Default + private Set documents = new HashSet<>(); + + @CreationTimestamp + @Column(updatable = false) + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createdAt; + + @UpdateTimestamp + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime updatedAt; + + @Column(name = "published_at") + private LocalDateTime publishedAt; +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/model/GeschichteStatus.java b/backend/src/main/java/org/raddatz/familienarchiv/model/GeschichteStatus.java new file mode 100644 index 00000000..5e85cc22 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/model/GeschichteStatus.java @@ -0,0 +1,6 @@ +package org.raddatz.familienarchiv.model; + +public enum GeschichteStatus { + DRAFT, + PUBLISHED +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java new file mode 100644 index 00000000..a207f00a --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java @@ -0,0 +1,12 @@ +package org.raddatz.familienarchiv.repository; + +import org.raddatz.familienarchiv.model.Geschichte; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface GeschichteRepository extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteSpecifications.java b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteSpecifications.java new file mode 100644 index 00000000..27442d60 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteSpecifications.java @@ -0,0 +1,91 @@ +package org.raddatz.familienarchiv.repository; + +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; +import jakarta.persistence.criteria.Subquery; +import org.raddatz.familienarchiv.model.Document; +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.raddatz.familienarchiv.model.Person; +import org.springframework.data.jpa.domain.Specification; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +public final class GeschichteSpecifications { + + private GeschichteSpecifications() {} + + public static Specification hasStatus(GeschichteStatus status) { + return (root, query, cb) -> status == null ? null : cb.equal(root.get("status"), status); + } + + /** + * Adds {@code ORDER BY COALESCE(publishedAt, updatedAt) DESC} to the query without contributing + * a predicate. Combined into the spec chain via {@code .and(...)}; the {@code conjunction} + * acts as a no-op WHERE clause. + */ + public static Specification orderByDisplayDateDesc() { + return (root, query, cb) -> { + // Skip ordering on count queries — JPA forbids orderBy on COUNT projections. + if (query != null + && Long.class != query.getResultType() + && long.class != query.getResultType()) { + query.orderBy(cb.desc(cb.coalesce(root.get("publishedAt"), root.get("updatedAt")))); + } + return cb.conjunction(); + }; + } + + public static Specification hasDocument(UUID documentId) { + return (root, query, cb) -> { + if (documentId == null) return null; + return cb.exists(documentSubquery(root, query, cb, documentId)); + }; + } + + /** + * AND-filter across persons: the Geschichte must be associated with EVERY id in {@code personIds}. + * + *

Implemented as one EXISTS subquery per id (canonical Criteria-API idiom for AND across a + * many-to-many join). Mirrors {@link DocumentSpecifications#hasTags} which uses the same shape. + * Empty / null input returns {@code null} (i.e. no constraint added). + */ + public static Specification hasAllPersons(Collection personIds) { + return (root, query, cb) -> { + if (personIds == null || personIds.isEmpty()) return null; + List predicates = new ArrayList<>(personIds.size()); + for (UUID id : personIds) { + predicates.add(cb.exists(personSubquery(root, query, cb, id))); + } + return cb.and(predicates.toArray(new Predicate[0])); + }; + } + + private static Subquery personSubquery( + Root root, CriteriaQuery query, CriteriaBuilder cb, UUID personId) { + Subquery sub = query.subquery(UUID.class); + Root subRoot = sub.from(Geschichte.class); + Join persons = subRoot.join("persons"); + sub.select(subRoot.get("id")) + .where(cb.equal(subRoot.get("id"), root.get("id")), + cb.equal(persons.get("id"), personId)); + return sub; + } + + private static Subquery documentSubquery( + Root root, CriteriaQuery query, CriteriaBuilder cb, UUID documentId) { + Subquery sub = query.subquery(UUID.class); + Root subRoot = sub.from(Geschichte.class); + Join documents = subRoot.join("documents"); + sub.select(subRoot.get("id")) + .where(cb.equal(subRoot.get("id"), root.get("id")), + cb.equal(documents.get("id"), documentId)); + return sub; + } +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/security/Permission.java b/backend/src/main/java/org/raddatz/familienarchiv/security/Permission.java index f26e6c85..ab5e6ace 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/security/Permission.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/security/Permission.java @@ -4,6 +4,7 @@ public enum Permission { READ_ALL, WRITE_ALL, ANNOTATE_ALL, + BLOG_WRITE, ADMIN, ADMIN_USER, ADMIN_TAG, diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/GeschichteService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/GeschichteService.java new file mode 100644 index 00000000..175af596 --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/GeschichteService.java @@ -0,0 +1,193 @@ +package org.raddatz.familienarchiv.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.owasp.html.HtmlPolicyBuilder; +import org.owasp.html.PolicyFactory; +import org.raddatz.familienarchiv.dto.GeschichteUpdateDTO; +import org.raddatz.familienarchiv.exception.DomainException; +import org.raddatz.familienarchiv.exception.ErrorCode; +import org.raddatz.familienarchiv.model.AppUser; +import org.raddatz.familienarchiv.model.Document; +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.raddatz.familienarchiv.model.Person; +import org.raddatz.familienarchiv.repository.GeschichteRepository; +import org.raddatz.familienarchiv.repository.GeschichteSpecifications; +import org.raddatz.familienarchiv.security.Permission; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +@Slf4j +public class GeschichteService { + + private final GeschichteRepository geschichteRepository; + private final PersonService personService; + private final DocumentService documentService; + private final UserService userService; + + /** + * Allow-list policy for Geschichte body HTML. Tiptap on the writer side + * already constrains the marks/nodes, but the backend re-sanitises every + * save so that an attacker calling the API directly cannot inject more. + */ + private static final PolicyFactory BODY_SANITIZER = new HtmlPolicyBuilder() + .allowElements("p", "br", "strong", "em", "h2", "h3", "ul", "ol", "li") + .toFactory(); + + private static final int DEFAULT_LIMIT = 50; + private static final int MAX_LIMIT = 200; + + // ─── Read API ──────────────────────────────────────────────────────────── + + public Geschichte getById(UUID id) { + Geschichte g = geschichteRepository.findById(id) + .orElseThrow(() -> DomainException.notFound( + ErrorCode.GESCHICHTE_NOT_FOUND, "Geschichte not found: " + id)); + if (g.getStatus() == GeschichteStatus.DRAFT && !currentUserHasBlogWrite()) { + // Use NOT_FOUND, not FORBIDDEN — don't leak DRAFT existence. + throw DomainException.notFound( + ErrorCode.GESCHICHTE_NOT_FOUND, "Geschichte not found: " + id); + } + return g; + } + + /** + * Lists Geschichten with optional filters. {@code personIds} uses AND semantics: the story + * must be associated with every person id supplied. An empty or null list applies no + * person filter. Result is ordered by {@code COALESCE(publishedAt, updatedAt) DESC}. + */ + public List list(GeschichteStatus status, List personIds, UUID documentId, int limit) { + GeschichteStatus effective = currentUserHasBlogWrite() ? status : GeschichteStatus.PUBLISHED; + int safeLimit = limit <= 0 ? DEFAULT_LIMIT : Math.min(limit, MAX_LIMIT); + + Specification spec = Specification.allOf( + GeschichteSpecifications.hasStatus(effective), + GeschichteSpecifications.hasAllPersons(personIds), + GeschichteSpecifications.hasDocument(documentId), + GeschichteSpecifications.orderByDisplayDateDesc() + ); + return geschichteRepository.findAll(spec, Sort.unsorted()) + .stream() + .limit(safeLimit) + .toList(); + } + + // ─── Write API ─────────────────────────────────────────────────────────── + + @Transactional + public Geschichte create(GeschichteUpdateDTO dto) { + requireTitle(dto.getTitle()); + Geschichte g = Geschichte.builder() + .title(dto.getTitle().trim()) + .body(sanitize(dto.getBody())) + .status(GeschichteStatus.DRAFT) + .author(currentUser()) + .persons(resolvePersons(dto.getPersonIds())) + .documents(resolveDocuments(dto.getDocumentIds())) + .build(); + if (dto.getStatus() == GeschichteStatus.PUBLISHED) { + g.setStatus(GeschichteStatus.PUBLISHED); + g.setPublishedAt(LocalDateTime.now()); + } + return geschichteRepository.save(g); + } + + @Transactional + public Geschichte update(UUID id, GeschichteUpdateDTO dto) { + Geschichte g = geschichteRepository.findById(id) + .orElseThrow(() -> DomainException.notFound( + ErrorCode.GESCHICHTE_NOT_FOUND, "Geschichte not found: " + id)); + if (dto.getTitle() != null) { + requireTitle(dto.getTitle()); + g.setTitle(dto.getTitle().trim()); + } + if (dto.getBody() != null) { + g.setBody(sanitize(dto.getBody())); + } + if (dto.getPersonIds() != null) { + g.setPersons(resolvePersons(dto.getPersonIds())); + } + if (dto.getDocumentIds() != null) { + g.setDocuments(resolveDocuments(dto.getDocumentIds())); + } + if (dto.getStatus() != null && dto.getStatus() != g.getStatus()) { + applyStatusTransition(g, dto.getStatus()); + } + return geschichteRepository.save(g); + } + + @Transactional + public void delete(UUID id) { + if (!geschichteRepository.existsById(id)) { + throw DomainException.notFound( + ErrorCode.GESCHICHTE_NOT_FOUND, "Geschichte not found: " + id); + } + geschichteRepository.deleteById(id); + } + + // ─── private helpers ───────────────────────────────────────────────────── + + private void applyStatusTransition(Geschichte g, GeschichteStatus next) { + g.setStatus(next); + if (next == GeschichteStatus.PUBLISHED) { + g.setPublishedAt(LocalDateTime.now()); + } else { + g.setPublishedAt(null); + } + } + + private void requireTitle(String title) { + if (title == null || title.trim().isEmpty()) { + throw DomainException.badRequest( + ErrorCode.VALIDATION_ERROR, "Title is required"); + } + } + + private String sanitize(String body) { + if (body == null) return null; + return BODY_SANITIZER.sanitize(body); + } + + private Set resolvePersons(List ids) { + if (ids == null || ids.isEmpty()) return new HashSet<>(); + return new LinkedHashSet<>(personService.getAllById(ids)); + } + + private Set resolveDocuments(List ids) { + if (ids == null || ids.isEmpty()) return new HashSet<>(); + Set out = new LinkedHashSet<>(); + for (UUID id : ids) { + out.add(documentService.getDocumentById(id)); + } + return out; + } + + private AppUser currentUser() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || !auth.isAuthenticated()) { + throw DomainException.unauthorized("Authentication required"); + } + return userService.findByEmail(auth.getName()); + } + + private boolean currentUserHasBlogWrite() { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + if (auth == null || !auth.isAuthenticated()) return false; + return auth.getAuthorities().stream() + .anyMatch(a -> Permission.BLOG_WRITE.name().equals(a.getAuthority())); + } +} diff --git a/backend/src/main/resources/db/migration/V58__add_geschichten.sql b/backend/src/main/resources/db/migration/V58__add_geschichten.sql new file mode 100644 index 00000000..ec37bdac --- /dev/null +++ b/backend/src/main/resources/db/migration/V58__add_geschichten.sql @@ -0,0 +1,34 @@ +-- Geschichten: blog-like family memory stories linked to persons and documents (issue #381). +-- BLOG_WRITE permission gates authoring; DRAFT stories are never returned to readers. + +CREATE TABLE geschichten ( + id UUID PRIMARY KEY, + title VARCHAR(255) NOT NULL, + body TEXT, + status VARCHAR(32) NOT NULL, + author_id UUID REFERENCES users (id) ON DELETE SET NULL, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL, + published_at TIMESTAMP +); + +CREATE TABLE geschichten_persons ( + geschichte_id UUID NOT NULL REFERENCES geschichten (id) ON DELETE CASCADE, + person_id UUID NOT NULL REFERENCES persons (id) ON DELETE CASCADE, + PRIMARY KEY (geschichte_id, person_id) +); + +CREATE TABLE geschichten_documents ( + geschichte_id UUID NOT NULL REFERENCES geschichten (id) ON DELETE CASCADE, + document_id UUID NOT NULL REFERENCES documents (id) ON DELETE CASCADE, + PRIMARY KEY (geschichte_id, document_id) +); + +-- Index page query: WHERE status = 'PUBLISHED' ORDER BY published_at DESC. +CREATE INDEX idx_geschichten_published + ON geschichten (published_at DESC) + WHERE status = 'PUBLISHED'; + +-- Reverse-lookup indexes for the ?personId / ?documentId filters. +CREATE INDEX idx_geschichten_persons_person ON geschichten_persons (person_id); +CREATE INDEX idx_geschichten_documents_document ON geschichten_documents (document_id); diff --git a/backend/src/main/resources/db/migration/V59__seed_blog_write.sql b/backend/src/main/resources/db/migration/V59__seed_blog_write.sql new file mode 100644 index 00000000..b653072a --- /dev/null +++ b/backend/src/main/resources/db/migration/V59__seed_blog_write.sql @@ -0,0 +1,16 @@ +-- Grant BLOG_WRITE to every existing group that already holds WRITE_ALL. +-- Without this, the Geschichten feature ships dark to production: no group +-- has BLOG_WRITE, so the editor controls are invisible and "+ Neue Geschichte" +-- is never rendered. The natural mapping is "groups that can already write +-- documents and tags can also author family stories." Admins can revoke or +-- re-assign via the group editor afterwards. + +INSERT INTO group_permissions (group_id, permission) +SELECT DISTINCT gp.group_id, 'BLOG_WRITE' +FROM group_permissions gp +WHERE gp.permission = 'WRITE_ALL' + AND NOT EXISTS ( + SELECT 1 FROM group_permissions existing + WHERE existing.group_id = gp.group_id + AND existing.permission = 'BLOG_WRITE' + ); diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/GeschichteControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/GeschichteControllerTest.java new file mode 100644 index 00000000..4c9f721b --- /dev/null +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/GeschichteControllerTest.java @@ -0,0 +1,237 @@ +package org.raddatz.familienarchiv.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.raddatz.familienarchiv.config.SecurityConfig; +import org.raddatz.familienarchiv.dto.GeschichteUpdateDTO; +import org.raddatz.familienarchiv.exception.DomainException; +import org.raddatz.familienarchiv.exception.ErrorCode; +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.raddatz.familienarchiv.security.PermissionAspect; +import org.raddatz.familienarchiv.service.CustomUserDetailsService; +import org.raddatz.familienarchiv.service.GeschichteService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(GeschichteController.class) +@Import({SecurityConfig.class, PermissionAspect.class, AopAutoConfiguration.class}) +class GeschichteControllerTest { + + @Autowired + MockMvc mockMvc; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @MockitoBean + GeschichteService geschichteService; + + @MockitoBean + CustomUserDetailsService customUserDetailsService; + + // ─── GET /api/geschichten ──────────────────────────────────────────────── + + @Test + void list_returns401_whenUnauthenticated() throws Exception { + mockMvc.perform(get("/api/geschichten")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser(authorities = "READ_ALL") + void list_returns200_forReader() throws Exception { + when(geschichteService.list(any(), any(), any(), anyInt())) + .thenReturn(List.of(published(UUID.randomUUID(), "Story A"))); + + mockMvc.perform(get("/api/geschichten")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].title").value("Story A")); + } + + @Test + @WithMockUser(authorities = "READ_ALL") + void list_passesSinglePersonIdFilterToServiceAsListOfOne() throws Exception { + UUID personId = UUID.randomUUID(); + when(geschichteService.list(any(), eq(List.of(personId)), any(), anyInt())) + .thenReturn(List.of()); + + mockMvc.perform(get("/api/geschichten").param("personId", personId.toString())) + .andExpect(status().isOk()); + + verify(geschichteService).list(any(), eq(List.of(personId)), any(), anyInt()); + } + + @Test + @WithMockUser(authorities = "READ_ALL") + void list_passesRepeatedPersonIdParamsAsListForAndFilter() throws Exception { + UUID a = UUID.randomUUID(); + UUID b = UUID.randomUUID(); + when(geschichteService.list(any(), eq(List.of(a, b)), any(), anyInt())) + .thenReturn(List.of()); + + mockMvc.perform(get("/api/geschichten") + .param("personId", a.toString()) + .param("personId", b.toString())) + .andExpect(status().isOk()); + + verify(geschichteService).list(any(), eq(List.of(a, b)), any(), anyInt()); + } + + // ─── GET /api/geschichten/{id} ─────────────────────────────────────────── + + @Test + @WithMockUser(authorities = "READ_ALL") + void getById_returns200_whenFound() throws Exception { + UUID id = UUID.randomUUID(); + when(geschichteService.getById(id)).thenReturn(published(id, "Hello")); + + mockMvc.perform(get("/api/geschichten/{id}", id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(id.toString())) + .andExpect(jsonPath("$.title").value("Hello")); + } + + @Test + @WithMockUser(authorities = "READ_ALL") + void getById_returns404_whenServiceThrowsNotFound() throws Exception { + UUID id = UUID.randomUUID(); + when(geschichteService.getById(id)) + .thenThrow(DomainException.notFound(ErrorCode.GESCHICHTE_NOT_FOUND, "x")); + + mockMvc.perform(get("/api/geschichten/{id}", id)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.code").value("GESCHICHTE_NOT_FOUND")); + } + + // ─── POST /api/geschichten ─────────────────────────────────────────────── + + @Test + void create_returns401_whenUnauthenticated() throws Exception { + mockMvc.perform(post("/api/geschichten") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"title\":\"x\"}")) + .andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser(authorities = "READ_ALL") + void create_returns403_whenLackingBlogWrite() throws Exception { + mockMvc.perform(post("/api/geschichten") + .contentType(MediaType.APPLICATION_JSON) + .content("{\"title\":\"x\"}")) + .andExpect(status().isForbidden()); + } + + @Test + @WithMockUser(authorities = "BLOG_WRITE") + void create_returns201_withBlogWrite() throws Exception { + UUID id = UUID.randomUUID(); + when(geschichteService.create(any(GeschichteUpdateDTO.class))) + .thenReturn(draft(id, "New")); + + GeschichteUpdateDTO dto = new GeschichteUpdateDTO(); + dto.setTitle("New"); + + mockMvc.perform(post("/api/geschichten") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.id").value(id.toString())); + } + + // ─── PATCH /api/geschichten/{id} ───────────────────────────────────────── + + @Test + @WithMockUser(authorities = "READ_ALL") + void update_returns403_whenLackingBlogWrite() throws Exception { + mockMvc.perform(patch("/api/geschichten/{id}", UUID.randomUUID()) + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isForbidden()); + } + + @Test + @WithMockUser(authorities = "BLOG_WRITE") + void update_returns200_withBlogWrite() throws Exception { + UUID id = UUID.randomUUID(); + when(geschichteService.update(eq(id), any(GeschichteUpdateDTO.class))) + .thenReturn(published(id, "Updated")); + + mockMvc.perform(patch("/api/geschichten/{id}", id) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"status\":\"PUBLISHED\"}")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status").value("PUBLISHED")); + } + + // ─── DELETE /api/geschichten/{id} ──────────────────────────────────────── + + @Test + @WithMockUser(authorities = "READ_ALL") + void delete_returns403_whenLackingBlogWrite() throws Exception { + mockMvc.perform(delete("/api/geschichten/{id}", UUID.randomUUID())) + .andExpect(status().isForbidden()); + } + + @Test + @WithMockUser(authorities = "BLOG_WRITE") + void delete_returns204_withBlogWrite() throws Exception { + UUID id = UUID.randomUUID(); + + mockMvc.perform(delete("/api/geschichten/{id}", id)) + .andExpect(status().isNoContent()); + + verify(geschichteService).delete(id); + } + + // ─── helpers ───────────────────────────────────────────────────────────── + + private Geschichte published(UUID id, String title) { + return Geschichte.builder() + .id(id) + .title(title) + .body("

x

") + .status(GeschichteStatus.PUBLISHED) + .publishedAt(LocalDateTime.now()) + .createdAt(LocalDateTime.now()) + .updatedAt(LocalDateTime.now()) + .persons(new HashSet<>()) + .documents(new HashSet<>()) + .build(); + } + + private Geschichte draft(UUID id, String title) { + return Geschichte.builder() + .id(id) + .title(title) + .status(GeschichteStatus.DRAFT) + .createdAt(LocalDateTime.now()) + .updatedAt(LocalDateTime.now()) + .persons(new HashSet<>()) + .documents(new HashSet<>()) + .build(); + } +} diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceIntegrationTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceIntegrationTest.java new file mode 100644 index 00000000..35ed3ada --- /dev/null +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceIntegrationTest.java @@ -0,0 +1,178 @@ +package org.raddatz.familienarchiv.service; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.raddatz.familienarchiv.PostgresContainerConfig; +import org.raddatz.familienarchiv.dto.GeschichteUpdateDTO; +import org.raddatz.familienarchiv.model.AppUser; +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.raddatz.familienarchiv.model.Person; +import org.raddatz.familienarchiv.repository.AppUserRepository; +import org.raddatz.familienarchiv.repository.GeschichteRepository; +import org.raddatz.familienarchiv.repository.PersonRepository; +import org.raddatz.familienarchiv.security.Permission; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import software.amazon.awssdk.services.s3.S3Client; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +@ActiveProfiles("test") +@Import(PostgresContainerConfig.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class GeschichteServiceIntegrationTest { + + @MockitoBean + S3Client s3Client; + + @Autowired GeschichteService geschichteService; + @Autowired GeschichteRepository geschichteRepository; + @Autowired PersonRepository personRepository; + @Autowired AppUserRepository appUserRepository; + + AppUser writer; + AppUser reader; + + @BeforeEach + void seed() { + writer = appUserRepository.save(AppUser.builder() + .email("writer-int@test") + .password("hash") + .build()); + reader = appUserRepository.save(AppUser.builder() + .email("reader-int@test") + .password("hash") + .build()); + } + + @AfterEach + void clear() { + SecurityContextHolder.clearContext(); + } + + @Test + void create_then_publish_then_read_then_delete_full_lifecycle() { + // Create as writer + authenticateAs(writer, Permission.BLOG_WRITE); + + Person franz = personRepository.save(Person.builder().firstName("Franz").lastName("Raddatz").build()); + + GeschichteUpdateDTO dto = new GeschichteUpdateDTO(); + dto.setTitle("Erinnerung an Opa Franz"); + dto.setBody("

Ich erinnere mich, wie er jeden Sonntag sang.

" + + ""); + dto.setPersonIds(List.of(franz.getId())); + + Geschichte created = geschichteService.create(dto); + + assertThat(created.getId()).isNotNull(); + assertThat(created.getStatus()).isEqualTo(GeschichteStatus.DRAFT); + assertThat(created.getBody()) + .contains("jeden Sonntag") + .doesNotContain(""); + + Geschichte saved = geschichteService.create(dto); + + assertThat(saved.getBody()) + .contains("

safe

") + .doesNotContain(""); + + Geschichte saved = geschichteService.update(id, dto); + + assertThat(saved.getBody()).doesNotContain(" + + + +{#each selectedDocuments as doc (doc.id)} + +{/each} + +
(showDropdown = false)}> +
+ {#each selectedDocuments as doc (doc.id)} + + {formatDocLabel(doc)} + + + {/each} + + { + updateDropdownPosition(); + showDropdown = true; + }} + placeholder={placeholder} + class="min-w-[120px] flex-1 border-none bg-transparent p-1 text-sm outline-none focus:ring-0" + /> +
+ + {#if showDropdown && (results.length > 0 || loading)} +
+ {#if loading} +
{m.comp_multiselect_loading()}
+ {:else} + {#each results as doc (doc.id)} +
selectDocument(doc)} + onkeydown={(e) => e.key === 'Enter' && selectDocument(doc)} + role="button" + tabindex="0" + > + {formatDocLabel(doc)} +
+ {/each} + {/if} +
+ {/if} +
diff --git a/frontend/src/lib/components/DocumentMultiSelect.svelte.spec.ts b/frontend/src/lib/components/DocumentMultiSelect.svelte.spec.ts new file mode 100644 index 00000000..b5650fbd --- /dev/null +++ b/frontend/src/lib/components/DocumentMultiSelect.svelte.spec.ts @@ -0,0 +1,126 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page, userEvent } from 'vitest/browser'; +import DocumentMultiSelect from './DocumentMultiSelect.svelte'; + +const waitForDebounce = () => new Promise((r) => setTimeout(r, 350)); + +const docFactory = (id: string, title: string, date = '1880-01-01') => ({ + id, + title, + documentDate: date, + originalFilename: `${title}.pdf`, + status: 'UPLOADED', + metadataComplete: false, + scriptType: 'UNKNOWN' as const, + createdAt: '2024-01-01T00:00:00', + updatedAt: '2024-01-01T00:00:00' +}); + +function mockSearchResponse(items: ReturnType[]) { + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + json: vi.fn().mockResolvedValue({ items: items.map((document) => ({ document })) }) + }) + ); +} + +afterEach(() => { + cleanup(); + vi.unstubAllGlobals(); +}); + +describe('DocumentMultiSelect — rendering', () => { + it('renders an empty chip-input by default', async () => { + render(DocumentMultiSelect); + await expect.element(page.getByPlaceholder('Dokument suchen…')).toBeInTheDocument(); + }); + + it('renders pre-selected documents as chips with their date', async () => { + render(DocumentMultiSelect, { + selectedDocuments: [docFactory('d1', 'Brief vom 1. Mai', '1882-05-01')] + }); + await expect.element(page.getByText(/Brief vom 1\. Mai/)).toBeInTheDocument(); + await expect.element(page.getByText(/01\.05\.1882/)).toBeInTheDocument(); + }); + + it('emits a hidden documentIds input for each pre-selected document', async () => { + render(DocumentMultiSelect, { + selectedDocuments: [docFactory('d1', 'A'), docFactory('d2', 'B')] + }); + const inputs = document.querySelectorAll( + 'input[type="hidden"][name="documentIds"]' + ); + expect(inputs).toHaveLength(2); + expect([inputs[0].value, inputs[1].value].sort()).toEqual(['d1', 'd2']); + }); +}); + +describe('DocumentMultiSelect — search and select', () => { + it('queries /api/documents/search after debounce and shows results', async () => { + mockSearchResponse([docFactory('d1', 'Brief von Eugenie')]); + render(DocumentMultiSelect); + + await userEvent.fill(page.getByPlaceholder('Dokument suchen…'), 'Eug'); + await waitForDebounce(); + + expect(globalThis.fetch).toHaveBeenCalledWith( + expect.stringMatching(/^\/api\/documents\/search\?q=Eug/) + ); + await expect.element(page.getByText(/Brief von Eugenie/)).toBeInTheDocument(); + }); + + it('adds a chip when a search result is clicked', async () => { + mockSearchResponse([docFactory('d1', 'Brief von Eugenie')]); + render(DocumentMultiSelect); + + await userEvent.fill(page.getByPlaceholder('Dokument suchen…'), 'Eug'); + await waitForDebounce(); + await userEvent.click(page.getByText(/Brief von Eugenie/)); + + // After selection the search field clears and the chip is rendered + const hidden = document.querySelector( + 'input[type="hidden"][name="documentIds"]' + ); + expect(hidden?.value).toBe('d1'); + }); + + it('hides already-selected documents from new search results', async () => { + const fetchMock = vi.fn().mockResolvedValue({ + ok: true, + json: vi.fn().mockResolvedValue({ + items: [ + { document: docFactory('d1', 'Already attached') }, + { document: docFactory('d2', 'Not attached') } + ] + }) + }); + vi.stubGlobal('fetch', fetchMock); + + render(DocumentMultiSelect, { + selectedDocuments: [docFactory('d1', 'Already attached')] + }); + + await userEvent.fill(page.getByPlaceholder('Dokument suchen…'), 'attached'); + await waitForDebounce(); + + // "Not attached" appears in the dropdown; "Already attached" only as the chip. + const matches = await page.getByText(/Already attached/).all(); + expect(matches.length).toBe(1); // chip only, not in dropdown + await expect.element(page.getByText(/Not attached/)).toBeInTheDocument(); + }); +}); + +describe('DocumentMultiSelect — remove', () => { + it('removes a chip when its × button is clicked', async () => { + render(DocumentMultiSelect, { + selectedDocuments: [docFactory('d1', 'Brief A')] + }); + await userEvent.click(page.getByLabelText('Entfernen')); + expect( + document.querySelector('input[type="hidden"][name="documentIds"]') + ).toBeNull(); + }); +}); diff --git a/frontend/src/lib/components/DocumentTopBar.svelte b/frontend/src/lib/components/DocumentTopBar.svelte index 15cadd6b..5e480a55 100644 --- a/frontend/src/lib/components/DocumentTopBar.svelte +++ b/frontend/src/lib/components/DocumentTopBar.svelte @@ -25,12 +25,21 @@ type Doc = { tags?: Tag[] | null; }; +type GeschichteSummary = { + id: string; + title: string; + publishedAt?: string; + author?: { firstName?: string; lastName?: string; email: string }; +}; + type Props = { doc: Doc; canWrite: boolean; fileUrl: string; transcribeMode: boolean; inferredRelationship?: { labelFromA: string; labelFromB: string } | null; + geschichten?: GeschichteSummary[]; + canBlogWrite?: boolean; }; let { @@ -38,7 +47,9 @@ let { canWrite, fileUrl, transcribeMode = $bindable(), - inferredRelationship = null + inferredRelationship = null, + geschichten = [], + canBlogWrite = false }: Props = $props(); let detailsOpen = $state(false); @@ -283,6 +294,9 @@ let mobileMenuOpen = $state(false); receivers={doc.receivers ? [...doc.receivers] : []} tags={doc.tags ? [...doc.tags] : []} inferredRelationship={inferredRelationship} + geschichten={geschichten} + documentId={doc.id} + canBlogWrite={canBlogWrite} /> {/if} diff --git a/frontend/src/lib/components/GeschichteEditor.svelte b/frontend/src/lib/components/GeschichteEditor.svelte new file mode 100644 index 00000000..70ff118b --- /dev/null +++ b/frontend/src/lib/components/GeschichteEditor.svelte @@ -0,0 +1,329 @@ + + +
+ +
+ +
+ + {#if showTitleError} + + {/if} +
+ + + + + +
+
+
+
+ + + +
+ + +
+

+ {isDraft + ? m.geschichte_editor_save_hint_draft() + : m.geschichte_editor_save_hint_published()} +

+
+ {#if isDraft} + + + {:else} + + + {/if} +
+
diff --git a/frontend/src/lib/components/GeschichteEditor.svelte.spec.ts b/frontend/src/lib/components/GeschichteEditor.svelte.spec.ts new file mode 100644 index 00000000..9207deab --- /dev/null +++ b/frontend/src/lib/components/GeschichteEditor.svelte.spec.ts @@ -0,0 +1,150 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page, userEvent } from 'vitest/browser'; +import GeschichteEditor from './GeschichteEditor.svelte'; + +const personFactory = (id: string, displayName: string) => ({ + id, + firstName: displayName.split(' ')[0], + lastName: displayName.split(' ').slice(1).join(' ') || displayName, + displayName, + personType: 'PERSON' as const +}); + +const docFactory = (id: string, title: string, date = '1882-01-01') => ({ + id, + title, + documentDate: date, + originalFilename: `${title}.pdf`, + status: 'UPLOADED' as const, + metadataComplete: false, + scriptType: 'UNKNOWN' as const, + createdAt: '2024-01-01T00:00:00', + updatedAt: '2024-01-01T00:00:00' +}); + +const draftFactory = (overrides: Record = {}) => ({ + id: 'g1', + title: 'Existing draft', + body: '

Hello world

', + status: 'DRAFT' as const, + persons: [], + documents: [], + createdAt: '2024-01-01T00:00:00', + updatedAt: '2024-01-01T00:00:00', + ...overrides +}); + +afterEach(() => cleanup()); + +describe('GeschichteEditor — title-required guard', () => { + it('disables both DRAFT save buttons when the title is empty', async () => { + const onSubmit = vi.fn().mockResolvedValue(undefined); + render(GeschichteEditor, { onSubmit }); + + const draft = await page.getByRole('button', { name: 'Entwurf speichern' }).element(); + const publish = await page.getByRole('button', { name: 'Veröffentlichen' }).element(); + expect(draft).toHaveProperty('disabled', true); + expect(publish).toHaveProperty('disabled', true); + }); + + it('shows the inline error after the title field is blurred while empty', async () => { + const onSubmit = vi.fn(); + render(GeschichteEditor, { onSubmit }); + + await userEvent.click(page.getByPlaceholder('Titel der Geschichte')); + await userEvent.tab(); // blur + await expect.element(page.getByText('Bitte gib einen Titel ein.')).toBeInTheDocument(); + }); +}); + +describe('GeschichteEditor — save bar adapts to status', () => { + it('renders DRAFT mode buttons when no geschichte prop is supplied', async () => { + render(GeschichteEditor, { onSubmit: vi.fn() }); + await expect + .element(page.getByRole('button', { name: 'Entwurf speichern' })) + .toBeInTheDocument(); + await expect.element(page.getByRole('button', { name: 'Veröffentlichen' })).toBeInTheDocument(); + }); + + it('renders PUBLISHED mode buttons when geschichte.status is PUBLISHED', async () => { + render(GeschichteEditor, { + geschichte: draftFactory({ status: 'PUBLISHED', publishedAt: '2024-04-01T12:00:00' }), + onSubmit: vi.fn() + }); + await expect.element(page.getByRole('button', { name: 'Speichern' })).toBeInTheDocument(); + await expect + .element(page.getByRole('button', { name: 'Zurück zu Entwurf' })) + .toBeInTheDocument(); + }); +}); + +describe('GeschichteEditor — pre-fill', () => { + it('renders initial persons as chips', async () => { + render(GeschichteEditor, { + initialPersons: [personFactory('p1', 'Franz Raddatz')], + onSubmit: vi.fn() + }); + await expect.element(page.getByText('Franz Raddatz')).toBeInTheDocument(); + }); + + it('renders initial documents as chips', async () => { + render(GeschichteEditor, { + initialDocuments: [docFactory('d1', 'Brief von Eugenie')], + onSubmit: vi.fn() + }); + await expect.element(page.getByText(/Brief von Eugenie/)).toBeInTheDocument(); + }); + + it('populates the title input from a geschichte prop', async () => { + render(GeschichteEditor, { + geschichte: draftFactory({ title: 'My existing story' }), + onSubmit: vi.fn() + }); + const input = await page.getByPlaceholder('Titel der Geschichte').element(); + expect((input as HTMLInputElement).value).toBe('My existing story'); + }); +}); + +describe('GeschichteEditor — onSubmit payload', () => { + it('passes the trimmed title and DRAFT status when "Entwurf speichern" is clicked', async () => { + const onSubmit = vi.fn().mockResolvedValue(undefined); + render(GeschichteEditor, { onSubmit }); + + await userEvent.fill(page.getByPlaceholder('Titel der Geschichte'), ' My title '); + await userEvent.click(page.getByRole('button', { name: 'Entwurf speichern' })); + + expect(onSubmit).toHaveBeenCalledTimes(1); + const payload = onSubmit.mock.calls[0][0]; + expect(payload.title).toBe('My title'); + expect(payload.status).toBe('DRAFT'); + }); + + it('passes status=PUBLISHED when "Veröffentlichen" is clicked', async () => { + const onSubmit = vi.fn().mockResolvedValue(undefined); + render(GeschichteEditor, { onSubmit }); + + await userEvent.fill(page.getByPlaceholder('Titel der Geschichte'), 'Story'); + await userEvent.click(page.getByRole('button', { name: 'Veröffentlichen' })); + + expect(onSubmit).toHaveBeenCalledTimes(1); + expect(onSubmit.mock.calls[0][0].status).toBe('PUBLISHED'); + }); + + it('passes the personIds and documentIds from initial props through onSubmit', async () => { + const onSubmit = vi.fn().mockResolvedValue(undefined); + render(GeschichteEditor, { + initialPersons: [personFactory('p1', 'Franz Raddatz')], + initialDocuments: [docFactory('d1', 'Brief A')], + onSubmit + }); + + await userEvent.fill(page.getByPlaceholder('Titel der Geschichte'), 'Story'); + await userEvent.click(page.getByRole('button', { name: 'Entwurf speichern' })); + + expect(onSubmit).toHaveBeenCalledTimes(1); + const payload = onSubmit.mock.calls[0][0]; + expect(payload.personIds).toEqual(['p1']); + expect(payload.documentIds).toEqual(['d1']); + }); +}); diff --git a/frontend/src/lib/components/GeschichtenCard.svelte b/frontend/src/lib/components/GeschichtenCard.svelte new file mode 100644 index 00000000..e5d840f5 --- /dev/null +++ b/frontend/src/lib/components/GeschichtenCard.svelte @@ -0,0 +1,89 @@ + + +{#if geschichten.length > 0} +
+
+

+ {m.geschichten_card_heading()} +

+ {#if canWrite} + + {m.geschichten_card_write_action()} + + {/if} +
+ + + + {#if hasOverflow} + + {/if} +
+{/if} diff --git a/frontend/src/lib/components/GeschichtenCard.svelte.spec.ts b/frontend/src/lib/components/GeschichtenCard.svelte.spec.ts new file mode 100644 index 00000000..c73f66d9 --- /dev/null +++ b/frontend/src/lib/components/GeschichtenCard.svelte.spec.ts @@ -0,0 +1,140 @@ +import { afterEach, describe, expect, it } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; +import GeschichtenCard from './GeschichtenCard.svelte'; + +const makeStory = (id: string, title: string, body: string | null = '

Body

') => ({ + id, + title, + body, + status: 'PUBLISHED' as const, + publishedAt: '2024-04-01T12:00:00', + createdAt: '2024-03-01T12:00:00', + updatedAt: '2024-04-01T12:00:00', + persons: [], + documents: [], + author: { + id: 'u1', + email: 'marcel@example.com', + firstName: 'Marcel', + lastName: 'Raddatz', + enabled: true, + notifyOnReply: false, + notifyOnMention: false, + groups: [], + createdAt: '2024-01-01T00:00:00', + color: '#000' + } +}); + +afterEach(() => cleanup()); + +describe('GeschichtenCard', () => { + it('renders nothing when geschichten is empty', async () => { + render(GeschichtenCard, { + geschichten: [], + personId: 'p1', + personName: 'Franz', + canWrite: true + }); + // No heading, no list — the entire
should not exist + expect( + document.querySelector('section[aria-labelledby="geschichten-card-heading"]') + ).toBeNull(); + }); + + it('renders the section heading and stories when geschichten is non-empty', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'Erinnerung an Franz')], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + await expect.element(page.getByText('Geschichten')).toBeInTheDocument(); + // The whole row is one link to the story; matching on the title text via + // a partial regex tolerates trailing author/date metadata in the + // accessible name. + const link = await page + .getByRole('link', { name: /Erinnerung an Franz/ }) + .first() + .element(); + expect(link.getAttribute('href')).toBe('/geschichten/g1'); + }); + + it('makes the entire story row a single clickable link', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'A title', '

Some body excerpt text

')], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + // The body-excerpt text is inside the same as the title. + const links = await page.getByRole('link', { name: /A title/ }).all(); + expect(links.length).toBeGreaterThan(0); + const linkEl = await links[0].element(); + expect(linkEl.tagName).toBe('A'); + expect(linkEl.textContent).toContain('Some body excerpt text'); + }); + + it('hides the "+ Geschichte schreiben" link when canWrite is false', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'A story')], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + const writeLinks = await page.getByText(/Geschichte schreiben/).all(); + expect(writeLinks).toHaveLength(0); + }); + + it('shows the write-action link only when canWrite is true', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'A story')], + personId: 'p1', + personName: 'Franz', + canWrite: true + }); + const link = await page.getByRole('link', { name: /Geschichte schreiben/ }).element(); + expect(link.getAttribute('href')).toBe('/geschichten/new?personId=p1'); + }); + + it('hides the "Alle Geschichten zu …" footer link below the 3-story threshold', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'A'), makeStory('g2', 'B')], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + const overflow = await page.getByText(/Alle Geschichten zu/).all(); + expect(overflow).toHaveLength(0); + }); + + it('shows the footer link at the 3-story threshold (>= 3)', async () => { + render(GeschichtenCard, { + geschichten: [makeStory('g1', 'A'), makeStory('g2', 'B'), makeStory('g3', 'C')], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + const link = await page.getByRole('link', { name: /Alle Geschichten zu Franz/ }).element(); + expect(link.getAttribute('href')).toBe('/geschichten?personId=p1'); + }); + + it('renders a plain-text excerpt without HTML markup', async () => { + render(GeschichtenCard, { + geschichten: [ + makeStory( + 'g1', + 'Mit HTML', + '

Plain bold story

' + ) + ], + personId: 'p1', + personName: 'Franz', + canWrite: false + }); + // Body excerpt appears once as plain text — no rendered, no script + await expect.element(page.getByText(/Plain bold story/)).toBeInTheDocument(); + expect(document.body.innerHTML).not.toContain(''); + expect(out).not.toContain(''); + }); + + it('drops markup', () => { + const out = extractText(''); + expect(out).not.toContain(' markup', () => { + const out = extractText('

short

', 80)).toBe('short'); + }); + + it('truncates at the boundary with an ellipsis', () => { + const html = '

' + 'a'.repeat(100) + '

'; + const out = plainExcerpt(html, 20); + expect(out.length).toBeLessThanOrEqual(21); + expect(out.endsWith('…')).toBe(true); + }); + + it('breaks at a word boundary when possible', () => { + const out = plainExcerpt('

The quick brown fox jumps over

', 18); + expect(out).toBe('The quick brown…'); + }); +}); diff --git a/frontend/src/lib/utils/extractText.ts b/frontend/src/lib/utils/extractText.ts new file mode 100644 index 00000000..331d9dea --- /dev/null +++ b/frontend/src/lib/utils/extractText.ts @@ -0,0 +1,38 @@ +/** + * **Not a sanitizer.** This module extracts visible text from a (presumed + * already-sanitised) HTML string for excerpt rendering. It is safe ONLY + * because the Geschichte body is sanitised against the OWASP allow-list + * on the server before persistence, and via DOMPurify on render. + * + * Do not use these helpers to defend against XSS — `safeHtml()` in + * `./sanitize.ts` is the only sanitiser. Calling `extractText()` on + * untrusted input that has not been sanitised does not protect against + * `javascript:` URLs, event-handler attributes, or `` payloads. + */ + +/** + * Strip tags and return plain text. Uses DOMParser in the browser; on the + * server it falls back to a regex that drops angle-bracket sequences. + * The fallback is **not** a sanitiser — see module docstring. + */ +export function extractText(html: string | null | undefined): string { + if (!html) return ''; + if (typeof DOMParser === 'function') { + const doc = new DOMParser().parseFromString(html, 'text/html'); + return (doc.body.textContent ?? '').replace(/\s+/g, ' ').trim(); + } + return html + .replace(/<[^>]*>/g, '') + .replace(/\s+/g, ' ') + .trim(); +} + +/** + * Strip tags then truncate to `max` chars on a word boundary, appending an + * ellipsis when truncated. Used for editorial story excerpts. + */ +export function plainExcerpt(html: string | null | undefined, max = 80): string { + const text = extractText(html); + if (text.length <= max) return text; + return text.slice(0, max).replace(/\s+\S*$/, '') + '…'; +} diff --git a/frontend/src/lib/utils/sanitize.spec.ts b/frontend/src/lib/utils/sanitize.spec.ts new file mode 100644 index 00000000..9495063d --- /dev/null +++ b/frontend/src/lib/utils/sanitize.spec.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest'; +import { safeHtml } from './sanitize'; + +describe('safeHtml', () => { + it('returns empty string for null/undefined/empty input', () => { + expect(safeHtml(null)).toBe(''); + expect(safeHtml(undefined)).toBe(''); + expect(safeHtml('')).toBe(''); + }); + + it('keeps allowed tags: p, strong, em, br, h2, h3, ul, ol, li', () => { + const html = + '

bold italic
x

' + + '

H2

H3

' + + '
  • a
  1. b
'; + const result = safeHtml(html); + expect(result).toContain('bold'); + expect(result).toContain('italic'); + expect(result).toContain('
'); + expect(result).toContain('

H2

'); + expect(result).toContain('

H3

'); + expect(result).toContain('
    '); + expect(result).toContain('
      '); + expect(result).toContain('
    1. a
    2. '); + }); + + it('strips '); + expect(result).not.toContain(' + +
      +
      +

      {m.geschichten_index_title()}

      + {#if data.canBlogWrite} +
      + {m.geschichten_new_button()} + + {/if} +
      + + +
      + + + {#each data.personFilters as p (p.id)} + + {/each} + + +
      + + {#if showPersonPicker} +
      + + {#if selectedPersonIds.length > 1} +

      + {m.geschichten_filter_and_hint()} +

      + {/if} +
      + {/if} + + + {#if data.geschichten.length === 0} +
      + {#if data.personFilters.length > 0} + {m.geschichten_empty_for_persons({ + names: data.personFilters.map((p) => p.displayName).join(' & ') + })} + {:else} + {m.geschichten_empty_no_filter()} + {/if} +
      + {:else} + + {/if} +
      diff --git a/frontend/src/routes/geschichten/[id]/+page.server.ts b/frontend/src/routes/geschichten/[id]/+page.server.ts new file mode 100644 index 00000000..bb4b3314 --- /dev/null +++ b/frontend/src/routes/geschichten/[id]/+page.server.ts @@ -0,0 +1,16 @@ +import { error } from '@sveltejs/kit'; +import { createApiClient } from '$lib/api.server'; +import { getErrorMessage } from '$lib/errors'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ params, fetch }) => { + const api = createApiClient(fetch); + const result = await api.GET('/api/geschichten/{id}', { + params: { path: { id: params.id } } + }); + if (!result.response.ok) { + const code = (result.error as unknown as { code?: string })?.code; + throw error(result.response.status, getErrorMessage(code)); + } + return { geschichte: result.data! }; +}; diff --git a/frontend/src/routes/geschichten/[id]/+page.svelte b/frontend/src/routes/geschichten/[id]/+page.svelte new file mode 100644 index 00000000..f7ba5541 --- /dev/null +++ b/frontend/src/routes/geschichten/[id]/+page.svelte @@ -0,0 +1,142 @@ + + +
      +
      + +
      + +
      +
      +

      + {g.title} +

      +

      + {authorName()} + {#if publishedAt}· {m.geschichten_published_on({ date: publishedAt })}{/if} +

      +
      + + +
      + + {@html sanitized} +
      +
      + + + {#if g.persons && g.persons.length > 0} +
      +

      + {m.geschichten_persons_section()} +

      + +
      + {/if} + + + {#if g.documents && g.documents.length > 0} +
      +

      + {m.geschichten_documents_section()} +

      + +
      + {/if} + + + {#if data.canBlogWrite} +
      + + {m.btn_edit()} + + +
      + {/if} +
      diff --git a/frontend/src/routes/geschichten/[id]/edit/+page.server.ts b/frontend/src/routes/geschichten/[id]/edit/+page.server.ts new file mode 100644 index 00000000..7d397921 --- /dev/null +++ b/frontend/src/routes/geschichten/[id]/edit/+page.server.ts @@ -0,0 +1,20 @@ +import { error, redirect } from '@sveltejs/kit'; +import { createApiClient } from '$lib/api.server'; +import { getErrorMessage } from '$lib/errors'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ params, fetch, parent }) => { + const layout = await parent(); + if (!layout.canBlogWrite) { + throw redirect(303, `/geschichten/${params.id}`); + } + const api = createApiClient(fetch); + const result = await api.GET('/api/geschichten/{id}', { + params: { path: { id: params.id } } + }); + if (!result.response.ok) { + const code = (result.error as unknown as { code?: string })?.code; + throw error(result.response.status, getErrorMessage(code)); + } + return { geschichte: result.data! }; +}; diff --git a/frontend/src/routes/geschichten/[id]/edit/+page.svelte b/frontend/src/routes/geschichten/[id]/edit/+page.svelte new file mode 100644 index 00000000..80bf0bf7 --- /dev/null +++ b/frontend/src/routes/geschichten/[id]/edit/+page.svelte @@ -0,0 +1,60 @@ + + +
      +
      + +
      + +

      + {m.btn_edit()}: {data.geschichte.title} +

      + + {#if errorMessage} + + {/if} + + +
      diff --git a/frontend/src/routes/geschichten/new/+page.server.ts b/frontend/src/routes/geschichten/new/+page.server.ts new file mode 100644 index 00000000..66f748e8 --- /dev/null +++ b/frontend/src/routes/geschichten/new/+page.server.ts @@ -0,0 +1,33 @@ +import { redirect } from '@sveltejs/kit'; +import { createApiClient } from '$lib/api.server'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ url, fetch, parent }) => { + const layout = await parent(); + if (!layout.canBlogWrite) { + throw redirect(303, '/geschichten'); + } + + const api = createApiClient(fetch); + const personId = url.searchParams.get('personId'); + const documentId = url.searchParams.get('documentId'); + + const [personResult, documentResult] = await Promise.all([ + personId + ? api.GET('/api/persons/{id}', { params: { path: { id: personId } } }) + : Promise.resolve(null), + documentId + ? api.GET('/api/documents/{id}', { params: { path: { id: documentId } } }) + : Promise.resolve(null) + ]); + + // Silently ignore 404/403 to avoid leaking entity existence on unknown IDs. + const initialPersons = + personResult && personResult.response.ok && personResult.data ? [personResult.data] : []; + const initialDocuments = + documentResult && documentResult.response.ok && documentResult.data + ? [documentResult.data] + : []; + + return { initialPersons, initialDocuments }; +}; diff --git a/frontend/src/routes/geschichten/new/+page.svelte b/frontend/src/routes/geschichten/new/+page.svelte new file mode 100644 index 00000000..57f9cf49 --- /dev/null +++ b/frontend/src/routes/geschichten/new/+page.svelte @@ -0,0 +1,64 @@ + + +
      +
      + +
      + +

      {m.geschichten_new_button()}

      + + {#if errorMessage} + + {/if} + + +
      diff --git a/frontend/src/routes/geschichten/page.svelte.spec.ts b/frontend/src/routes/geschichten/page.svelte.spec.ts new file mode 100644 index 00000000..f5f7621e --- /dev/null +++ b/frontend/src/routes/geschichten/page.svelte.spec.ts @@ -0,0 +1,123 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; + +vi.mock('$app/navigation', () => ({ goto: vi.fn() })); +vi.mock('$app/state', () => ({ navigating: { to: null } })); + +import Page from './+page.svelte'; +import type { PageData } from './$types'; + +afterEach(() => { + cleanup(); + vi.clearAllMocks(); +}); + +function person(id: string, displayName: string) { + return { + id, + firstName: displayName.split(' ')[0] ?? displayName, + lastName: displayName.split(' ').slice(1).join(' ') || 'X', + displayName, + personType: 'PERSON' + }; +} + +function makeData(overrides: Partial = {}): PageData { + return { + geschichten: [], + personFilters: [], + documentFilter: null, + canBlogWrite: false, + ...overrides + } as unknown as PageData; +} + +describe('geschichten page — multi-person filter chips', () => { + it('renders one chip per person in personFilters', async () => { + render(Page, { + data: makeData({ + personFilters: [person('a', 'Anna A'), person('b', 'Bertha B')] as PageData['personFilters'] + }) + }); + + await expect + .element(page.getByRole('button', { name: /Anna A aus Filter entfernen/ })) + .toBeVisible(); + await expect + .element(page.getByRole('button', { name: /Bertha B aus Filter entfernen/ })) + .toBeVisible(); + }); + + it('renders the "All" pill in pressed state when no filters are active', async () => { + render(Page, { data: makeData() }); + await expect + .element(page.getByRole('button', { name: 'Alle' })) + .toHaveAttribute('aria-pressed', 'true'); + }); + + it('renders the "All" pill in unpressed state when at least one filter is active', async () => { + render(Page, { + data: makeData({ + personFilters: [person('a', 'Anna A')] as PageData['personFilters'] + }) + }); + await expect + .element(page.getByRole('button', { name: 'Alle' })) + .toHaveAttribute('aria-pressed', 'false'); + }); + + it('clicking × on a chip removes only that person from the URL', async () => { + const { goto } = await import('$app/navigation'); + vi.mocked(goto).mockClear(); + + // Seed window.location so the chip-removal logic builds the new URL deterministically. + const originalHref = window.location.href; + window.history.replaceState({}, '', '/geschichten?personId=a&personId=b'); + + render(Page, { + data: makeData({ + personFilters: [person('a', 'Anna A'), person('b', 'Bertha B')] as PageData['personFilters'] + }) + }); + + await page.getByRole('button', { name: /Anna A aus Filter entfernen/ }).click(); + + expect(goto).toHaveBeenCalledOnce(); + const url = vi.mocked(goto).mock.calls[0][0] as string; + expect(url).toContain('personId=b'); + expect(url).not.toContain('personId=a'); + + window.history.replaceState({}, '', originalHref); + }); + + it('shows the "+ Person wählen" button even when filters are already active', async () => { + render(Page, { + data: makeData({ + personFilters: [person('a', 'Anna A')] as PageData['personFilters'] + }) + }); + await expect.element(page.getByRole('button', { name: /Person wählen/ })).toBeVisible(); + }); + + it('renders all filter pills with a 44px touch target (h-11)', async () => { + render(Page, { + data: makeData({ + personFilters: [person('a', 'Anna A')] as PageData['personFilters'] + }) + }); + + // All three pill variants must use h-11 (44px) per the senior-author touch-target rule + const all = page.getByRole('button', { name: 'Alle' }); + const chip = page.getByRole('button', { name: /Anna A aus Filter entfernen/ }); + const add = page.getByRole('button', { name: /Person wählen/ }); + + const allEl = (await all.element()) as HTMLElement; + const chipEl = (await chip.element()) as HTMLElement; + const addEl = (await add.element()) as HTMLElement; + + expect(allEl.className).toContain('h-11'); + expect(chipEl.className).toContain('h-11'); + expect(addEl.className).toContain('h-11'); + }); +}); diff --git a/frontend/src/routes/layout.svelte.spec.ts b/frontend/src/routes/layout.svelte.spec.ts index 7600053a..850af12c 100644 --- a/frontend/src/routes/layout.svelte.spec.ts +++ b/frontend/src/routes/layout.svelte.spec.ts @@ -25,6 +25,7 @@ const makeData = (overrides = {}) => ({ }, canWrite: true, canAnnotate: false, + canBlogWrite: false, ...overrides }); diff --git a/frontend/src/routes/page.svelte.spec.ts b/frontend/src/routes/page.svelte.spec.ts index 4fbd2b92..59d9a1c0 100644 --- a/frontend/src/routes/page.svelte.spec.ts +++ b/frontend/src/routes/page.svelte.spec.ts @@ -22,6 +22,7 @@ const baseData = { } as User, canWrite: true, canAnnotate: false, + canBlogWrite: false, resumeDoc: null, pulse: null, activityFeed: [], diff --git a/frontend/src/routes/persons/[id]/+page.server.ts b/frontend/src/routes/persons/[id]/+page.server.ts index 33b3ae74..1fa9db55 100644 --- a/frontend/src/routes/persons/[id]/+page.server.ts +++ b/frontend/src/routes/persons/[id]/+page.server.ts @@ -17,14 +17,18 @@ export async function load({ params, fetch, locals }) { receivedDocsResult, aliasesResult, relsResult, - inferredResult + inferredResult, + geschichtenResult ] = await Promise.all([ api.GET('/api/persons/{id}', { params: { path: { id } } }), api.GET('/api/persons/{id}/documents', { params: { path: { id } } }), api.GET('/api/persons/{id}/received-documents', { params: { path: { id } } }), api.GET('/api/persons/{id}/aliases', { params: { path: { id } } }), api.GET('/api/persons/{id}/relationships', { params: { path: { id } } }), - api.GET('/api/persons/{id}/inferred-relationships', { params: { path: { id } } }) + api.GET('/api/persons/{id}/inferred-relationships', { params: { path: { id } } }), + api.GET('/api/geschichten', { + params: { query: { status: 'PUBLISHED', personId: id } } + }) ]); if (!personResult.response.ok) { @@ -39,6 +43,7 @@ export async function load({ params, fetch, locals }) { aliases: aliasesResult.data ?? [], relationships: relsResult.data ?? [], inferredRelationships: inferredResult.data ?? [], + geschichten: geschichtenResult.data ?? [], canWrite }; } diff --git a/frontend/src/routes/persons/[id]/+page.svelte b/frontend/src/routes/persons/[id]/+page.svelte index 58c398b4..3a627892 100644 --- a/frontend/src/routes/persons/[id]/+page.svelte +++ b/frontend/src/routes/persons/[id]/+page.svelte @@ -7,6 +7,7 @@ import NameHistoryCard from './NameHistoryCard.svelte'; import CoCorrespondentsList from './CoCorrespondentsList.svelte'; import PersonDocumentList from './PersonDocumentList.svelte'; import PersonRelationshipsCard from './PersonRelationshipsCard.svelte'; +import GeschichtenCard from '$lib/components/GeschichtenCard.svelte'; let { data } = $props(); @@ -92,6 +93,17 @@ const coCorrespondents = $derived.by(() => { emptyMessage={m.person_no_received_docs()} /> + + {#if data.geschichten && data.geschichten.length > 0} +
      + +
      + {/if} diff --git a/frontend/src/routes/persons/[id]/page.server.spec.ts b/frontend/src/routes/persons/[id]/page.server.spec.ts index fcf24eb7..c239c7df 100644 --- a/frontend/src/routes/persons/[id]/page.server.spec.ts +++ b/frontend/src/routes/persons/[id]/page.server.spec.ts @@ -29,6 +29,7 @@ describe('person detail load — happy path', () => { .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) + .mockResolvedValueOnce({ response: { ok: true }, data: [] }) } as ReturnType); const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocals }); @@ -51,6 +52,7 @@ describe('person detail load — happy path', () => { .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) + .mockResolvedValueOnce({ response: { ok: true }, data: [] }) } as ReturnType); const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocalsWriter }); @@ -71,6 +73,7 @@ describe('person detail load — happy path', () => { .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) + .mockResolvedValueOnce({ response: { ok: true }, data: [] }) } as ReturnType); const result = await load({ params: { id: 'p1' }, fetch: mockFetch, locals: mockLocals }); @@ -93,6 +96,7 @@ describe('person detail load — error paths', () => { .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) + .mockResolvedValueOnce({ response: { ok: true }, data: [] }) } as ReturnType); await expect( @@ -112,6 +116,7 @@ describe('person detail load — error paths', () => { .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) .mockResolvedValueOnce({ response: { ok: true }, data: [] }) + .mockResolvedValueOnce({ response: { ok: true }, data: [] }) } as ReturnType); await expect( diff --git a/frontend/src/routes/persons/page.svelte.spec.ts b/frontend/src/routes/persons/page.svelte.spec.ts index 6c975a4e..19697f80 100644 --- a/frontend/src/routes/persons/page.svelte.spec.ts +++ b/frontend/src/routes/persons/page.svelte.spec.ts @@ -21,6 +21,7 @@ const emptyData = { user: undefined, canWrite: true, canAnnotate: false, + canBlogWrite: false, q: '', persons: [], stats: defaultStats diff --git a/frontend/yarn.lock b/frontend/yarn.lock deleted file mode 100644 index 91d23d4b..00000000 --- a/frontend/yarn.lock +++ /dev/null @@ -1,2534 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@axe-core/playwright@^4.11.1": - version "4.11.1" - resolved "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.11.1.tgz" - integrity sha512-mKEfoUIB1MkVTht0BGZFXtSAEKXMJoDkyV5YZ9jbBmZCcWDz71tegNsdTkIN8zc/yMi5Gm2kx7Z5YQ9PfWNAWw== - dependencies: - axe-core "~4.11.1" - -"@babel/code-frame@^7.26.2": - version "7.29.0" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz" - integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== - dependencies: - "@babel/helper-validator-identifier" "^7.28.5" - js-tokens "^4.0.0" - picocolors "^1.1.1" - -"@babel/helper-string-parser@^7.27.1": - version "7.27.1" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz" - integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== - -"@babel/helper-validator-identifier@^7.28.5": - version "7.28.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz" - integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== - -"@babel/parser@^7.29.0": - version "7.29.2" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz" - integrity sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA== - dependencies: - "@babel/types" "^7.29.0" - -"@babel/types@^7.29.0": - version "7.29.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz" - integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== - dependencies: - "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.28.5" - -"@bcoe/v8-coverage@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz" - integrity sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA== - -"@blazediff/core@1.9.1": - version "1.9.1" - resolved "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz" - integrity sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA== - -"@esbuild/linux-x64@0.27.4": - version "0.27.4" - resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz" - integrity sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA== - -"@eslint-community/eslint-utils@^4.6.1", "@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": - version "4.9.1" - resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz" - integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== - dependencies: - eslint-visitor-keys "^3.4.3" - -"@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.12.2": - version "4.12.2" - resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz" - integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== - -"@eslint/compat@^1.4.0": - version "1.4.1" - resolved "https://registry.npmjs.org/@eslint/compat/-/compat-1.4.1.tgz" - integrity sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w== - dependencies: - "@eslint/core" "^0.17.0" - -"@eslint/config-array@^0.21.2": - version "0.21.2" - resolved "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz" - integrity sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw== - dependencies: - "@eslint/object-schema" "^2.1.7" - debug "^4.3.1" - minimatch "^3.1.5" - -"@eslint/config-helpers@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz" - integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== - dependencies: - "@eslint/core" "^0.17.0" - -"@eslint/core@^0.17.0": - version "0.17.0" - resolved "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz" - integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== - dependencies: - "@types/json-schema" "^7.0.15" - -"@eslint/eslintrc@^3.3.5": - version "3.3.5" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz" - integrity sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg== - dependencies: - ajv "^6.14.0" - 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.5" - strip-json-comments "^3.1.1" - -"@eslint/js@^9.39.1", "@eslint/js@9.39.4": - version "9.39.4" - resolved "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz" - integrity sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw== - -"@eslint/object-schema@^2.1.7": - version "2.1.7" - resolved "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz" - integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== - -"@eslint/plugin-kit@^0.4.1": - version "0.4.1" - resolved "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz" - integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== - dependencies: - "@eslint/core" "^0.17.0" - levn "^0.4.1" - -"@humanfs/core@^0.19.1": - version "0.19.1" - resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" - integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== - -"@humanfs/node@^0.16.6": - version "0.16.7" - resolved "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz" - integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== - dependencies: - "@humanfs/core" "^0.19.1" - "@humanwhocodes/retry" "^0.4.0" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": - version "0.4.3" - resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz" - integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== - -"@inlang/paraglide-js@^2.5.0": - version "2.15.0" - resolved "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.15.0.tgz" - integrity sha512-2ZOa9nssVn4tjkKskqb88KP5A7cTIjo8AiM9xnPvH+vBhRIRenO+ftAbVOHhHcHjcFxy2QFcOfBAH/Cw1LIsUg== - dependencies: - "@inlang/recommend-sherlock" "^0.2.1" - "@inlang/sdk" "^2.8.0" - commander "11.1.0" - consola "3.4.0" - json5 "2.2.3" - unplugin "^2.1.2" - urlpattern-polyfill "^10.0.0" - -"@inlang/recommend-sherlock@^0.2.1": - version "0.2.1" - resolved "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz" - integrity sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg== - dependencies: - comment-json "^4.2.3" - -"@inlang/sdk@^2.8.0": - version "2.8.0" - resolved "https://registry.npmjs.org/@inlang/sdk/-/sdk-2.8.0.tgz" - integrity sha512-w1jysvUDTMgCaONklIgOJAp9dUDl0UhLbsdqfWEwY/GIqoc9IwpuHsrP3pzC+h3DfOpkMMDnDkTpPv8kIZ98iA== - dependencies: - "@lix-js/sdk" "0.4.7" - "@sinclair/typebox" "^0.31.17" - kysely "^0.27.4" - sqlite-wasm-kysely "0.3.0" - uuid "^13.0.0" - -"@jridgewell/gen-mapping@^0.3.5": - version "0.3.13" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz" - integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== - dependencies: - "@jridgewell/sourcemap-codec" "^1.5.0" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/remapping@^2.3.4", "@jridgewell/remapping@^2.3.5": - version "2.3.5" - resolved "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz" - integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.24" - -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - -"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": - version "1.5.5" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" - integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== - -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.31": - version "0.3.31" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz" - integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - -"@lix-js/sdk@0.4.7": - version "0.4.7" - resolved "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.4.7.tgz" - integrity sha512-pRbW+joG12L0ULfMiWYosIW0plmW4AsUdiPCp+Z8rAsElJ+wJ6in58zhD3UwUcd4BNcpldEGjg6PdA7e0RgsDQ== - dependencies: - "@lix-js/server-protocol-schema" "0.1.1" - dedent "1.5.1" - human-id "^4.1.1" - js-sha256 "^0.11.0" - kysely "^0.27.4" - sqlite-wasm-kysely "0.3.0" - uuid "^10.0.0" - -"@lix-js/server-protocol-schema@0.1.1": - version "0.1.1" - resolved "https://registry.npmjs.org/@lix-js/server-protocol-schema/-/server-protocol-schema-0.1.1.tgz" - integrity sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ== - -"@napi-rs/canvas-linux-x64-gnu@0.1.97": - version "0.1.97" - resolved "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.97.tgz" - integrity sha512-iDUBe7AilfuBSRbSa8/IGX38Mf+iCSBqoVKLSQ5XaY2JLOaqz1TVyPFEyIck7wT6mRQhQt5sN6ogfjIDfi74tg== - -"@napi-rs/canvas-linux-x64-musl@0.1.97": - version "0.1.97" - resolved "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.97.tgz" - integrity sha512-AKLFd/v0Z5fvgqBDqhvqtAdx+fHMJ5t9JcUNKq4FIZ5WH+iegGm8HPdj00NFlCSnm83Fp3Ln8I2f7uq1aIiWaA== - -"@napi-rs/canvas@^0.1.95": - version "0.1.97" - resolved "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.97.tgz" - integrity sha512-8cFniXvrIEnVwuNSRCW9wirRZbHvrD3JVujdS2P5n5xiJZNZMOZcfOvJ1pb66c7jXMKHHglJEDVJGbm8XWFcXQ== - optionalDependencies: - "@napi-rs/canvas-android-arm64" "0.1.97" - "@napi-rs/canvas-darwin-arm64" "0.1.97" - "@napi-rs/canvas-darwin-x64" "0.1.97" - "@napi-rs/canvas-linux-arm-gnueabihf" "0.1.97" - "@napi-rs/canvas-linux-arm64-gnu" "0.1.97" - "@napi-rs/canvas-linux-arm64-musl" "0.1.97" - "@napi-rs/canvas-linux-riscv64-gnu" "0.1.97" - "@napi-rs/canvas-linux-x64-gnu" "0.1.97" - "@napi-rs/canvas-linux-x64-musl" "0.1.97" - "@napi-rs/canvas-win32-arm64-msvc" "0.1.97" - "@napi-rs/canvas-win32-x64-msvc" "0.1.97" - -"@playwright/test@^1.58.2": - version "1.58.2" - resolved "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz" - integrity sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA== - dependencies: - playwright "1.58.2" - -"@polka/url@^1.0.0-next.24": - version "1.0.0-next.29" - resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz" - integrity sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww== - -"@redocly/ajv@8.11.2": - version "8.11.2" - resolved "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz" - integrity sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js-replace "^1.0.1" - -"@redocly/config@0.22.0": - version "0.22.0" - resolved "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz" - integrity sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ== - -"@redocly/openapi-core@^1.34.6": - version "1.34.10" - resolved "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.10.tgz" - integrity sha512-XCBR/9WHJ0cpezuunHMZjuFMl4KqUo7eiFwzrQrvm7lTXt0EBd3No8UY+9OyzXpDfreGEMMtxmaLZ+ksVw378g== - dependencies: - "@redocly/ajv" "8.11.2" - "@redocly/config" "0.22.0" - colorette "1.4.0" - https-proxy-agent "7.0.6" - js-levenshtein "1.1.6" - js-yaml "4.1.1" - minimatch "5.1.9" - pluralize "8.0.0" - yaml-ast-parser "0.0.43" - -"@rollup/plugin-commonjs@^29.0.0": - version "29.0.2" - resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz" - integrity sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - commondir "^1.0.1" - estree-walker "^2.0.2" - fdir "^6.2.0" - is-reference "1.2.1" - magic-string "^0.30.3" - picomatch "^4.0.2" - -"@rollup/plugin-json@^6.1.0": - version "6.1.0" - resolved "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz" - integrity sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA== - dependencies: - "@rollup/pluginutils" "^5.1.0" - -"@rollup/plugin-node-resolve@^16.0.0": - version "16.0.3" - resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz" - integrity sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg== - dependencies: - "@rollup/pluginutils" "^5.0.1" - "@types/resolve" "1.20.2" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.22.1" - -"@rollup/pluginutils@^5.0.1", "@rollup/pluginutils@^5.1.0": - version "5.3.0" - resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz" - integrity sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^4.0.2" - -"@rollup/rollup-linux-x64-gnu@4.59.0": - version "4.59.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz" - integrity sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg== - -"@rollup/rollup-linux-x64-musl@4.59.0": - version "4.59.0" - resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz" - integrity sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg== - -"@sinclair/typebox@^0.31.17": - version "0.31.28" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.28.tgz" - integrity sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ== - -"@sqlite.org/sqlite-wasm@^3.48.0-build2": - version "3.48.0-build4" - resolved "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.48.0-build4.tgz" - integrity sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ== - -"@standard-schema/spec@^1.0.0", "@standard-schema/spec@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz" - integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== - -"@sveltejs/acorn-typescript@^1.0.5": - version "1.0.9" - resolved "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz" - integrity sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA== - -"@sveltejs/adapter-node@^5.4.0": - version "5.5.4" - resolved "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.4.tgz" - integrity sha512-45X92CXW+2J8ZUzPv3eLlKWEzINKiiGeFWTjyER4ZN4sGgNoaoeSkCY/QYNxHpPXy71QPsctwccBo9jJs0ySPQ== - dependencies: - "@rollup/plugin-commonjs" "^29.0.0" - "@rollup/plugin-json" "^6.1.0" - "@rollup/plugin-node-resolve" "^16.0.0" - rollup "^4.59.0" - -"@sveltejs/kit@^2.4.0", "@sveltejs/kit@^2.48.5": - version "2.55.0" - resolved "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz" - integrity sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA== - dependencies: - "@standard-schema/spec" "^1.0.0" - "@sveltejs/acorn-typescript" "^1.0.5" - "@types/cookie" "^0.6.0" - acorn "^8.14.1" - cookie "^0.6.0" - devalue "^5.6.4" - esm-env "^1.2.2" - kleur "^4.1.5" - magic-string "^0.30.5" - mrmime "^2.0.0" - set-cookie-parser "^3.0.0" - sirv "^3.0.0" - -"@sveltejs/vite-plugin-svelte-inspector@^5.0.0": - version "5.0.2" - resolved "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz" - integrity sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig== - dependencies: - obug "^2.1.0" - -"@sveltejs/vite-plugin-svelte@^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "@sveltejs/vite-plugin-svelte@^6.0.0-next.0", "@sveltejs/vite-plugin-svelte@^6.2.1": - version "6.2.4" - resolved "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz" - integrity sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA== - dependencies: - "@sveltejs/vite-plugin-svelte-inspector" "^5.0.0" - deepmerge "^4.3.1" - magic-string "^0.30.21" - obug "^2.1.0" - vitefu "^1.1.1" - -"@tailwindcss/forms@^0.5.10": - version "0.5.11" - resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.11.tgz" - integrity sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA== - dependencies: - mini-svg-data-uri "^1.2.3" - -"@tailwindcss/node@4.2.1": - version "4.2.1" - resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz" - integrity sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg== - dependencies: - "@jridgewell/remapping" "^2.3.5" - enhanced-resolve "^5.19.0" - jiti "^2.6.1" - lightningcss "1.31.1" - magic-string "^0.30.21" - source-map-js "^1.2.1" - tailwindcss "4.2.1" - -"@tailwindcss/oxide-linux-x64-gnu@4.2.1": - version "4.2.1" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz" - integrity sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g== - -"@tailwindcss/oxide-linux-x64-musl@4.2.1": - version "4.2.1" - resolved "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz" - integrity sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g== - -"@tailwindcss/oxide@4.2.1": - version "4.2.1" - resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz" - integrity sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw== - optionalDependencies: - "@tailwindcss/oxide-android-arm64" "4.2.1" - "@tailwindcss/oxide-darwin-arm64" "4.2.1" - "@tailwindcss/oxide-darwin-x64" "4.2.1" - "@tailwindcss/oxide-freebsd-x64" "4.2.1" - "@tailwindcss/oxide-linux-arm-gnueabihf" "4.2.1" - "@tailwindcss/oxide-linux-arm64-gnu" "4.2.1" - "@tailwindcss/oxide-linux-arm64-musl" "4.2.1" - "@tailwindcss/oxide-linux-x64-gnu" "4.2.1" - "@tailwindcss/oxide-linux-x64-musl" "4.2.1" - "@tailwindcss/oxide-wasm32-wasi" "4.2.1" - "@tailwindcss/oxide-win32-arm64-msvc" "4.2.1" - "@tailwindcss/oxide-win32-x64-msvc" "4.2.1" - -"@tailwindcss/typography@^0.5.19": - version "0.5.19" - resolved "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz" - integrity sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg== - dependencies: - postcss-selector-parser "6.0.10" - -"@tailwindcss/vite@^4.1.17": - version "4.2.1" - resolved "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz" - integrity sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w== - dependencies: - "@tailwindcss/node" "4.2.1" - "@tailwindcss/oxide" "4.2.1" - tailwindcss "4.2.1" - -"@testing-library/svelte-core@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@testing-library/svelte-core/-/svelte-core-1.0.0.tgz" - integrity sha512-VkUePoLV6oOYwSUvX6ShA8KLnJqZiYMIbP2JW2t0GLWLkJxKGvuH5qrrZBV/X7cXFnLGuFQEC7RheYiZOW68KQ== - -"@tiptap/core@^3.22.5", "@tiptap/core@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/core/-/core-3.22.5.tgz" - integrity sha512-L1lhWz6ujGny8LduTJ7MBWYhzigwOvfUJUrJ7IzOJSuy3+OAzisdGDD1GV7LEO/hU0Hr2Mkm1wajRIHExvS9HQ== - -"@tiptap/extension-blockquote@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-3.22.5.tgz" - integrity sha512-ajyP5W8fG5Hrru47T/eF3xMKOpNvWofgNJqBTeNuGl02sYxsy9a4EunyFxudsaZP9WW3VOD4SaIWr5+MqpbnOQ== - -"@tiptap/extension-bold@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-3.22.5.tgz" - integrity sha512-l/uDtpJISiFFyfctvnODNWBN/XPZI1jVZRacTRDDnSn8+x6KQ7G2qgFYueU7KvVJGDFVT39Iio56mcFRG/Pozg== - -"@tiptap/extension-bullet-list@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-3.22.5.tgz" - integrity sha512-cf54fG9AybU8NgPMv1TOcoqAkELeRc/VpnSCt/rIJZphWQx9nsFmrtkrlCatrIcCaGtNZYwlHlMnC5LVVMu0uA== - -"@tiptap/extension-code-block@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-3.22.5.tgz" - integrity sha512-d123kCfLdJTi4fue1m0+TNFztDkmIRSZGZmGu6H9KqwG5Q7IzjT9o8lzRsz+pXxYqHvqgYmXoEpM6srbzXx/Ag== - -"@tiptap/extension-code@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-3.22.5.tgz" - integrity sha512-mwDNOJC9rYbDu/JcqrN4dbUQRklJU8Fuk2raxD/IvFw9qUIcPCmxQ2XT9UTKmZz/Ju7Kdy72fss6XpgWv6gLAQ== - -"@tiptap/extension-document@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-3.22.5.tgz" - integrity sha512-8NJERd+pCtvSuEP4C4WMGYmRRCV12ePZL7bC+QUdFlbdXg+kNZS0zZ7hh879tYA0Kidbi8rWWD1Tx+H2ezkmMw== - -"@tiptap/extension-dropcursor@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-3.22.5.tgz" - integrity sha512-Mp40DaFrY3sEUVtFqmxrR0BmU4G3k8GCYYNGqNa9OqWv7BrcFDC03V2n3okESDKt4MKkzhQQmypq+ouLy8dLfA== - -"@tiptap/extension-gapcursor@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-3.22.5.tgz" - integrity sha512-4WkMu7qqjbsm8hCQS+8X+la1wjriN0SKoRdvpfKH33qM50MB34tYJuGLAO+y7TTh4MMMco3AZCKPBL5JVMqNIg== - -"@tiptap/extension-hard-break@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-3.22.5.tgz" - integrity sha512-n0R2mUVYZU2AVbJhg/WcY9+zx690wVwvsItHJf0DrYbf1tCYHx+PRHUt/AoXk6u8BSmnkb8/FDziS8m3mjfpSg== - -"@tiptap/extension-heading@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-3.22.5.tgz" - integrity sha512-hjyEG4947PAhMBfP1G6B0QAh6+y9mp2C5BQmNjprA05/lQzDAT7KFZzNh8ZVp3ol6aICKq/N1gFOW9Dc/9FUOw== - -"@tiptap/extension-horizontal-rule@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.22.5.tgz" - integrity sha512-vUV0/ugIbXOc8SJib0h8UMhgcqZXWu/dkEhlswZN4VVven1o5enkfxEiDw+OyIJHi5rUkrdhsQ/KTxG/Xb7X8A== - -"@tiptap/extension-italic@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-3.22.5.tgz" - integrity sha512-4T8baSiLkeIymTgEwirxDFt5YgYofkP3m1+MGYdGy2HKcOK+1vpvlPhEO1X5qtZngtJW5S4+njKjinRg52A4PA== - -"@tiptap/extension-link@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-3.22.5.tgz" - integrity sha512-d671MvF3GPKoS2OVxjIlQ7hIE7MS3hREdR+d4cvnnoiLLD+ZJ6KgDnxmWqF0a1s4qxLWK2KxKRSOIfYGE31QWQ== - dependencies: - linkifyjs "^4.3.2" - -"@tiptap/extension-list-item@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-3.22.5.tgz" - integrity sha512-W7uTmyKLhlsvuTPLv+8WwnsY+mlikBFIoLSvVcBaFt4MwpsZ+DeB6KQg02Y7tbtaAnG7rXu9Fvw2QORh2P728A== - -"@tiptap/extension-list-keymap@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-list-keymap/-/extension-list-keymap-3.22.5.tgz" - integrity sha512-cGUnxJ0y515e1bVHNjUmbx7oWHoEon59w6BA5N2KwV9iW2mZZchlTX4yxJSOX+ixeVRChsa7YwC3Z1jUZ6AMEg== - -"@tiptap/extension-list@^3.22.5", "@tiptap/extension-list@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.5.tgz" - integrity sha512-cVO3ZHCgxAWZ4zrFSs81FO2nyCk1wb2EHkpLpW98FzbJLkN9rDkazhW99P3HRWy/CvUldOT+8ecI1YrQtBojMg== - -"@tiptap/extension-mention@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-3.22.5.tgz" - integrity sha512-rGTbTjyxLc5C/6QjfbQF53nMbxjVgJU1VK6Si1i1J2c5DU09COgEFlYvi4YHjb3xz39SprPfG+GTtgD96eg7Ww== - -"@tiptap/extension-ordered-list@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-3.22.5.tgz" - integrity sha512-OXdh4k4CNrukwiSdWdEQ49uvgnqvR0Z9aNSP4HI5/kZQ/Te1NtRtYCpUrzWyO/7CtjcCisXHti0o9C/TV8YMbQ== - -"@tiptap/extension-paragraph@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-3.22.5.tgz" - integrity sha512-52KCto4+XKpnBWpIufspWLyq4UWxAWC72ANPdGuIhbi72NRTabiTbTVN40uwGSPkyakeESG0/vKdWJCVvB4f0g== - -"@tiptap/extension-strike@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-3.22.5.tgz" - integrity sha512-42WrrFK5gOom/0znH85x12Mw5IQ/6O6DWdyUWoRIrNA/qJpuHtU8oVU+bIgU2tuomMGHruRjIzgBQv5sBjEtww== - -"@tiptap/extension-text@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-3.22.5.tgz" - integrity sha512-bzpDOdAEo1JeoVZDIyV0oY0jGXkEG+AzF70SzHoRSjOvFDtKWunyXf9eO1OnOr2/fmMcckT2qwUBNBMQplWBzw== - -"@tiptap/extension-underline@^3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-3.22.5.tgz" - integrity sha512-9ut09rJD0iEbS6sk7yd2j6IwuFDLTNmDEGTDLodvqAfi+bq7ddsTDv0YviXoZaA9sdHAdTEVr2ITy2m6WK5jpA== - -"@tiptap/extensions@^3.22.5", "@tiptap/extensions@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.5.tgz" - integrity sha512-Ifg4MzKCj3uRqe3ieTwYnomu2y4p7EXr2avVSKZYfh12i2dyWe2Gkn1KuZDREANVE+gHqFlQjJRYzhJFwzSCrg== - -"@tiptap/pm@^3.22.5", "@tiptap/pm@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.5.tgz" - integrity sha512-Cr9Mv4igxvI2tKMiahw48sZxva3PfDzypErH8IB82N+9qa9n9ygVMt0BOaDg53hLKxEEVeYr2S/wCcJIVFgBTw== - dependencies: - prosemirror-changeset "^2.3.0" - prosemirror-commands "^1.6.2" - prosemirror-dropcursor "^1.8.1" - prosemirror-gapcursor "^1.3.2" - prosemirror-history "^1.4.1" - prosemirror-keymap "^1.2.2" - prosemirror-model "^1.24.1" - prosemirror-schema-list "^1.5.0" - prosemirror-state "^1.4.3" - prosemirror-tables "^1.6.4" - prosemirror-transform "^1.10.2" - prosemirror-view "^1.38.1" - -"@tiptap/starter-kit@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-3.22.5.tgz" - integrity sha512-LZ/LYbwH6rnDi5DnRyagkuNsYAVyhM+yJvvz+ZuYA0JkPiTXJV86J5PWSKew8M0gVfMHcNVtKjfQCvViFCeIgw== - dependencies: - "@tiptap/core" "^3.22.5" - "@tiptap/extension-blockquote" "^3.22.5" - "@tiptap/extension-bold" "^3.22.5" - "@tiptap/extension-bullet-list" "^3.22.5" - "@tiptap/extension-code" "^3.22.5" - "@tiptap/extension-code-block" "^3.22.5" - "@tiptap/extension-document" "^3.22.5" - "@tiptap/extension-dropcursor" "^3.22.5" - "@tiptap/extension-gapcursor" "^3.22.5" - "@tiptap/extension-hard-break" "^3.22.5" - "@tiptap/extension-heading" "^3.22.5" - "@tiptap/extension-horizontal-rule" "^3.22.5" - "@tiptap/extension-italic" "^3.22.5" - "@tiptap/extension-link" "^3.22.5" - "@tiptap/extension-list" "^3.22.5" - "@tiptap/extension-list-item" "^3.22.5" - "@tiptap/extension-list-keymap" "^3.22.5" - "@tiptap/extension-ordered-list" "^3.22.5" - "@tiptap/extension-paragraph" "^3.22.5" - "@tiptap/extension-strike" "^3.22.5" - "@tiptap/extension-text" "^3.22.5" - "@tiptap/extension-underline" "^3.22.5" - "@tiptap/extensions" "^3.22.5" - "@tiptap/pm" "^3.22.5" - -"@tiptap/suggestion@3.22.5": - version "3.22.5" - resolved "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.22.5.tgz" - integrity sha512-Uv79Ht/o4mx1GWIT65jeQTE67LMrA+K7d8p51XOe9PJw0H0fS3iCdeMJ8tAo3h6QrMJFejdsB7z8jJL9UbAnhA== - -"@types/chai@^5.2.2": - version "5.2.3" - resolved "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz" - integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== - dependencies: - "@types/deep-eql" "*" - assertion-error "^2.0.1" - -"@types/cookie@^0.6.0": - version "0.6.0" - resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz" - integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== - -"@types/deep-eql@*": - version "4.0.2" - resolved "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz" - integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== - -"@types/diff@^7.0.2": - version "7.0.2" - resolved "https://registry.npmjs.org/@types/diff/-/diff-7.0.2.tgz" - integrity sha512-JSWRMozjFKsGlEjiiKajUjIJVKuKdE3oVy2DNtK+fUo8q82nhFZ2CPQwicAIkXrofahDXrWJ7mjelvZphMS98Q== - -"@types/estree@*", "@types/estree@^1.0.0", "@types/estree@^1.0.5", "@types/estree@^1.0.6", "@types/estree@1.0.8": - version "1.0.8" - resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz" - integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== - -"@types/json-schema@^7.0.15": - version "7.0.15" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/node@^20.0.0 || ^22.0.0 || >=24.0.0", "@types/node@^20.19.0 || >=22.12.0", "@types/node@^24": - version "24.12.0" - resolved "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz" - integrity sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ== - dependencies: - undici-types "~7.16.0" - -"@types/resolve@1.20.2": - version "1.20.2" - resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz" - integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== - -"@types/trusted-types@^2.0.7": - version "2.0.7" - resolved "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz" - integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== - -"@typescript-eslint/eslint-plugin@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz" - integrity sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ== - dependencies: - "@eslint-community/regexpp" "^4.12.2" - "@typescript-eslint/scope-manager" "8.57.0" - "@typescript-eslint/type-utils" "8.57.0" - "@typescript-eslint/utils" "8.57.0" - "@typescript-eslint/visitor-keys" "8.57.0" - ignore "^7.0.5" - natural-compare "^1.4.0" - ts-api-utils "^2.4.0" - -"@typescript-eslint/parser@^8.57.0", "@typescript-eslint/parser@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz" - integrity sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g== - dependencies: - "@typescript-eslint/scope-manager" "8.57.0" - "@typescript-eslint/types" "8.57.0" - "@typescript-eslint/typescript-estree" "8.57.0" - "@typescript-eslint/visitor-keys" "8.57.0" - debug "^4.4.3" - -"@typescript-eslint/project-service@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz" - integrity sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w== - dependencies: - "@typescript-eslint/tsconfig-utils" "^8.57.0" - "@typescript-eslint/types" "^8.57.0" - debug "^4.4.3" - -"@typescript-eslint/scope-manager@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz" - integrity sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw== - dependencies: - "@typescript-eslint/types" "8.57.0" - "@typescript-eslint/visitor-keys" "8.57.0" - -"@typescript-eslint/tsconfig-utils@^8.57.0", "@typescript-eslint/tsconfig-utils@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz" - integrity sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA== - -"@typescript-eslint/type-utils@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz" - integrity sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ== - dependencies: - "@typescript-eslint/types" "8.57.0" - "@typescript-eslint/typescript-estree" "8.57.0" - "@typescript-eslint/utils" "8.57.0" - debug "^4.4.3" - ts-api-utils "^2.4.0" - -"@typescript-eslint/types@^8.2.0", "@typescript-eslint/types@^8.57.0", "@typescript-eslint/types@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz" - integrity sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg== - -"@typescript-eslint/typescript-estree@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz" - integrity sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q== - dependencies: - "@typescript-eslint/project-service" "8.57.0" - "@typescript-eslint/tsconfig-utils" "8.57.0" - "@typescript-eslint/types" "8.57.0" - "@typescript-eslint/visitor-keys" "8.57.0" - debug "^4.4.3" - minimatch "^10.2.2" - semver "^7.7.3" - tinyglobby "^0.2.15" - ts-api-utils "^2.4.0" - -"@typescript-eslint/utils@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz" - integrity sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ== - dependencies: - "@eslint-community/eslint-utils" "^4.9.1" - "@typescript-eslint/scope-manager" "8.57.0" - "@typescript-eslint/types" "8.57.0" - "@typescript-eslint/typescript-estree" "8.57.0" - -"@typescript-eslint/visitor-keys@8.57.0": - version "8.57.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz" - integrity sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg== - dependencies: - "@typescript-eslint/types" "8.57.0" - eslint-visitor-keys "^5.0.0" - -"@vitest/browser-playwright@^4.0.10", "@vitest/browser-playwright@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.0.tgz" - integrity sha512-2RU7pZELY9/aVMLmABNy1HeZ4FX23FXGY1jRuHLHgWa2zaAE49aNW2GLzebW+BmbTZIKKyFF1QXvk7DEWViUCQ== - dependencies: - "@vitest/browser" "4.1.0" - "@vitest/mocker" "4.1.0" - tinyrainbow "^3.0.3" - -"@vitest/browser@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.0.tgz" - integrity sha512-tG/iOrgbiHQks0ew7CdelUyNEHkv8NLrt+CqdTivIuoSnXvO7scWMn4Kqo78/UGY1NJ6Hv+vp8BvRnED/bjFdQ== - dependencies: - "@blazediff/core" "1.9.1" - "@vitest/mocker" "4.1.0" - "@vitest/utils" "4.1.0" - magic-string "^0.30.21" - pngjs "^7.0.0" - sirv "^3.0.2" - tinyrainbow "^3.0.3" - ws "^8.19.0" - -"@vitest/coverage-v8@^4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.0.tgz" - integrity sha512-nDWulKeik2bL2Va/Wl4x7DLuTKAXa906iRFooIRPR+huHkcvp9QDkPQ2RJdmjOFrqOqvNfoSQLF68deE3xC3CQ== - dependencies: - "@bcoe/v8-coverage" "^1.0.2" - "@vitest/utils" "4.1.0" - ast-v8-to-istanbul "^1.0.0" - istanbul-lib-coverage "^3.2.2" - istanbul-lib-report "^3.0.1" - istanbul-reports "^3.2.0" - magicast "^0.5.2" - obug "^2.1.1" - std-env "^4.0.0-rc.1" - tinyrainbow "^3.0.3" - -"@vitest/expect@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.0.tgz" - integrity sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA== - dependencies: - "@standard-schema/spec" "^1.1.0" - "@types/chai" "^5.2.2" - "@vitest/spy" "4.1.0" - "@vitest/utils" "4.1.0" - chai "^6.2.2" - tinyrainbow "^3.0.3" - -"@vitest/mocker@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.0.tgz" - integrity sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw== - dependencies: - "@vitest/spy" "4.1.0" - estree-walker "^3.0.3" - magic-string "^0.30.21" - -"@vitest/pretty-format@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.0.tgz" - integrity sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A== - dependencies: - tinyrainbow "^3.0.3" - -"@vitest/runner@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.0.tgz" - integrity sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ== - dependencies: - "@vitest/utils" "4.1.0" - pathe "^2.0.3" - -"@vitest/snapshot@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.0.tgz" - integrity sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg== - dependencies: - "@vitest/pretty-format" "4.1.0" - "@vitest/utils" "4.1.0" - magic-string "^0.30.21" - pathe "^2.0.3" - -"@vitest/spy@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.0.tgz" - integrity sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw== - -"@vitest/utils@4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.0.tgz" - integrity sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw== - dependencies: - "@vitest/pretty-format" "4.1.0" - convert-source-map "^2.0.0" - tinyrainbow "^3.0.3" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.12.1, acorn@^8.14.1, acorn@^8.15.0, acorn@^8.9.0: - version "8.16.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz" - integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== - -agent-base@^7.1.2: - version "7.1.4" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz" - integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== - -ajv@^6.14.0: - version "6.14.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz" - integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== - 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" - -ansi-colors@^4.1.3: - version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -aria-query@5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz" - integrity sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g== - -array-timsort@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz" - integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== - -assertion-error@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz" - integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== - -ast-v8-to-istanbul@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz" - integrity sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.31" - estree-walker "^3.0.3" - js-tokens "^10.0.0" - -axe-core@~4.11.1: - version "4.11.1" - resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.11.1.tgz" - integrity sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A== - -axobject-query@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz" - integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -balanced-match@^4.0.2: - version "4.0.4" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz" - integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== - -brace-expansion@^1.1.7: - version "1.1.12" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" - integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz" - integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== - dependencies: - balanced-match "^1.0.0" - -brace-expansion@^5.0.2: - version "5.0.4" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz" - integrity sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg== - dependencies: - balanced-match "^4.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -chai@^6.2.2: - version "6.2.2" - resolved "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz" - integrity sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg== - -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -change-case@^5.4.4: - version "5.4.4" - resolved "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz" - integrity sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w== - -chokidar@^4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz" - integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== - dependencies: - readdirp "^4.0.1" - -clsx@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" - integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colorette@1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" - integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== - -commander@11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz" - integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== - -comment-json@^4.2.3: - version "4.6.2" - resolved "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz" - integrity sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w== - dependencies: - array-timsort "^1.0.3" - esprima "^4.0.1" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" - integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -consola@3.4.0: - version "3.4.0" - resolved "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz" - integrity sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA== - -convert-source-map@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" - integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== - -cookie@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== - -cross-spawn@^7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" - integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -debug@^4.3.1, debug@^4.3.2, debug@^4.4.3, debug@4: - version "4.4.3" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz" - integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== - dependencies: - ms "^2.1.3" - -dedent@1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -deepmerge@^4.2.2, deepmerge@^4.3.1: - version "4.3.1" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" - integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== - -detect-libc@^2.0.3: - version "2.1.2" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz" - integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== - -devalue@^5.6.4: - version "5.6.4" - resolved "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz" - integrity sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA== - -diff@^8.0.3: - version "8.0.3" - resolved "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz" - integrity sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ== - -enhanced-resolve@^5.19.0: - version "5.20.0" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz" - integrity sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.3.0" - -es-module-lexer@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz" - integrity sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw== - -esbuild@^0.27.0: - version "0.27.4" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz" - integrity sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ== - optionalDependencies: - "@esbuild/aix-ppc64" "0.27.4" - "@esbuild/android-arm" "0.27.4" - "@esbuild/android-arm64" "0.27.4" - "@esbuild/android-x64" "0.27.4" - "@esbuild/darwin-arm64" "0.27.4" - "@esbuild/darwin-x64" "0.27.4" - "@esbuild/freebsd-arm64" "0.27.4" - "@esbuild/freebsd-x64" "0.27.4" - "@esbuild/linux-arm" "0.27.4" - "@esbuild/linux-arm64" "0.27.4" - "@esbuild/linux-ia32" "0.27.4" - "@esbuild/linux-loong64" "0.27.4" - "@esbuild/linux-mips64el" "0.27.4" - "@esbuild/linux-ppc64" "0.27.4" - "@esbuild/linux-riscv64" "0.27.4" - "@esbuild/linux-s390x" "0.27.4" - "@esbuild/linux-x64" "0.27.4" - "@esbuild/netbsd-arm64" "0.27.4" - "@esbuild/netbsd-x64" "0.27.4" - "@esbuild/openbsd-arm64" "0.27.4" - "@esbuild/openbsd-x64" "0.27.4" - "@esbuild/openharmony-arm64" "0.27.4" - "@esbuild/sunos-x64" "0.27.4" - "@esbuild/win32-arm64" "0.27.4" - "@esbuild/win32-ia32" "0.27.4" - "@esbuild/win32-x64" "0.27.4" - -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-config-prettier@^10.1.8: - version "10.1.8" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz" - integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== - -eslint-plugin-svelte@^3.13.0: - version "3.15.2" - resolved "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.15.2.tgz" - integrity sha512-k4Nsjs3bHujeEnnckoTM4mFYR1e8Mb9l2rTwNdmYiamA+Tjzn8X+2F+fuSP2w4VbXYhn2bmySyACQYdmUDW2Cg== - dependencies: - "@eslint-community/eslint-utils" "^4.6.1" - "@jridgewell/sourcemap-codec" "^1.5.0" - esutils "^2.0.3" - globals "^16.0.0" - known-css-properties "^0.37.0" - postcss "^8.4.49" - postcss-load-config "^3.1.4" - postcss-safe-parser "^7.0.0" - semver "^7.6.3" - svelte-eslint-parser "^1.4.0" - -eslint-scope@^8.2.0, eslint-scope@^8.4.0: - version "8.4.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz" - integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint-visitor-keys@^4.0.0, eslint-visitor-keys@^4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" - integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== - -eslint-visitor-keys@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz" - integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA== - -"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.40 || 9", "eslint@^8.57.0 || ^9.0.0 || ^10.0.0", "eslint@^8.57.1 || ^9.0.0 || ^10.0.0", eslint@^9.39.1, eslint@>=7.0.0: - version "9.39.4" - resolved "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz" - integrity sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ== - dependencies: - "@eslint-community/eslint-utils" "^4.8.0" - "@eslint-community/regexpp" "^4.12.1" - "@eslint/config-array" "^0.21.2" - "@eslint/config-helpers" "^0.4.2" - "@eslint/core" "^0.17.0" - "@eslint/eslintrc" "^3.3.5" - "@eslint/js" "9.39.4" - "@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.14.0" - 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.5" - natural-compare "^1.4.0" - optionator "^0.9.3" - -esm-env@^1.2.1, esm-env@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz" - integrity sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA== - -espree@^10.0.0, espree@^10.0.1, espree@^10.4.0: - version "10.4.0" - resolved "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz" - integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== - dependencies: - acorn "^8.15.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^4.2.1" - -esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.5.0: - version "1.7.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz" - integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== - dependencies: - estraverse "^5.1.0" - -esrap@^2.2.2: - version "2.2.4" - resolved "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz" - integrity sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - "@typescript-eslint/types" "^8.2.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -estree-walker@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - -estree-walker@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz" - integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== - dependencies: - "@types/estree" "^1.0.0" - -esutils@^2.0.2, esutils@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -expect-type@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz" - integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fdir@^6.2.0, fdir@^6.5.0: - version "6.5.0" - resolved "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz" - integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== - -file-entry-cache@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz" - integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== - dependencies: - flat-cache "^4.0.0" - -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz" - integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.4" - -flatted@^3.2.9: - version "3.4.1" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz" - integrity sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -globals@^14.0.0: - version "14.0.0" - resolved "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz" - integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== - -globals@^16.0.0, globals@^16.5.0: - version "16.5.0" - resolved "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz" - integrity sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ== - -graceful-fs@^4.2.4: - version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - -html-escaper@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - -https-proxy-agent@7.0.6: - version "7.0.6" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz" - integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== - dependencies: - agent-base "^7.1.2" - debug "4" - -human-id@^4.1.1: - version "4.1.3" - resolved "https://registry.npmjs.org/human-id/-/human-id-4.1.3.tgz" - integrity sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q== - -ignore@^5.2.0: - version "5.3.2" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -ignore@^7.0.5: - version "7.0.5" - resolved "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz" - integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== - -import-fresh@^3.2.1: - version "3.3.1" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz" - integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -index-to-position@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz" - integrity sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw== - -is-core-module@^2.16.1: - version "2.16.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz" - integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== - dependencies: - hasown "^2.0.2" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-glob@^4.0.0, is-glob@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" - integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== - -is-reference@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz" - integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== - dependencies: - "@types/estree" "^1.0.6" - -is-reference@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" - integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== - -istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" - integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== - dependencies: - istanbul-lib-coverage "^3.0.0" - make-dir "^4.0.0" - supports-color "^7.1.0" - -istanbul-reports@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz" - integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - -jiti@*, jiti@^2.6.1, jiti@>=1.21.0: - version "2.6.1" - resolved "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz" - integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ== - -js-levenshtein@1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz" - integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== - -js-sha256@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.11.1.tgz" - integrity sha512-o6WSo/LUvY2uC4j7mO50a2ms7E/EAdbP0swigLV+nzHKTTaYnaLIWJ02VdXrsJX0vGedDESQnLsOekr94ryfjg== - -js-tokens@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz" - integrity sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^4.1.1, js-yaml@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" - integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== - dependencies: - argparse "^2.0.1" - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json5@2.2.3: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -keyv@^4.5.4: - version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -kleur@^4.1.5: - version "4.1.5" - resolved "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz" - integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== - -known-css-properties@^0.37.0: - version "0.37.0" - resolved "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz" - integrity sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ== - -kysely@*, kysely@^0.27.4: - version "0.27.6" - resolved "https://registry.npmjs.org/kysely/-/kysely-0.27.6.tgz" - integrity sha512-FIyV/64EkKhJmjgC0g2hygpBv5RNWVPyNCqSAD7eTCv6eFWNIi4PN1UvdSJGicN/o35bnevgis4Y0UDC0qi8jQ== - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -lightningcss-linux-x64-gnu@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz" - integrity sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA== - -lightningcss-linux-x64-musl@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz" - integrity sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA== - -lightningcss@^1.21.0, lightningcss@1.31.1: - version "1.31.1" - resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz" - integrity sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ== - dependencies: - detect-libc "^2.0.3" - optionalDependencies: - lightningcss-android-arm64 "1.31.1" - lightningcss-darwin-arm64 "1.31.1" - lightningcss-darwin-x64 "1.31.1" - lightningcss-freebsd-x64 "1.31.1" - lightningcss-linux-arm-gnueabihf "1.31.1" - lightningcss-linux-arm64-gnu "1.31.1" - lightningcss-linux-arm64-musl "1.31.1" - lightningcss-linux-x64-gnu "1.31.1" - lightningcss-linux-x64-musl "1.31.1" - lightningcss-win32-arm64-msvc "1.31.1" - lightningcss-win32-x64-msvc "1.31.1" - -lilconfig@^2.0.5: - version "2.1.0" - resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" - integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== - -linkifyjs@^4.3.2: - version "4.3.2" - resolved "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.2.tgz" - integrity sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA== - -locate-character@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz" - integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -magic-string@^0.30.11, magic-string@^0.30.21, magic-string@^0.30.3, magic-string@^0.30.5: - version "0.30.21" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz" - integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== - dependencies: - "@jridgewell/sourcemap-codec" "^1.5.5" - -magicast@^0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz" - integrity sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ== - dependencies: - "@babel/parser" "^7.29.0" - "@babel/types" "^7.29.0" - source-map-js "^1.2.1" - -make-dir@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" - integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== - dependencies: - semver "^7.5.3" - -mini-svg-data-uri@^1.2.3: - version "1.4.4" - resolved "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz" - integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== - -minimatch@^10.2.2: - version "10.2.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz" - integrity sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg== - dependencies: - brace-expansion "^5.0.2" - -minimatch@^3.1.5: - version "3.1.5" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz" - integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== - dependencies: - brace-expansion "^1.1.7" - -minimatch@5.1.9: - version "5.1.9" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz" - integrity sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw== - dependencies: - brace-expansion "^2.0.1" - -mri@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - -mrmime@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz" - integrity sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ== - -ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -nanoid@^3.3.11: - version "3.3.11" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" - integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -node-readable-to-web-readable-stream@^0.4.2: - version "0.4.2" - resolved "https://registry.npmjs.org/node-readable-to-web-readable-stream/-/node-readable-to-web-readable-stream-0.4.2.tgz" - integrity sha512-/cMZNI34v//jUTrI+UIo4ieHAB5EZRY/+7OmXZgBxaWBMcW2tGdceIw06RFxWxrKZ5Jp3sI2i5TsRo+CBhtVLQ== - -obug@^2.1.0, obug@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz" - integrity sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ== - -openapi-fetch@^0.13.5: - version "0.13.8" - resolved "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.13.8.tgz" - integrity sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ== - dependencies: - openapi-typescript-helpers "^0.0.15" - -openapi-typescript-helpers@^0.0.15: - version "0.0.15" - resolved "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.15.tgz" - integrity sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw== - -openapi-typescript@^7.8.0: - version "7.13.0" - resolved "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz" - integrity sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ== - dependencies: - "@redocly/openapi-core" "^1.34.6" - ansi-colors "^4.1.3" - change-case "^5.4.4" - parse-json "^8.3.0" - supports-color "^10.2.2" - yargs-parser "^21.1.1" - -optionator@^0.9.3: - version "0.9.4" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" - integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== - 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" - -orderedmap@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz" - integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g== - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-json@^8.3.0: - version "8.3.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz" - integrity sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ== - dependencies: - "@babel/code-frame" "^7.26.2" - index-to-position "^1.1.0" - type-fest "^4.39.1" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -pathe@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz" - integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== - -pdfjs-dist@^5.5.207: - version "5.5.207" - resolved "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.5.207.tgz" - integrity sha512-WMqqw06w1vUt9ZfT0gOFhMf3wHsWhaCrxGrckGs5Cci6ybDW87IvPaOd2pnBwT6BJuP/CzXDZxjFgmSULLdsdw== - optionalDependencies: - "@napi-rs/canvas" "^0.1.95" - node-readable-to-web-readable-stream "^0.4.2" - -picocolors@^1.0.0, picocolors@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" - integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== - -"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" - integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== - -"playwright-core@>= 1.0.0", playwright-core@1.58.2: - version "1.58.2" - resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz" - integrity sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg== - -playwright@*, playwright@^1.56.1, playwright@1.58.2: - version "1.58.2" - resolved "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz" - integrity sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A== - dependencies: - playwright-core "1.58.2" - optionalDependencies: - fsevents "2.3.2" - -pluralize@8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz" - integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== - -pngjs@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz" - integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== - -postcss-load-config@^3.1.4: - version "3.1.4" - resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz" - integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== - dependencies: - lilconfig "^2.0.5" - yaml "^1.10.2" - -postcss-safe-parser@^7.0.0: - version "7.0.1" - resolved "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz" - integrity sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A== - -postcss-scss@^4.0.9: - version "4.0.9" - resolved "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz" - integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A== - -postcss-selector-parser@^7.0.0: - version "7.1.1" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz" - integrity sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-selector-parser@6.0.10: - version "6.0.10" - resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz" - integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss@^8.4.29, postcss@^8.4.31, postcss@^8.4.49, postcss@^8.5.6, postcss@>=8.0.9: - version "8.5.8" - resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz" - integrity sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg== - dependencies: - nanoid "^3.3.11" - picocolors "^1.1.1" - source-map-js "^1.2.1" - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier-plugin-svelte@*, prettier-plugin-svelte@^3.4.0: - version "3.5.1" - resolved "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.1.tgz" - integrity sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg== - -prettier-plugin-tailwindcss@^0.7.1: - version "0.7.2" - resolved "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz" - integrity sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA== - -prettier@^3.0, prettier@^3.0.0, prettier@^3.6.2: - version "3.8.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz" - integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg== - -prosemirror-changeset@^2.3.0: - version "2.4.1" - resolved "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.1.tgz" - integrity sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw== - dependencies: - prosemirror-transform "^1.0.0" - -prosemirror-commands@^1.6.2: - version "1.7.1" - resolved "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz" - integrity sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w== - dependencies: - prosemirror-model "^1.0.0" - prosemirror-state "^1.0.0" - prosemirror-transform "^1.10.2" - -prosemirror-dropcursor@^1.8.1: - version "1.8.2" - resolved "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz" - integrity sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw== - dependencies: - prosemirror-state "^1.0.0" - prosemirror-transform "^1.1.0" - prosemirror-view "^1.1.0" - -prosemirror-gapcursor@^1.3.2: - version "1.4.1" - resolved "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.1.tgz" - integrity sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw== - dependencies: - prosemirror-keymap "^1.0.0" - prosemirror-model "^1.0.0" - prosemirror-state "^1.0.0" - prosemirror-view "^1.0.0" - -prosemirror-history@^1.4.1: - version "1.5.0" - resolved "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz" - integrity sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg== - dependencies: - prosemirror-state "^1.2.2" - prosemirror-transform "^1.0.0" - prosemirror-view "^1.31.0" - rope-sequence "^1.3.0" - -prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.2.2, prosemirror-keymap@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz" - integrity sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw== - dependencies: - prosemirror-state "^1.0.0" - w3c-keyname "^2.2.0" - -prosemirror-model@^1.0.0, prosemirror-model@^1.20.0, prosemirror-model@^1.21.0, prosemirror-model@^1.24.1, prosemirror-model@^1.25.4: - version "1.25.4" - resolved "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz" - integrity sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA== - dependencies: - orderedmap "^2.0.0" - -prosemirror-schema-list@^1.5.0: - version "1.5.1" - resolved "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz" - integrity sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q== - dependencies: - prosemirror-model "^1.0.0" - prosemirror-state "^1.0.0" - prosemirror-transform "^1.7.3" - -prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.4.3, prosemirror-state@^1.4.4: - version "1.4.4" - resolved "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz" - integrity sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw== - dependencies: - prosemirror-model "^1.0.0" - prosemirror-transform "^1.0.0" - prosemirror-view "^1.27.0" - -prosemirror-tables@^1.6.4: - version "1.8.5" - resolved "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.5.tgz" - integrity sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw== - dependencies: - prosemirror-keymap "^1.2.3" - prosemirror-model "^1.25.4" - prosemirror-state "^1.4.4" - prosemirror-transform "^1.10.5" - prosemirror-view "^1.41.4" - -prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.10.2, prosemirror-transform@^1.10.5, prosemirror-transform@^1.7.3: - version "1.12.0" - resolved "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.12.0.tgz" - integrity sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w== - dependencies: - prosemirror-model "^1.21.0" - -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.38.1, prosemirror-view@^1.41.4: - version "1.41.8" - resolved "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.8.tgz" - integrity sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA== - dependencies: - prosemirror-model "^1.20.0" - prosemirror-state "^1.0.0" - prosemirror-transform "^1.1.0" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -readdirp@^4.0.1: - version "4.1.2" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz" - integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== - -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve@^1.22.1: - version "1.22.11" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz" - integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== - dependencies: - is-core-module "^2.16.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -rollup@^1.20.0||^2.0.0||^3.0.0||^4.0.0, rollup@^2.68.0||^3.0.0||^4.0.0, rollup@^2.78.0||^3.0.0||^4.0.0, rollup@^4.43.0, rollup@^4.59.0: - version "4.59.0" - resolved "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz" - integrity sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg== - dependencies: - "@types/estree" "1.0.8" - optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.59.0" - "@rollup/rollup-android-arm64" "4.59.0" - "@rollup/rollup-darwin-arm64" "4.59.0" - "@rollup/rollup-darwin-x64" "4.59.0" - "@rollup/rollup-freebsd-arm64" "4.59.0" - "@rollup/rollup-freebsd-x64" "4.59.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.59.0" - "@rollup/rollup-linux-arm-musleabihf" "4.59.0" - "@rollup/rollup-linux-arm64-gnu" "4.59.0" - "@rollup/rollup-linux-arm64-musl" "4.59.0" - "@rollup/rollup-linux-loong64-gnu" "4.59.0" - "@rollup/rollup-linux-loong64-musl" "4.59.0" - "@rollup/rollup-linux-ppc64-gnu" "4.59.0" - "@rollup/rollup-linux-ppc64-musl" "4.59.0" - "@rollup/rollup-linux-riscv64-gnu" "4.59.0" - "@rollup/rollup-linux-riscv64-musl" "4.59.0" - "@rollup/rollup-linux-s390x-gnu" "4.59.0" - "@rollup/rollup-linux-x64-gnu" "4.59.0" - "@rollup/rollup-linux-x64-musl" "4.59.0" - "@rollup/rollup-openbsd-x64" "4.59.0" - "@rollup/rollup-openharmony-arm64" "4.59.0" - "@rollup/rollup-win32-arm64-msvc" "4.59.0" - "@rollup/rollup-win32-ia32-msvc" "4.59.0" - "@rollup/rollup-win32-x64-gnu" "4.59.0" - "@rollup/rollup-win32-x64-msvc" "4.59.0" - fsevents "~2.3.2" - -rope-sequence@^1.3.0: - version "1.3.4" - resolved "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz" - integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== - -sade@^1.7.4: - version "1.8.1" - resolved "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz" - integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== - dependencies: - mri "^1.1.0" - -semver@^7.5.3, semver@^7.6.3, semver@^7.7.2, semver@^7.7.3: - version "7.7.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz" - integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== - -set-cookie-parser@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz" - integrity sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q== - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -siginfo@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz" - integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== - -sirv@^3.0.0, sirv@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz" - integrity sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g== - dependencies: - "@polka/url" "^1.0.0-next.24" - mrmime "^2.0.0" - totalist "^3.0.0" - -source-map-js@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" - integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== - -sqlite-wasm-kysely@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/sqlite-wasm-kysely/-/sqlite-wasm-kysely-0.3.0.tgz" - integrity sha512-TzjBNv7KwRw6E3pdKdlRyZiTmUIE0UttT/Sl56MVwVARl/u5gp978KepazCJZewFUnlWHz9i3NQd4kOtP/Afdg== - dependencies: - "@sqlite.org/sqlite-wasm" "^3.48.0-build2" - -stackback@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz" - integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== - -std-env@^4.0.0-rc.1: - version "4.0.0" - resolved "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz" - integrity sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ== - -strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -supports-color@^10.2.2: - version "10.2.2" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz" - integrity sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g== - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -svelte-check@^4.3.4: - version "4.4.5" - resolved "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.5.tgz" - integrity sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw== - dependencies: - "@jridgewell/trace-mapping" "^0.3.25" - chokidar "^4.0.1" - fdir "^6.2.0" - picocolors "^1.0.0" - sade "^1.7.4" - -svelte-eslint-parser@^1.4.0: - version "1.6.0" - resolved "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.6.0.tgz" - integrity sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw== - dependencies: - eslint-scope "^8.2.0" - eslint-visitor-keys "^4.0.0" - espree "^10.0.0" - postcss "^8.4.49" - postcss-scss "^4.0.9" - postcss-selector-parser "^7.0.0" - semver "^7.7.2" - -"svelte@^3 || ^4 || ^5 || ^5.0.0-next.0", "svelte@^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0", "svelte@^3.37.0 || ^4.0.0 || ^5.0.0", "svelte@^4.0.0 || ^5.0.0-next.0", svelte@^5.0.0, svelte@^5.43.8: - version "5.53.12" - resolved "https://registry.npmjs.org/svelte/-/svelte-5.53.12.tgz" - integrity sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA== - dependencies: - "@jridgewell/remapping" "^2.3.4" - "@jridgewell/sourcemap-codec" "^1.5.0" - "@sveltejs/acorn-typescript" "^1.0.5" - "@types/estree" "^1.0.5" - "@types/trusted-types" "^2.0.7" - acorn "^8.12.1" - aria-query "5.3.1" - axobject-query "^4.1.0" - clsx "^2.1.1" - devalue "^5.6.4" - esm-env "^1.2.1" - esrap "^2.2.2" - is-reference "^3.0.3" - locate-character "^3.0.0" - magic-string "^0.30.11" - zimmerframe "^1.1.2" - -tailwindcss@^4.1.17, "tailwindcss@>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1", "tailwindcss@>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1", tailwindcss@4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz" - integrity sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw== - -tapable@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz" - integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== - -tinybench@^2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz" - integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== - -tinyexec@^1.0.2: - version "1.0.4" - resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz" - integrity sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw== - -tinyglobby@^0.2.15: - version "0.2.15" - resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz" - integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== - dependencies: - fdir "^6.5.0" - picomatch "^4.0.3" - -tinyrainbow@^3.0.3: - version "3.1.0" - resolved "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz" - integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw== - -totalist@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz" - integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== - -ts-api-utils@^2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz" - integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-fest@^4.39.1: - version "4.41.0" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz" - integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== - -typescript-eslint@^8.47.0: - version "8.57.0" - resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz" - integrity sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA== - dependencies: - "@typescript-eslint/eslint-plugin" "8.57.0" - "@typescript-eslint/parser" "8.57.0" - "@typescript-eslint/typescript-estree" "8.57.0" - "@typescript-eslint/utils" "8.57.0" - -typescript@^5.3.3, typescript@^5.9.3, typescript@^5.x, typescript@>=4.8.4, "typescript@>=4.8.4 <6.0.0", typescript@>=5.0.0: - version "5.9.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz" - integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== - -undici-types@~7.16.0: - version "7.16.0" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz" - integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== - -unplugin@^2.1.2: - version "2.3.11" - resolved "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz" - integrity sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww== - dependencies: - "@jridgewell/remapping" "^2.3.5" - acorn "^8.15.0" - picomatch "^4.0.3" - webpack-virtual-modules "^0.6.2" - -uri-js-replace@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz" - integrity sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urlpattern-polyfill@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz" - integrity sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw== - -util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -uuid@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz" - integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== - -uuid@^11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz" - integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== - -uuid@^13.0.0: - version "13.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz" - integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== - -vite-plugin-devtools-json@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/vite-plugin-devtools-json/-/vite-plugin-devtools-json-1.0.0.tgz" - integrity sha512-MobvwqX76Vqt/O4AbnNMNWoXWGrKUqZbphCUle/J2KXH82yKQiunOeKnz/nqEPosPsoWWPP9FtNuPBSYpiiwkw== - dependencies: - uuid "^11.1.0" - -"vite@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0", "vite@^5.0.0 || ^6.0.0 || ^7.0.0", "vite@^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0", "vite@^5.2.0 || ^6 || ^7", "vite@^6.0.0 || ^7.0.0 || ^8.0.0-0", "vite@^6.3.0 || ^7.0.0", vite@^7.2.2: - version "7.3.1" - resolved "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz" - integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== - dependencies: - esbuild "^0.27.0" - fdir "^6.5.0" - picomatch "^4.0.3" - postcss "^8.5.6" - rollup "^4.43.0" - tinyglobby "^0.2.15" - optionalDependencies: - fsevents "~2.3.3" - -vitefu@^1.1.1: - version "1.1.2" - resolved "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz" - integrity sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw== - -vitest-browser-svelte@^2.0.1: - version "2.1.0" - resolved "https://registry.npmjs.org/vitest-browser-svelte/-/vitest-browser-svelte-2.1.0.tgz" - integrity sha512-Uqcqn9gKhYoNOn5uGOQHSPIEGHgIz25zPP6R63LQ5+yEVHfDXdOKBMba9pBlPIgp31AxYbV9h43j9+W+5M5y+A== - dependencies: - "@playwright/test" "^1.58.2" - "@testing-library/svelte-core" "^1.0.0" - -vitest@^4.0.0, vitest@^4.0.10, vitest@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/vitest/-/vitest-4.1.0.tgz" - integrity sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw== - dependencies: - "@vitest/expect" "4.1.0" - "@vitest/mocker" "4.1.0" - "@vitest/pretty-format" "4.1.0" - "@vitest/runner" "4.1.0" - "@vitest/snapshot" "4.1.0" - "@vitest/spy" "4.1.0" - "@vitest/utils" "4.1.0" - es-module-lexer "^2.0.0" - expect-type "^1.3.0" - magic-string "^0.30.21" - obug "^2.1.1" - pathe "^2.0.3" - picomatch "^4.0.3" - std-env "^4.0.0-rc.1" - tinybench "^2.9.0" - tinyexec "^1.0.2" - tinyglobby "^0.2.15" - tinyrainbow "^3.0.3" - vite "^6.0.0 || ^7.0.0 || ^8.0.0-0" - why-is-node-running "^2.3.0" - -w3c-keyname@^2.2.0: - version "2.2.8" - resolved "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz" - integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== - -webpack-virtual-modules@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz" - integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== - -which@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -why-is-node-running@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz" - integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== - dependencies: - siginfo "^2.0.0" - stackback "0.0.2" - -word-wrap@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - -ws@^8.19.0: - version "8.19.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz" - integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== - -yaml-ast-parser@0.0.43: - version "0.0.43" - resolved "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz" - integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A== - -yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zimmerframe@^1.1.2: - version "1.1.4" - resolved "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz" - integrity sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==