From f662bd870e4b1f3dbb13577163de100f2ca37d2a Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:21:58 +0200 Subject: [PATCH 01/30] chore(deps): add HTML sanitizers for Geschichten rich-text body Adds OWASP Java HTML Sanitizer on the backend and DOMPurify on the frontend. Together with Tiptap on the writer side they form a defense-in-depth chain against XSS in the new Geschichte body field (issue #381). Co-Authored-By: Claude Opus 4.7 --- backend/pom.xml | 7 +++++++ frontend/package-lock.json | 23 ++++++++++++++++++++++- frontend/package.json | 2 ++ frontend/yarn.lock | 16 +++++++++++++++- 4 files changed, 46 insertions(+), 2 deletions(-) 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/frontend/package-lock.json b/frontend/package-lock.json index e39be73d..d54afd27 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "@tiptap/extension-mention": "3.22.5", "@tiptap/starter-kit": "3.22.5", "diff": "^8.0.3", + "dompurify": "^3.4.2", "openapi-fetch": "^0.13.5", "pdfjs-dist": "^5.5.207" }, @@ -28,6 +29,7 @@ "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.17", "@types/diff": "^7.0.2", + "@types/dompurify": "^3.0.5", "@types/node": "^24", "@vitest/browser-playwright": "^4.0.10", "@vitest/coverage-v8": "^4.1.0", @@ -2620,6 +2622,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -2655,7 +2667,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -3584,6 +3596,15 @@ "node": ">=0.3.1" } }, + "node_modules/dompurify": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz", + "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/enhanced-resolve": { "version": "5.20.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 542411e8..ad6083cd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,7 @@ "@tiptap/extension-mention": "3.22.5", "@tiptap/starter-kit": "3.22.5", "diff": "^8.0.3", + "dompurify": "^3.4.2", "openapi-fetch": "^0.13.5", "pdfjs-dist": "^5.5.207" }, @@ -41,6 +42,7 @@ "@tailwindcss/typography": "^0.5.19", "@tailwindcss/vite": "^4.1.17", "@types/diff": "^7.0.2", + "@types/dompurify": "^3.0.5", "@types/node": "^24", "@vitest/browser-playwright": "^4.0.10", "@vitest/coverage-v8": "^4.1.0", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 91d23d4b..dd92428f 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -691,6 +691,13 @@ resolved "https://registry.npmjs.org/@types/diff/-/diff-7.0.2.tgz" integrity sha512-JSWRMozjFKsGlEjiiKajUjIJVKuKdE3oVy2DNtK+fUo8q82nhFZ2CPQwicAIkXrofahDXrWJ7mjelvZphMS98Q== +"@types/dompurify@^3.0.5": + version "3.0.5" + resolved "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz" + integrity sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg== + dependencies: + "@types/trusted-types" "*" + "@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" @@ -713,7 +720,7 @@ resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz" integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q== -"@types/trusted-types@^2.0.7": +"@types/trusted-types@*", "@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== @@ -1162,6 +1169,13 @@ diff@^8.0.3: resolved "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz" integrity sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ== +dompurify@^3.4.2: + version "3.4.2" + resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz" + integrity sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA== + optionalDependencies: + "@types/trusted-types" "^2.0.7" + enhanced-resolve@^5.19.0: version "5.20.0" resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz" -- 2.49.1 From 71b249bf3173ab6ab1b103d91d3e84ca98030288 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:23:03 +0200 Subject: [PATCH 02/30] feat(security): add BLOG_WRITE permission and GESCHICHTE_NOT_FOUND error code Foundation for the Geschichten (story) domain (issue #381). BLOG_WRITE gates authoring of family memory stories; GESCHICHTE_NOT_FOUND is also returned for DRAFTs requested by users without BLOG_WRITE so existence is not leaked. Co-Authored-By: Claude Opus 4.7 --- .../java/org/raddatz/familienarchiv/exception/ErrorCode.java | 4 ++++ .../java/org/raddatz/familienarchiv/security/Permission.java | 1 + 2 files changed, 5 insertions(+) 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/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, -- 2.49.1 From b944ae9510427ba7e68c2286d21f6e20ba38d0a0 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:24:31 +0200 Subject: [PATCH 03/30] feat(geschichte): add entity, status enum, and V58 schema migration Geschichte holds family memory stories (issue #381). Body is unbounded TEXT (Tiptap HTML, no length limit). Two join tables link a story to historical Persons and Documents. A partial index speeds the public index query (status='PUBLISHED' ORDER BY published_at DESC) and reverse-lookup indexes support the ?personId and ?documentId filters. Co-Authored-By: Claude Opus 4.7 --- .../familienarchiv/model/Geschichte.java | 69 +++++++++++++++++++ .../model/GeschichteStatus.java | 6 ++ .../db/migration/V58__add_geschichten.sql | 34 +++++++++ 3 files changed, 109 insertions(+) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/model/Geschichte.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/model/GeschichteStatus.java create mode 100644 backend/src/main/resources/db/migration/V58__add_geschichten.sql 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/resources/db/migration/V58__add_geschichten.sql b/backend/src/main/resources/db/migration/V58__add_geschichten.sql new file mode 100644 index 00000000..14bc8eee --- /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 app_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); -- 2.49.1 From b7a2f6c2fe68d62c412d461b469e9688bf0ba30e Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:25:34 +0200 Subject: [PATCH 04/30] feat(geschichte): add repository and update DTO GeschichteRepository.search filters by status / personId / documentId in a single JPQL query so the controller can serve the index page, the person discovery card, and the document drawer column from one method. The DTO is shared between create and update like DocumentUpdateDTO. Co-Authored-By: Claude Opus 4.7 --- .../dto/GeschichteUpdateDTO.java | 21 +++++++++++++ .../repository/GeschichteRepository.java | 30 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/dto/GeschichteUpdateDTO.java create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java 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/repository/GeschichteRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java new file mode 100644 index 00000000..3d6ffbea --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/repository/GeschichteRepository.java @@ -0,0 +1,30 @@ +package org.raddatz.familienarchiv.repository; + +import org.raddatz.familienarchiv.model.Geschichte; +import org.raddatz.familienarchiv.model.GeschichteStatus; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.UUID; + +@Repository +public interface GeschichteRepository extends JpaRepository, JpaSpecificationExecutor { + + @Query(""" + SELECT g FROM Geschichte g + WHERE (:status IS NULL OR g.status = :status) + AND (:personId IS NULL OR :personId IN (SELECT p.id FROM g.persons p)) + AND (:documentId IS NULL OR :documentId IN (SELECT d.id FROM g.documents d)) + ORDER BY COALESCE(g.publishedAt, g.updatedAt) DESC + """) + List search( + @Param("status") GeschichteStatus status, + @Param("personId") UUID personId, + @Param("documentId") UUID documentId, + Pageable pageable); +} -- 2.49.1 From 08d96e5b0f13a82307d6f55f598d730b378ef2c4 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:29:11 +0200 Subject: [PATCH 05/30] feat(geschichte): add GeschichteService with HTML sanitization and DRAFT visibility rules DRAFT stories are 404 to readers without BLOG_WRITE (NOT_FOUND, not FORBIDDEN, to avoid leaking existence). list() forces status=PUBLISHED for non-writers even when they pass status=null. Body HTML is sanitised via OWASP allow-list (p, br, strong, em, h2, h3, ul, ol, li) on every save. publishedAt is set on every transition into PUBLISHED and cleared on retract. Co-Authored-By: Claude Opus 4.7 --- .../service/GeschichteService.java | 178 ++++++++ .../service/GeschichteServiceTest.java | 413 ++++++++++++++++++ 2 files changed, 591 insertions(+) create mode 100644 backend/src/main/java/org/raddatz/familienarchiv/service/GeschichteService.java create mode 100644 backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceTest.java 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..a0f5d4ba --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/GeschichteService.java @@ -0,0 +1,178 @@ +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.security.Permission; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +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; + } + + public List list(GeschichteStatus status, UUID personId, UUID documentId, int limit) { + GeschichteStatus effective = currentUserHasBlogWrite() ? status : GeschichteStatus.PUBLISHED; + int safeLimit = limit <= 0 ? DEFAULT_LIMIT : Math.min(limit, MAX_LIMIT); + Pageable pageable = PageRequest.of(0, safeLimit); + return geschichteRepository.search(effective, personId, documentId, pageable); + } + + // ─── 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/test/java/org/raddatz/familienarchiv/service/GeschichteServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceTest.java new file mode 100644 index 00000000..ffd6b15f --- /dev/null +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/GeschichteServiceTest.java @@ -0,0 +1,413 @@ +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.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +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.security.Permission; +import org.springframework.data.domain.Pageable; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GeschichteServiceTest { + + @Mock + GeschichteRepository geschichteRepository; + @Mock + PersonService personService; + @Mock + DocumentService documentService; + @Mock + UserService userService; + + @InjectMocks + GeschichteService geschichteService; + + AppUser writer; + AppUser reader; + + @BeforeEach + void setUp() { + SecurityContextHolder.clearContext(); + writer = AppUser.builder().id(UUID.randomUUID()).email("writer@test").build(); + reader = AppUser.builder().id(UUID.randomUUID()).email("reader@test").build(); + } + + @AfterEach + void tearDown() { + SecurityContextHolder.clearContext(); + } + + // ─── getById ────────────────────────────────────────────────────────────── + + @Test + void getById_throws_NOT_FOUND_for_draft_when_user_lacks_BLOG_WRITE() { + authenticateAs(reader, Permission.READ_ALL); + UUID id = UUID.randomUUID(); + Geschichte draft = draft(id); + when(geschichteRepository.findById(id)).thenReturn(Optional.of(draft)); + + assertThatThrownBy(() -> geschichteService.getById(id)) + .isInstanceOf(DomainException.class) + .extracting("code") + .isEqualTo(ErrorCode.GESCHICHTE_NOT_FOUND); + } + + @Test + void getById_returns_draft_when_user_has_BLOG_WRITE() { + authenticateAs(writer, Permission.BLOG_WRITE); + UUID id = UUID.randomUUID(); + Geschichte draft = draft(id); + when(geschichteRepository.findById(id)).thenReturn(Optional.of(draft)); + + Geschichte result = geschichteService.getById(id); + + assertThat(result).isSameAs(draft); + } + + @Test + void getById_returns_published_to_anyone_authenticated() { + authenticateAs(reader, Permission.READ_ALL); + UUID id = UUID.randomUUID(); + Geschichte published = published(id); + when(geschichteRepository.findById(id)).thenReturn(Optional.of(published)); + + Geschichte result = geschichteService.getById(id); + + assertThat(result).isSameAs(published); + } + + @Test + void getById_throws_NOT_FOUND_when_id_unknown() { + authenticateAs(reader, Permission.READ_ALL); + UUID id = UUID.randomUUID(); + when(geschichteRepository.findById(id)).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> geschichteService.getById(id)) + .isInstanceOf(DomainException.class) + .extracting("code") + .isEqualTo(ErrorCode.GESCHICHTE_NOT_FOUND); + } + + // ─── list ───────────────────────────────────────────────────────────────── + + @Test + void list_forces_PUBLISHED_status_for_reader_without_BLOG_WRITE() { + authenticateAs(reader, Permission.READ_ALL); + when(geschichteRepository.search(eq(GeschichteStatus.PUBLISHED), any(), any(), any())) + .thenReturn(List.of(published(UUID.randomUUID()))); + + geschichteService.list(/*status*/ null, /*personId*/ null, /*documentId*/ null, /*limit*/ 50); + + verify(geschichteRepository).search(eq(GeschichteStatus.PUBLISHED), any(), any(), any()); + } + + @Test + void list_passes_null_status_through_for_BLOG_WRITER_so_drafts_are_visible() { + authenticateAs(writer, Permission.BLOG_WRITE); + when(geschichteRepository.search(any(), any(), any(), any())) + .thenReturn(List.of(draft(UUID.randomUUID()), published(UUID.randomUUID()))); + + geschichteService.list(null, null, null, 50); + + verify(geschichteRepository).search(eq(null), any(), any(), any()); + } + + @Test + void list_filters_by_personId() { + authenticateAs(reader, Permission.READ_ALL); + UUID personId = UUID.randomUUID(); + when(geschichteRepository.search(any(), eq(personId), any(), any())) + .thenReturn(List.of()); + + geschichteService.list(null, personId, null, 50); + + verify(geschichteRepository).search(eq(GeschichteStatus.PUBLISHED), eq(personId), eq(null), any()); + } + + @Test + void list_filters_by_documentId() { + authenticateAs(reader, Permission.READ_ALL); + UUID documentId = UUID.randomUUID(); + when(geschichteRepository.search(any(), any(), eq(documentId), any())) + .thenReturn(List.of()); + + geschichteService.list(null, null, documentId, 50); + + verify(geschichteRepository).search(eq(GeschichteStatus.PUBLISHED), eq(null), eq(documentId), any()); + } + + // ─── create ────────────────────────────────────────────────────────────── + + @Test + void create_sets_status_to_DRAFT_by_default() { + authenticateAs(writer, Permission.BLOG_WRITE); + when(userService.findByEmail(writer.getEmail())).thenReturn(writer); + when(geschichteRepository.save(any(Geschichte.class))) + .thenAnswer(inv -> inv.getArgument(0)); + + GeschichteUpdateDTO dto = new GeschichteUpdateDTO(); + dto.setTitle("My Story"); + dto.setBody("

plain text

"); + + Geschichte saved = geschichteService.create(dto); + + assertThat(saved.getStatus()).isEqualTo(GeschichteStatus.DRAFT); + assertThat(saved.getPublishedAt()).isNull(); + assertThat(saved.getAuthor()).isSameAs(writer); + } + + @Test + void create_sanitizes_body_HTML_dropping_disallowed_tags() { + authenticateAs(writer, Permission.BLOG_WRITE); + when(userService.findByEmail(writer.getEmail())).thenReturn(writer); + when(geschichteRepository.save(any(Geschichte.class))) + .thenAnswer(inv -> inv.getArgument(0)); + + GeschichteUpdateDTO dto = new GeschichteUpdateDTO(); + dto.setTitle("XSS attempt"); + dto.setBody("

safe

"); + + Geschichte saved = geschichteService.create(dto); + + assertThat(saved.getBody()) + .contains("

safe

") + .doesNotContain(""); + + Geschichte saved = geschichteService.update(id, dto); + + assertThat(saved.getBody()).doesNotContain(""); + 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("'); + expect(result).not.toContain(' + + + +{#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} +
-- 2.49.1 From ab3e633a0cd681e9a10eda8a66427b03848bf860 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:49:10 +0200 Subject: [PATCH 11/30] feat(geschichten): add GeschichteEditor with Tiptap toolbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tiptap StarterKit configured for B/I/¶/H2/H3/UL/OL/history; code, codeBlock, blockquote, strike, horizontalRule and hardBreak disabled to keep output matching the backend HTML allow-list. Two-column responsive layout with the editor body on the left and Personen / Dokumente / Status sections in the sidebar. Sticky save bar adapts to DRAFT vs PUBLISHED state. Title-required guard with inline error and beforeNavigate dirty-state guard. Co-Authored-By: Claude Opus 4.7 --- .../lib/components/GeschichteEditor.svelte | 329 ++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 frontend/src/lib/components/GeschichteEditor.svelte 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} +
+
-- 2.49.1 From 9e6efacbcb66e6925b3ad26c9be32bbcf4a21cec Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:50:58 +0200 Subject: [PATCH 12/30] feat(geschichten): add stripHtml util and GeschichtenCard component stripHtml() strips tags via DOMParser (browser) with a regex fallback for SSR. plainExcerpt() truncates at a word boundary with an ellipsis. Both covered by Vitest specs. GeschichtenCard renders the top 3 published stories about a person on /persons/[id], with an editorial excerpt, publication date, author, and a "+ Geschichte schreiben" link visible only to BLOG_WRITERs. Footer link to /geschichten?personId=... appears once geschichten.length >= 3. Co-Authored-By: Claude Opus 4.7 --- .../src/lib/components/GeschichtenCard.svelte | 87 +++++++++++++++++++ frontend/src/lib/utils/stripHtml.spec.ts | 36 ++++++++ frontend/src/lib/utils/stripHtml.ts | 23 +++++ 3 files changed, 146 insertions(+) create mode 100644 frontend/src/lib/components/GeschichtenCard.svelte create mode 100644 frontend/src/lib/utils/stripHtml.spec.ts create mode 100644 frontend/src/lib/utils/stripHtml.ts diff --git a/frontend/src/lib/components/GeschichtenCard.svelte b/frontend/src/lib/components/GeschichtenCard.svelte new file mode 100644 index 00000000..6b8a0d4c --- /dev/null +++ b/frontend/src/lib/components/GeschichtenCard.svelte @@ -0,0 +1,87 @@ + + +{#if geschichten.length > 0} +
+
+

+ {m.geschichten_card_heading()} +

+ {#if canWrite} + + {m.geschichten_card_write_action()} + + {/if} +
+ +
    + {#each visible as g (g.id)} +
  • + + {g.title} + +

    + {authorName(g)} + {#if formatPublishedDate(g)}· {formatPublishedDate(g)}{/if} +

    + {#if g.body} +

    {plainExcerpt(g.body, 80)}

    + {/if} +
  • + {/each} +
+ + {#if hasOverflow} + + {/if} +
+{/if} diff --git a/frontend/src/lib/utils/stripHtml.spec.ts b/frontend/src/lib/utils/stripHtml.spec.ts new file mode 100644 index 00000000..4dcc7308 --- /dev/null +++ b/frontend/src/lib/utils/stripHtml.spec.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest'; +import { plainExcerpt, stripHtml } from './stripHtml'; + +describe('stripHtml', () => { + it('returns empty string for null/undefined/empty', () => { + expect(stripHtml(null)).toBe(''); + expect(stripHtml(undefined)).toBe(''); + expect(stripHtml('')).toBe(''); + }); + + it('strips tags and preserves visible text', () => { + expect(stripHtml('

Hello world

')).toBe('Hello world'); + }); + + it('strips nested HTML', () => { + expect(stripHtml('

A

B

')).toBe('AB'); + }); +}); + +describe('plainExcerpt', () => { + it('returns full text when under the limit', () => { + expect(plainExcerpt('

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); // 20 chars + ellipsis + 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/stripHtml.ts b/frontend/src/lib/utils/stripHtml.ts new file mode 100644 index 00000000..00ce62ff --- /dev/null +++ b/frontend/src/lib/utils/stripHtml.ts @@ -0,0 +1,23 @@ +/** + * Strip HTML tags from a string and return the plain text. + * Uses DOMParser in the browser, falls back to a regex strip on the server + * (where DOMParser is not available without isomorphic-dompurify's JSDOM). + */ +export function stripHtml(html: string | null | undefined): string { + if (!html) return ''; + if (typeof DOMParser === 'function') { + const doc = new DOMParser().parseFromString(html, 'text/html'); + return (doc.body.textContent ?? '').trim(); + } + return html.replace(/<[^>]*>/g, '').trim(); +} + +/** + * Strip HTML and truncate to a maximum length, appending an ellipsis when + * the source exceeds it. Used for editorial story excerpts. + */ +export function plainExcerpt(html: string | null | undefined, max = 80): string { + const text = stripHtml(html); + if (text.length <= max) return text; + return text.slice(0, max).replace(/\s+\S*$/, '') + '…'; +} -- 2.49.1 From fe1014a08a587379eef8a2b818a52f531ce5a7d6 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 17:54:31 +0200 Subject: [PATCH 13/30] feat(geschichten): add /geschichten routes (index, detail, new, edit) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /geschichten — published-stories index with filter pills + "+ Neue Geschichte" for BLOG_WRITERs; supports ?personId and ?documentId pre-filtering - /geschichten/[id] — reader detail with sanitised {@html} body, person and document chip sections, BLOG_WRITER edit/delete with confirm dialog - /geschichten/new — editor with optional ?personId and ?documentId pre-fill (silent ignore on unknown IDs to avoid leaking entity existence) - /geschichten/[id]/edit — editor populated from existing story; BLOG_WRITE guard redirects readers to the detail page All routes load via createApiClient(fetch) with !response.ok error handling following the project pattern; PATCH/DELETE go through raw fetch which the Vite dev proxy / Caddy production proxy authenticates via cookie. Co-Authored-By: Claude Opus 4.7 --- .../src/routes/geschichten/+page.server.ts | 36 +++++ frontend/src/routes/geschichten/+page.svelte | 130 +++++++++++++++++ .../routes/geschichten/[id]/+page.server.ts | 16 +++ .../src/routes/geschichten/[id]/+page.svelte | 133 ++++++++++++++++++ .../geschichten/[id]/edit/+page.server.ts | 20 +++ .../routes/geschichten/[id]/edit/+page.svelte | 60 ++++++++ .../routes/geschichten/new/+page.server.ts | 33 +++++ .../src/routes/geschichten/new/+page.svelte | 64 +++++++++ 8 files changed, 492 insertions(+) create mode 100644 frontend/src/routes/geschichten/+page.server.ts create mode 100644 frontend/src/routes/geschichten/+page.svelte create mode 100644 frontend/src/routes/geschichten/[id]/+page.server.ts create mode 100644 frontend/src/routes/geschichten/[id]/+page.svelte create mode 100644 frontend/src/routes/geschichten/[id]/edit/+page.server.ts create mode 100644 frontend/src/routes/geschichten/[id]/edit/+page.svelte create mode 100644 frontend/src/routes/geschichten/new/+page.server.ts create mode 100644 frontend/src/routes/geschichten/new/+page.svelte diff --git a/frontend/src/routes/geschichten/+page.server.ts b/frontend/src/routes/geschichten/+page.server.ts new file mode 100644 index 00000000..66e3fdf1 --- /dev/null +++ b/frontend/src/routes/geschichten/+page.server.ts @@ -0,0 +1,36 @@ +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 ({ url, fetch }) => { + const api = createApiClient(fetch); + const personId = url.searchParams.get('personId') ?? undefined; + const documentId = url.searchParams.get('documentId') ?? undefined; + + const [listResult, personResult] = await Promise.all([ + api.GET('/api/geschichten', { + params: { + query: { + status: 'PUBLISHED', + personId, + documentId + } + } + }), + personId + ? api.GET('/api/persons/{id}', { params: { path: { id: personId } } }) + : Promise.resolve(null) + ]); + + if (!listResult.response.ok) { + const code = (listResult.error as unknown as { code?: string })?.code; + throw error(listResult.response.status, getErrorMessage(code)); + } + + return { + geschichten: listResult.data ?? [], + personFilter: personResult && personResult.response.ok ? personResult.data! : null, + documentFilter: documentId ?? null + }; +}; diff --git a/frontend/src/routes/geschichten/+page.svelte b/frontend/src/routes/geschichten/+page.svelte new file mode 100644 index 00000000..d85aeab3 --- /dev/null +++ b/frontend/src/routes/geschichten/+page.svelte @@ -0,0 +1,130 @@ + + +
+
+

{m.geschichten_index_title()}

+ {#if data.canBlogWrite} + + {m.geschichten_new_button()} + + {/if} +
+ + +
+ + + {#if data.personFilter} + + {:else} + + {/if} +
+ + {#if showPersonPicker} +
+ +
+ {/if} + + + {#if data.geschichten.length === 0} +
+ {#if data.personFilter} + {m.geschichten_empty_for_person({ name: filterName })} + {: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..e96af176 --- /dev/null +++ b/frontend/src/routes/geschichten/[id]/+page.svelte @@ -0,0 +1,133 @@ + + +
+
+ +
+ +
+
+

+ {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} + + +
-- 2.49.1 From ed270f68e1c2578f8582d49b1effb47c4223a9bd Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:01:19 +0200 Subject: [PATCH 14/30] feat(geschichten): wire discovery integrations on Person and Document pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Person detail (/persons/[id]): - Server load fetches GET /api/geschichten?status=PUBLISHED&personId={id} in parallel with the existing person/document queries. - Renders below the received-documents list when the person has at least one published story. Document detail (/documents/[id]): - Server load adds the same parallel call with documentId={id}. - DocumentTopBar gains geschichten + canBlogWrite props that flow through to DocumentMetadataDrawer. - DocumentMetadataDrawer's grid expands to lg:grid-cols-4 when the Geschichten column should appear (stories exist OR user can author), and shows "+ Geschichte anhängen" / "Alle anzeigen" links following the >= 3-story threshold from issue comment #5758. Co-Authored-By: Claude Opus 4.7 --- .../components/DocumentMetadataDrawer.svelte | 79 ++++++++++++++++++- .../src/lib/components/DocumentTopBar.svelte | 16 +++- .../src/routes/documents/[id]/+page.server.ts | 10 ++- .../src/routes/documents/[id]/+page.svelte | 2 + .../src/routes/persons/[id]/+page.server.ts | 9 ++- frontend/src/routes/persons/[id]/+page.svelte | 12 +++ 6 files changed, 121 insertions(+), 7 deletions(-) diff --git a/frontend/src/lib/components/DocumentMetadataDrawer.svelte b/frontend/src/lib/components/DocumentMetadataDrawer.svelte index ff8e177c..e30f87c8 100644 --- a/frontend/src/lib/components/DocumentMetadataDrawer.svelte +++ b/frontend/src/lib/components/DocumentMetadataDrawer.svelte @@ -7,6 +7,12 @@ import RelationshipPill from '$lib/components/RelationshipPill.svelte'; type Person = { id: string; firstName?: string | null; lastName: string; displayName: string }; type Tag = { id: string; name: string }; +type GeschichteSummary = { + id: string; + title: string; + publishedAt?: string; + author?: { firstName?: string; lastName?: string; email: string }; +}; type Props = { documentDate: string | null; @@ -16,6 +22,9 @@ type Props = { receivers: Person[]; tags: Tag[]; inferredRelationship?: { labelFromA: string; labelFromB: string } | null; + geschichten?: GeschichteSummary[]; + documentId?: string; + canBlogWrite?: boolean; }; let { @@ -25,10 +34,30 @@ let { sender, receivers, tags, - inferredRelationship = null + inferredRelationship = null, + geschichten = [], + documentId, + canBlogWrite = false }: Props = $props(); const VISIBLE_RECEIVER_LIMIT = 5; +const VISIBLE_GESCHICHTEN_LIMIT = 3; +const showGeschichtenColumn = $derived(geschichten.length > 0 || canBlogWrite); +const visibleGeschichten = $derived(geschichten.slice(0, VISIBLE_GESCHICHTEN_LIMIT)); +const hasGeschichtenOverflow = $derived(geschichten.length >= VISIBLE_GESCHICHTEN_LIMIT); +const gridClass = $derived(showGeschichtenColumn ? 'lg:grid-cols-4' : 'lg:grid-cols-3'); + +function formatGeschichteAuthor(g: GeschichteSummary): string { + const a = g.author; + if (!a) return ''; + const full = [a.firstName, a.lastName].filter(Boolean).join(' ').trim(); + return full || a.email || ''; +} + +function formatGeschichteDate(g: GeschichteSummary): string { + if (!g.publishedAt) return ''; + return formatDate(g.publishedAt.slice(0, 10), 'short'); +} const formattedDate = $derived(documentDate ? formatDate(documentDate) : '—'); const displayLocation = $derived(location ?? '—'); @@ -67,7 +96,7 @@ function getFullName(person: Person): string { {/snippet}
-
+

@@ -159,5 +188,51 @@ function getFullName(person: Person): string {

{m.doc_details_no_tags()}

{/if}

+ + + {#if showGeschichtenColumn} +
+
+

+ {m.geschichten_card_heading()} +

+ {#if canBlogWrite && documentId} + + {m.geschichten_card_attach_action()} + + {/if} +
+ + {#if geschichten.length === 0} +

+ {:else} +
    + {#each visibleGeschichten as g (g.id)} +
  • + + {g.title} + +

    + {formatGeschichteAuthor(g)} + {#if formatGeschichteDate(g)}· {formatGeschichteDate(g)}{/if} +

    +
  • + {/each} +
+ + {#if hasGeschichtenOverflow && documentId} + + {m.geschichten_card_show_all()} → + + {/if} + {/if} +
+ {/if}
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/routes/documents/[id]/+page.server.ts b/frontend/src/routes/documents/[id]/+page.server.ts index e601dd44..6f3d297b 100644 --- a/frontend/src/routes/documents/[id]/+page.server.ts +++ b/frontend/src/routes/documents/[id]/+page.server.ts @@ -7,7 +7,12 @@ export async function load({ params, fetch }) { const { id } = params; const api = createApiClient(fetch); - const docResult = await api.GET('/api/documents/{id}', { params: { path: { id } } }); + const [docResult, geschichtenResult] = await Promise.all([ + api.GET('/api/documents/{id}', { params: { path: { id } } }), + api.GET('/api/geschichten', { + params: { query: { status: 'PUBLISHED', documentId: id } } + }) + ]); if (docResult.response.status === 401) throw redirect(302, '/login'); @@ -18,8 +23,9 @@ export async function load({ params, fetch }) { const document = docResult.data!; const inferredRelationship = await loadInferredRelationship(api, document); + const geschichten = geschichtenResult.data ?? []; - return { document, inferredRelationship }; + return { document, inferredRelationship, geschichten }; } async function loadInferredRelationship( diff --git a/frontend/src/routes/documents/[id]/+page.svelte b/frontend/src/routes/documents/[id]/+page.svelte index 69f24b50..49810b90 100644 --- a/frontend/src/routes/documents/[id]/+page.svelte +++ b/frontend/src/routes/documents/[id]/+page.svelte @@ -424,6 +424,8 @@ onMount(() => { fileUrl={fileLoader.fileUrl} bind:transcribeMode={transcribeMode} inferredRelationship={data.inferredRelationship} + geschichten={data.geschichten ?? []} + canBlogWrite={data.canBlogWrite ?? false} />
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} -- 2.49.1 From b698f9f223b70e4a109c42dfa9bc49072ac4785e Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:12:50 +0200 Subject: [PATCH 15/30] test(persons): add seventh GET mock for the geschichten API call The /persons/[id] +page.server.ts now fetches geschichten in parallel with the other endpoints. Each test in this spec mocks the typed-client's GET call sequentially, so each chain needs one extra resolved value. Co-Authored-By: Claude Opus 4.7 --- frontend/src/routes/persons/[id]/page.server.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) 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( -- 2.49.1 From 77ac9a01b5fb0e318a94085d0cfb6038a423a739 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:39:32 +0200 Subject: [PATCH 16/30] =?UTF-8?q?chore(deps):=20drop=20frontend/yarn.lock?= =?UTF-8?q?=20=E2=80=94=20repo=20uses=20npm=20everywhere?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both lockfiles were updated on every npm install, creating a drift surface for nothing. CI, Docker and dev all use npm, so yarn.lock has no consumer. Add it to .gitignore so future yarn-curious developers don't accidentally re-introduce it. Co-Authored-By: Claude Opus 4.7 --- .gitignore | 4 + frontend/yarn.lock | 2794 -------------------------------------------- 2 files changed, 4 insertions(+), 2794 deletions(-) delete mode 100644 frontend/yarn.lock 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/frontend/yarn.lock b/frontend/yarn.lock deleted file mode 100644 index 682efcd2..00000000 --- a/frontend/yarn.lock +++ /dev/null @@ -1,2794 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@asamuzakjp/css-color@^5.1.11": - version "5.1.11" - resolved "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz" - integrity sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg== - dependencies: - "@asamuzakjp/generational-cache" "^1.0.1" - "@csstools/css-calc" "^3.2.0" - "@csstools/css-color-parser" "^4.1.0" - "@csstools/css-parser-algorithms" "^4.0.0" - "@csstools/css-tokenizer" "^4.0.0" - -"@asamuzakjp/dom-selector@^7.1.1": - version "7.1.1" - resolved "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz" - integrity sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ== - dependencies: - "@asamuzakjp/generational-cache" "^1.0.1" - "@asamuzakjp/nwsapi" "^2.3.9" - bidi-js "^1.0.3" - css-tree "^3.2.1" - is-potential-custom-element-name "^1.0.1" - -"@asamuzakjp/generational-cache@^1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz" - integrity sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg== - -"@asamuzakjp/nwsapi@^2.3.9": - version "2.3.9" - resolved "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz" - integrity sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q== - -"@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== - -"@bramus/specificity@^2.4.2": - version "2.4.2" - resolved "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz" - integrity sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw== - dependencies: - css-tree "^3.0.0" - -"@csstools/color-helpers@^6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz" - integrity sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q== - -"@csstools/css-calc@^3.2.0": - version "3.2.0" - resolved "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz" - integrity sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w== - -"@csstools/css-color-parser@^4.1.0": - version "4.1.0" - resolved "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz" - integrity sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ== - dependencies: - "@csstools/color-helpers" "^6.0.2" - "@csstools/css-calc" "^3.2.0" - -"@csstools/css-parser-algorithms@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz" - integrity sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w== - -"@csstools/css-syntax-patches-for-csstree@^1.1.3": - version "1.1.3" - resolved "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz" - integrity sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg== - -"@csstools/css-tokenizer@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz" - integrity sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA== - -"@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" - -"@exodus/bytes@^1.11.0", "@exodus/bytes@^1.15.0", "@exodus/bytes@^1.6.0": - version "1.15.0" - resolved "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz" - integrity sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ== - -"@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== - -bidi-js@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz" - integrity sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw== - dependencies: - require-from-string "^2.0.2" - -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" - -css-tree@^3.0.0, css-tree@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz" - integrity sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA== - dependencies: - mdn-data "2.27.1" - source-map-js "^1.2.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== - -data-urls@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz" - integrity sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA== - dependencies: - whatwg-mimetype "^5.0.0" - whatwg-url "^16.0.0" - -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" - -decimal.js@^10.6.0: - version "10.6.0" - resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz" - integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== - -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== - -dompurify@^3.4.2: - version "3.4.2" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz" - integrity sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA== - optionalDependencies: - "@types/trusted-types" "^2.0.7" - -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" - -entities@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz" - integrity sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA== - -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-encoding-sniffer@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz" - integrity sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg== - dependencies: - "@exodus/bytes" "^1.6.0" - -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-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - -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== - -isomorphic-dompurify@^3.12.0: - version "3.12.0" - resolved "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-3.12.0.tgz" - integrity sha512-8n+j+6ypTHvriJwFOQ2qusQ6bzGjZVcR3jbe1pBpLcGI1dn4WIl0ctLBngqE5QttquQBAlKXwJeTMw+X7x7qKw== - dependencies: - dompurify "^3.4.2" - jsdom "^29.1.1" - -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" - -jsdom@*, jsdom@^29.1.1: - version "29.1.1" - resolved "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz" - integrity sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q== - dependencies: - "@asamuzakjp/css-color" "^5.1.11" - "@asamuzakjp/dom-selector" "^7.1.1" - "@bramus/specificity" "^2.4.2" - "@csstools/css-syntax-patches-for-csstree" "^1.1.3" - "@exodus/bytes" "^1.15.0" - css-tree "^3.2.1" - data-urls "^7.0.0" - decimal.js "^10.6.0" - html-encoding-sniffer "^6.0.0" - is-potential-custom-element-name "^1.0.1" - lru-cache "^11.3.5" - parse5 "^8.0.1" - saxes "^6.0.0" - symbol-tree "^3.2.4" - tough-cookie "^6.0.1" - undici "^7.25.0" - w3c-xmlserializer "^5.0.0" - webidl-conversions "^8.0.1" - whatwg-mimetype "^5.0.0" - whatwg-url "^16.0.1" - xml-name-validator "^5.0.0" - -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== - -lru-cache@^11.3.5: - version "11.3.5" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz" - integrity sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw== - -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" - -mdn-data@2.27.1: - version "2.27.1" - resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz" - integrity sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ== - -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" - -parse5@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz" - integrity sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw== - dependencies: - entities "^8.0.0" - -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, punycode@^2.3.1: - 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" - -saxes@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz" - integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== - dependencies: - xmlchars "^2.2.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" - -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -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== - -tldts-core@^7.0.30: - version "7.0.30" - resolved "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.30.tgz" - integrity sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q== - -tldts@^7.0.5: - version "7.0.30" - resolved "https://registry.npmjs.org/tldts/-/tldts-7.0.30.tgz" - integrity sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw== - dependencies: - tldts-core "^7.0.30" - -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== - -tough-cookie@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz" - integrity sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw== - dependencies: - tldts "^7.0.5" - -tr46@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz" - integrity sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw== - dependencies: - punycode "^2.3.1" - -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== - -undici@^7.25.0: - version "7.25.0" - resolved "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz" - integrity sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ== - -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== - -w3c-xmlserializer@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz" - integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== - dependencies: - xml-name-validator "^5.0.0" - -webidl-conversions@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz" - integrity sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ== - -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== - -whatwg-mimetype@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz" - integrity sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw== - -whatwg-url@^16.0.0, whatwg-url@^16.0.1: - version "16.0.1" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz" - integrity sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw== - dependencies: - "@exodus/bytes" "^1.11.0" - tr46 "^6.0.0" - webidl-conversions "^8.0.1" - -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== - -xml-name-validator@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz" - integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -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== -- 2.49.1 From 35ec7e799fd31264e818f97a309eaa69fba4c329 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:41:09 +0200 Subject: [PATCH 17/30] feat(admin): add BLOG_WRITE to group permission checkbox UI Both /admin/groups/new and /admin/groups/[id] now expose BLOG_WRITE in the standard-permissions card so admins can grant Geschichten authoring through the UI instead of running raw SQL. Adds Paraglide labels in de/en/es. Closes Markus's review B1 on PR #382. Co-Authored-By: Claude Opus 4.7 --- frontend/messages/de.json | 1 + frontend/messages/en.json | 1 + frontend/messages/es.json | 1 + frontend/src/routes/admin/groups/[id]/+page.svelte | 3 ++- frontend/src/routes/admin/groups/new/+page.svelte | 3 ++- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/messages/de.json b/frontend/messages/de.json index e08dbb1c..932b8f24 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -228,6 +228,7 @@ "admin_perm_read_all": "Nur lesen", "admin_perm_annotate_all": "Lesen & Annotieren", "admin_perm_write_all": "Lesen & Schreiben", + "admin_perm_blog_write": "Geschichten schreiben", "admin_perm_admin": "Vollzugriff (Admin)", "admin_perm_admin_user": "Benutzer verwalten", "admin_perm_admin_tag": "Schlagworte verwalten", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 3e1e691d..2bcb443d 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -228,6 +228,7 @@ "admin_perm_read_all": "Read only", "admin_perm_annotate_all": "Read & Annotate", "admin_perm_write_all": "Read & Write", + "admin_perm_blog_write": "Write stories", "admin_perm_admin": "Full access (Admin)", "admin_perm_admin_user": "Manage users", "admin_perm_admin_tag": "Manage tags", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index a1cff1eb..1777de77 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -228,6 +228,7 @@ "admin_perm_read_all": "Solo lectura", "admin_perm_annotate_all": "Leer y anotar", "admin_perm_write_all": "Leer y escribir", + "admin_perm_blog_write": "Escribir historias", "admin_perm_admin": "Acceso completo (Admin)", "admin_perm_admin_user": "Gestionar usuarios", "admin_perm_admin_tag": "Gestionar etiquetas", diff --git a/frontend/src/routes/admin/groups/[id]/+page.svelte b/frontend/src/routes/admin/groups/[id]/+page.svelte index a6b8527f..9b9a3574 100644 --- a/frontend/src/routes/admin/groups/[id]/+page.svelte +++ b/frontend/src/routes/admin/groups/[id]/+page.svelte @@ -27,7 +27,8 @@ $effect(() => { const STANDARD_PERMISSIONS = $derived([ { value: 'READ_ALL', label: m.admin_perm_read_all() }, { value: 'ANNOTATE_ALL', label: m.admin_perm_annotate_all() }, - { value: 'WRITE_ALL', label: m.admin_perm_write_all() } + { value: 'WRITE_ALL', label: m.admin_perm_write_all() }, + { value: 'BLOG_WRITE', label: m.admin_perm_blog_write() } ]); const ADMIN_PERMISSIONS = $derived([ diff --git a/frontend/src/routes/admin/groups/new/+page.svelte b/frontend/src/routes/admin/groups/new/+page.svelte index 7392ec79..78d7218e 100644 --- a/frontend/src/routes/admin/groups/new/+page.svelte +++ b/frontend/src/routes/admin/groups/new/+page.svelte @@ -6,7 +6,8 @@ import { m } from '$lib/paraglide/messages.js'; const availableStandard = $derived([ { value: 'READ_ALL', label: m.admin_perm_read_all() }, { value: 'ANNOTATE_ALL', label: m.admin_perm_annotate_all() }, - { value: 'WRITE_ALL', label: m.admin_perm_write_all() } + { value: 'WRITE_ALL', label: m.admin_perm_write_all() }, + { value: 'BLOG_WRITE', label: m.admin_perm_blog_write() } ]); const availableAdmin = $derived([ { value: 'ADMIN', label: m.admin_perm_admin() }, -- 2.49.1 From 18e5d18cc78a8347179b0861530a1ea512b8e901 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:42:46 +0200 Subject: [PATCH 18/30] feat(geschichte): V59 grants BLOG_WRITE to existing WRITE_ALL groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without this, the Geschichten feature ships dark on prod day-one — no group holds BLOG_WRITE, so the editor controls never render even for admins. The mapping "anyone who can write documents can also author family stories" is the safest default and admins can revoke afterwards via the new checkbox UI. Closes Tobias's review S5 on PR #382. Co-Authored-By: Claude Opus 4.7 --- .../db/migration/V59__seed_blog_write.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 backend/src/main/resources/db/migration/V59__seed_blog_write.sql 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' + ); -- 2.49.1 From ad535e314b84fbd556adacf5bd7977e7ed9282ce Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 2 May 2026 18:44:40 +0200 Subject: [PATCH 19/30] =?UTF-8?q?refactor(extract-text):=20rename=20stripH?= =?UTF-8?q?tml=20=E2=86=92=20extractText=20and=20document=20non-sanitiser?= =?UTF-8?q?=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a module docstring at the top of extractText.ts spelling out that this is text extraction, not XSS sanitisation, and that callers must rely on safeHtml() (DOMPurify) for security. Adds a Vitest test block with classic XSS-shaped payloads ('); + 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/stripHtml.spec.ts b/frontend/src/lib/utils/stripHtml.spec.ts deleted file mode 100644 index 4dcc7308..00000000 --- a/frontend/src/lib/utils/stripHtml.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { plainExcerpt, stripHtml } from './stripHtml'; - -describe('stripHtml', () => { - it('returns empty string for null/undefined/empty', () => { - expect(stripHtml(null)).toBe(''); - expect(stripHtml(undefined)).toBe(''); - expect(stripHtml('')).toBe(''); - }); - - it('strips tags and preserves visible text', () => { - expect(stripHtml('

Hello world

')).toBe('Hello world'); - }); - - it('strips nested HTML', () => { - expect(stripHtml('

A

B

')).toBe('AB'); - }); -}); - -describe('plainExcerpt', () => { - it('returns full text when under the limit', () => { - expect(plainExcerpt('

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); // 20 chars + ellipsis - 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/stripHtml.ts b/frontend/src/lib/utils/stripHtml.ts deleted file mode 100644 index 00ce62ff..00000000 --- a/frontend/src/lib/utils/stripHtml.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Strip HTML tags from a string and return the plain text. - * Uses DOMParser in the browser, falls back to a regex strip on the server - * (where DOMParser is not available without isomorphic-dompurify's JSDOM). - */ -export function stripHtml(html: string | null | undefined): string { - if (!html) return ''; - if (typeof DOMParser === 'function') { - const doc = new DOMParser().parseFromString(html, 'text/html'); - return (doc.body.textContent ?? '').trim(); - } - return html.replace(/<[^>]*>/g, '').trim(); -} - -/** - * Strip HTML and truncate to a maximum length, appending an ellipsis when - * the source exceeds it. Used for editorial story excerpts. - */ -export function plainExcerpt(html: string | null | undefined, max = 80): string { - const text = stripHtml(html); - if (text.length <= max) return text; - return text.slice(0, max).replace(/\s+\S*$/, '') + '…'; -} diff --git a/frontend/src/routes/geschichten/+page.svelte b/frontend/src/routes/geschichten/+page.svelte index d85aeab3..feb1f876 100644 --- a/frontend/src/routes/geschichten/+page.svelte +++ b/frontend/src/routes/geschichten/+page.svelte @@ -1,7 +1,7 @@ ' + ) + ], + 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('