diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 540943595fe..4a4262471b6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "18.20.3" + node-version: "22.22.0" cache: "npm" cache-dependency-path: | ui/ui-frontend/package-lock.json diff --git a/.github/workflows/i18n-check.yml b/.github/workflows/i18n-check.yml index 4389e83d353..be23693fd96 100644 --- a/.github/workflows/i18n-check.yml +++ b/.github/workflows/i18n-check.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "18.20.3" + node-version: "22.22.0" - name: Run i18n comparison script working-directory: tools run: node check-i18n.js diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6345a34300e..dca11fab54c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: '18.20.3' + node-version: '22.22.0' - name: Check missing icon in icomoon run: ./tools/check_icomoon.sh # Only install prettier globally (with same version as in package.json) diff --git a/.github/workflows/publish-design-system.yml b/.github/workflows/publish-design-system.yml index 57554144c44..8916ad24a8b 100644 --- a/.github/workflows/publish-design-system.yml +++ b/.github/workflows/publish-design-system.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "18.20.3" + node-version: "22.22.0" cache: "npm" cache-dependency-path: | ui/ui-frontend/package-lock.json diff --git a/Jenkinsfile b/Jenkinsfile index f21057ef597..8d489412307 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -93,7 +93,7 @@ pipeline { sh 'sudo apt install -y build-essential make ruby ruby-dev rubygems jq' sh 'sudo timedatectl set-timezone Europe/Paris' sh 'sudo gem install fpm' - nvm('v18.20.3') { // We're installing correct Node version through NVM then update the path to make it available. Do NOT wrap your code in `nvm('...') {}` as it would override the whole PATH and then break tools (jdk, maven) configurations + nvm('v22.22.0') { // We're installing correct Node version through NVM then update the path to make it available. Do NOT wrap your code in `nvm('...') {}` as it would override the whole PATH and then break tools (jdk, maven) configurations script { nvmPath = sh(script: 'dirname $(which node)', returnStdout: true).trim() env.PATH = "${nvmPath}:${env.PATH}" diff --git a/api/api-gateway/src/main/resources/application-dev.yml b/api/api-gateway/src/main/resources/application-dev.yml index 0fcaf0f1eb5..8385cde18ea 100644 --- a/api/api-gateway/src/main/resources/application-dev.yml +++ b/api/api-gateway/src/main/resources/application-dev.yml @@ -92,6 +92,7 @@ spring: /collect-api/users/analytics, /collect-api/logbooks/operations/**, /collect-api/accesscontracts/**, + /collect-api/discussions/**, /ingest-api/ui/applications/**, /ingest-api/externalparameters/**, @@ -146,6 +147,7 @@ spring: - RewritePath=/collect-api/userinfos(?.*),/iam/v1/userinfos$\{segment}, - RewritePath=/collect-api/users(?.*),/iam/v1/users$\{segment}, - RewritePath=/collect-api/subrogations/(?.*),/iam/v1/subrogations/$\{segment}, + - RewritePath=/collect-api/discussions(?.*),/iam/v1/discussions$\{segment}, - RewritePath=/collect-api/(?.*),/v1/$\{segment} # Ingest IAM API diff --git a/api/api-iam/iam/pom.xml b/api/api-iam/iam/pom.xml index d91123c6cdd..76921423da2 100644 --- a/api/api-iam/iam/pom.xml +++ b/api/api-iam/iam/pom.xml @@ -173,6 +173,10 @@ org.springframework.boot spring-boot-starter-data-mongodb + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + org.springframework.boot spring-boot-starter-security diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionReadRepository.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionReadRepository.java new file mode 100644 index 00000000000..9aa96d52c57 --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionReadRepository.java @@ -0,0 +1,18 @@ +package fr.gouv.vitamui.iam.server.discussion.dao; + +import fr.gouv.vitamui.commons.mongo.repository.VitamUIRepository; +import fr.gouv.vitamui.iam.server.discussion.domain.DiscussionRead; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** + * Repository for DiscussionRead. + */ +@Repository +public interface DiscussionReadRepository extends VitamUIRepository { + Optional findByUserIdAndDiscussionId(String userId, String discussionId); + + List findByUserIdAndDiscussionIdIn(String userId, List discussionIds); +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionRepository.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionRepository.java new file mode 100644 index 00000000000..f207ac52821 --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/dao/DiscussionRepository.java @@ -0,0 +1,15 @@ +package fr.gouv.vitamui.iam.server.discussion.dao; + +import fr.gouv.vitamui.commons.mongo.repository.VitamUIRepository; +import fr.gouv.vitamui.iam.server.discussion.domain.Discussion; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * Repository for Discussions. + */ +@Repository +public interface DiscussionRepository extends VitamUIRepository { + List findByEntitiesEntityIdAndEntitiesEntityType(String entityId, String entityType); +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/Discussion.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/Discussion.java new file mode 100644 index 00000000000..07cfbbfc4e4 --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/Discussion.java @@ -0,0 +1,55 @@ +package fr.gouv.vitamui.iam.server.discussion.domain; + +import fr.gouv.vitamui.commons.api.domain.BaseIdentifierDocument; +import fr.gouv.vitamui.commons.mongo.IdDocument; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +/** + * Discussion document. + */ +@Document(collection = "discussions") +@Getter +@Setter +@ToString +public class Discussion extends IdDocument implements BaseIdentifierDocument { + + private String identifier; // Using this as the 'id' for BaseIdentifierDocument compliance if needed, or + // mapped to internal logic + + private List entities = new ArrayList<>(); + + private String title; + + private String status; + + private Instant lastMessageAt; + + private List messages = new ArrayList<>(); + + @Getter + @Setter + @ToString + public static class EntityLink { + + private String entityId; + private String entityType; + } + + @Getter + @Setter + @ToString + public static class Message { + + private String id; + private String authorUserInfoId; + private String text; + private Instant createdAt; + } +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/DiscussionRead.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/DiscussionRead.java new file mode 100644 index 00000000000..8c05039f798 --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/domain/DiscussionRead.java @@ -0,0 +1,27 @@ +package fr.gouv.vitamui.iam.server.discussion.domain; + +import fr.gouv.vitamui.commons.mongo.IdDocument; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.springframework.data.mongodb.core.index.CompoundIndex; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.time.Instant; + +/** + * Discussion Read status document. + */ +@Document(collection = "discussions_read") +@CompoundIndex(def = "{'userId': 1, 'discussionId': 1}", unique = true) +@Getter +@Setter +@ToString +public class DiscussionRead extends IdDocument { + + private String userId; + + private String discussionId; + + private Instant lastReadAt; +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionController.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionController.java new file mode 100644 index 00000000000..abd308cd67c --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionController.java @@ -0,0 +1,99 @@ +package fr.gouv.vitamui.iam.server.discussion.rest; + +import fr.gouv.vitamui.iam.server.discussion.domain.Discussion; +import fr.gouv.vitamui.iam.server.discussion.service.DiscussionService; +import lombok.Getter; +import lombok.Setter; +import org.springframework.http.MediaType; +import org.springframework.http.codec.ServerSentEvent; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +import java.util.List; + +/** + * Controller for Discussion API. + */ +@RestController +@RequestMapping("/iam/v1/discussions") +public class DiscussionController { + + private final DiscussionService discussionService; + + public DiscussionController(DiscussionService discussionService) { + this.discussionService = discussionService; + } + + @GetMapping + public List findDiscussions(@RequestParam String entityId, @RequestParam String entityType) { + return discussionService.findDiscussions(entityId, entityType); + } + + @PostMapping + public Discussion createDiscussion(@RequestBody CreateDiscussionRequest request) { + return discussionService.createDiscussion(request.getTitle(), request.getEntities()); + } + + @PostMapping("/{discussionId}/messages") + public Discussion addMessage(@PathVariable String discussionId, @RequestBody AddMessageRequest request) { + return discussionService.addMessage(discussionId, request.getText()); + } + + @PutMapping("/{discussionId}/resolve") + public void resolveDiscussion(@PathVariable String discussionId) { + discussionService.resolveDiscussion(discussionId); + } + + @PutMapping("/{discussionId}/unresolve") + public void unresolveDiscussion(@PathVariable String discussionId) { + discussionService.unresolveDiscussion(discussionId); + } + + @PutMapping("/{discussionId}/read") + public void markAsRead(@PathVariable String discussionId) { + discussionService.markAsRead(discussionId); + } + + @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux> streamDiscussions( + @RequestParam(required = false) String entityId, + @RequestParam(required = false) String entityType + ) { + return discussionService + .getDiscussionChangeStream() + .filter(discussion -> { + if (entityId != null && entityType != null) { + return discussion + .getEntities() + .stream() + .anyMatch( + entity -> entityId.equals(entity.getEntityId()) && entityType.equals(entity.getEntityType()) + ); + } + return true; + }) + .map(discussion -> ServerSentEvent.builder(discussion).build()); + } + + @Getter + @Setter + public static class CreateDiscussionRequest { + + private String title; + private List entities; + } + + @Getter + @Setter + public static class AddMessageRequest { + + private String text; + } +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionDto.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionDto.java new file mode 100644 index 00000000000..d3c01a503bf --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/rest/DiscussionDto.java @@ -0,0 +1,37 @@ +package fr.gouv.vitamui.iam.server.discussion.rest; + +import fr.gouv.vitamui.iam.server.discussion.domain.Discussion; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import java.time.Instant; + +/** + * DTO for Discussion with Read Status. + */ +@Getter +@Setter +@ToString +public class DiscussionDto { + + private Discussion discussion; + private Instant lastReadAt; + private boolean isUnread; // Helper flag for UI + + public DiscussionDto(Discussion discussion, Instant lastReadAt) { + this.discussion = discussion; + this.lastReadAt = lastReadAt; + this.isUnread = calculateUnread(discussion, lastReadAt); + } + + private boolean calculateUnread(Discussion discussion, Instant lastReadAt) { + if (discussion.getLastMessageAt() == null) { + return false; + } + if (lastReadAt == null) { + return true; + } + return discussion.getLastMessageAt().isAfter(lastReadAt); + } +} diff --git a/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/service/DiscussionService.java b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/service/DiscussionService.java new file mode 100644 index 00000000000..5efbc893df4 --- /dev/null +++ b/api/api-iam/iam/src/main/java/fr/gouv/vitamui/iam/server/discussion/service/DiscussionService.java @@ -0,0 +1,133 @@ +package fr.gouv.vitamui.iam.server.discussion.service; + +import fr.gouv.vitamui.iam.security.service.SecurityService; +import fr.gouv.vitamui.iam.server.discussion.dao.DiscussionReadRepository; +import fr.gouv.vitamui.iam.server.discussion.dao.DiscussionRepository; +import fr.gouv.vitamui.iam.server.discussion.domain.Discussion; +import fr.gouv.vitamui.iam.server.discussion.domain.DiscussionRead; +import fr.gouv.vitamui.iam.server.discussion.rest.DiscussionDto; +import org.springframework.data.mongodb.core.ChangeStreamEvent; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Service for Discussion Management. + */ +@Service +public class DiscussionService { + + private final DiscussionRepository discussionRepository; + private final DiscussionReadRepository discussionReadRepository; + private final ReactiveMongoTemplate reactiveMongoTemplate; + private final SecurityService securityService; + + public DiscussionService( + DiscussionRepository discussionRepository, + DiscussionReadRepository discussionReadRepository, + ReactiveMongoTemplate reactiveMongoTemplate, + SecurityService securityService + ) { + this.discussionRepository = discussionRepository; + this.discussionReadRepository = discussionReadRepository; + this.reactiveMongoTemplate = reactiveMongoTemplate; + this.securityService = securityService; + } + + public Discussion createDiscussion(String title, List entities) { + Discussion discussion = new Discussion(); + discussion.setTitle(title); + discussion.setStatus("IN_PROGRESS"); + discussion.setEntities(entities); + discussion.setLastMessageAt(Instant.now()); + return discussionRepository.save(discussion); + } + + public Discussion addMessage(String discussionId, String text) { + Discussion discussion = discussionRepository + .findById(discussionId) + .orElseThrow(() -> new IllegalArgumentException("Discussion not found")); + + String authorUserInfoId = securityService.getUser().getUserInfoId(); + + Discussion.Message message = new Discussion.Message(); + message.setId(UUID.randomUUID().toString()); + message.setAuthorUserInfoId(authorUserInfoId); + message.setText(text); + message.setCreatedAt(Instant.now()); + + discussion.getMessages().add(message); + discussion.setLastMessageAt(message.getCreatedAt()); + + return discussionRepository.save(discussion); + } + + public void resolveDiscussion(String discussionId) { + Discussion discussion = discussionRepository + .findById(discussionId) + .orElseThrow(() -> new IllegalArgumentException("Discussion not found")); + discussion.setStatus("RESOLVED"); + discussionRepository.save(discussion); + } + + public void unresolveDiscussion(String discussionId) { + Discussion discussion = discussionRepository + .findById(discussionId) + .orElseThrow(() -> new IllegalArgumentException("Discussion not found")); + discussion.setStatus("IN_PROGRESS"); + discussionRepository.save(discussion); + } + + public List findDiscussions(String entityId, String entityType) { + List discussions = discussionRepository.findByEntitiesEntityIdAndEntitiesEntityType( + entityId, + entityType + ); + + List discussionIds = discussions.stream().map(Discussion::getId).collect(Collectors.toList()); + + String userId = securityService.getUser().getId(); + Map readStatusMap = discussionReadRepository + .findByUserIdAndDiscussionIdIn(userId, discussionIds) + .stream() + .collect(Collectors.toMap(DiscussionRead::getDiscussionId, Function.identity())); + + return discussions + .stream() + .map(discussion -> { + DiscussionRead read = readStatusMap.get(discussion.getId()); + Instant lastReadAt = read != null ? read.getLastReadAt() : null; + return new DiscussionDto(discussion, lastReadAt); + }) + .collect(Collectors.toList()); + } + + public void markAsRead(String discussionId) { + String userId = securityService.getUser().getId(); + DiscussionRead read = discussionReadRepository + .findByUserIdAndDiscussionId(userId, discussionId) + .orElseGet(() -> { + DiscussionRead newRead = new DiscussionRead(); + newRead.setUserId(userId); + newRead.setDiscussionId(discussionId); + return newRead; + }); + read.setLastReadAt(Instant.now()); + discussionReadRepository.save(read); + } + + public Flux getDiscussionChangeStream() { + return reactiveMongoTemplate + .changeStream(Discussion.class) + .watchCollection("discussions") + .listen() + .mapNotNull(ChangeStreamEvent::getBody); + } +} diff --git a/pom.xml b/pom.xml index e5f00dcf5fe..1282101ba2d 100644 --- a/pom.xml +++ b/pom.xml @@ -76,8 +76,8 @@ 9.1.0-SNAPSHOT - v18.20.3 - 10.7.0 + v22.22.0 + 10.9.4 diff --git a/ui/ui-frontend/package-lock.json b/ui/ui-frontend/package-lock.json index 220470960ba..2c1b6fbccd9 100644 --- a/ui/ui-frontend/package-lock.json +++ b/ui/ui-frontend/package-lock.json @@ -28,6 +28,7 @@ "colors": "1.4.0", "d3": "^7.9.0", "dompurify": "3.2.4", + "eventsource": "4.1.0", "fast-xml-parser": "^5.3.4", "file-saver-es": "^2.0.5", "jszip": "^3.10.1", @@ -62,11 +63,9 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.32.0", "@types/d3": "^7.4.3", - "@types/dompurify": "3.2.0", "@types/file-saver-es": "^2.0.3", "@types/jasmine": "~5.1.4", "@types/jasminewd2": "^2.0.8", - "@types/jszip": "^3.4.1", "@types/lodash-es": "^4.17.12", "@types/luxon": "3.7.1", "@types/node": "^12.11.1", @@ -113,13 +112,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1902.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.19.tgz", - "integrity": "sha512-iexYDIYpGAeAU7T60bGcfrGwtq1bxpZixYxWuHYiaD1b5baQgNSfd1isGEOh37GgDNsf4In9i2LOLPm0wBdtgQ==", + "version": "0.1902.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1902.20.tgz", + "integrity": "sha512-tEM8PX9RTIvgEPJH/9nDaGlhbjZf9BBFS2FXKuOwKB+NFvfZuuDpPH7CzJKyyvkQLPtoNh2Y9C92m2f+RXsBmQ==", "devOptional": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", + "@angular-devkit/core": "19.2.20", "rxjs": "7.8.1" }, "engines": { @@ -139,17 +138,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.19.tgz", - "integrity": "sha512-uIxi6Vzss6+ycljVhkyPUPWa20w8qxJL9lEn0h6+sX/fhM8Djt0FHIuTQjoX58EoMaQ/1jrXaRaGimkbaFcG9A==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.20.tgz", + "integrity": "sha512-m7J+k0lJEFvr6STGUQROx6TyoGn0WQsQiooO8WTkM8QUWKxSUmq4WImlPSq6y+thc+Jzx1EBw3yn73+phNIZag==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1902.19", - "@angular-devkit/build-webpack": "0.1902.19", - "@angular-devkit/core": "19.2.19", - "@angular/build": "19.2.19", + "@angular-devkit/architect": "0.1902.20", + "@angular-devkit/build-webpack": "0.1902.20", + "@angular-devkit/core": "19.2.20", + "@angular/build": "19.2.20", "@babel/core": "7.26.10", "@babel/generator": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", @@ -160,7 +159,7 @@ "@babel/preset-env": "7.26.9", "@babel/runtime": "7.26.10", "@discoveryjs/json-ext": "0.6.3", - "@ngtools/webpack": "19.2.19", + "@ngtools/webpack": "19.2.20", "@vitejs/plugin-basic-ssl": "1.2.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -195,7 +194,7 @@ "terser": "5.39.0", "tree-kill": "1.2.2", "tslib": "2.8.1", - "webpack": "5.98.0", + "webpack": "5.105.0", "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.2.2", "webpack-merge": "6.0.1", @@ -214,7 +213,7 @@ "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", - "@angular/ssr": "^19.2.19", + "@angular/ssr": "^19.2.20", "@web/test-runner": "^0.20.0", "browser-sync": "^3.0.2", "jest": "^29.5.0", @@ -276,7 +275,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { "version": "4.57.1", @@ -290,7 +290,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.57.1", @@ -304,7 +305,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { "version": "4.57.1", @@ -318,7 +320,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.57.1", @@ -332,7 +335,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-freebsd-x64": { "version": "4.57.1", @@ -346,7 +350,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.57.1", @@ -360,7 +365,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.57.1", @@ -374,7 +380,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.57.1", @@ -388,7 +395,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.57.1", @@ -402,7 +410,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.57.1", @@ -416,7 +425,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.57.1", @@ -430,7 +440,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.57.1", @@ -444,7 +455,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.57.1", @@ -458,7 +470,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.57.1", @@ -472,7 +485,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.57.1", @@ -486,7 +500,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.57.1", @@ -500,12 +515,13 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, "license": "MIT", "optional": true, @@ -533,6 +549,7 @@ "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -588,6 +605,7 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -677,6 +695,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -687,13 +706,13 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1902.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.19.tgz", - "integrity": "sha512-x2tlGg5CsUveFzuRuqeHknSbGirSAoRynEh+KqPRGK0G3WpMViW/M8SuVurecasegfIrDWtYZ4FnVxKqNbKwXQ==", + "version": "0.1902.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1902.20.tgz", + "integrity": "sha512-T8RLKZOR0+l3FBMBTUQk83I/Dr5RpNPCOE6tWqGjAMRPKoL1m5BbqhkQ7ygnyd8/ZRz/x1RUVM08l0AeuzWUmA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1902.19", + "@angular-devkit/architect": "0.1902.20", "rxjs": "7.8.1" }, "engines": { @@ -717,9 +736,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.19.tgz", - "integrity": "sha512-JbLL+4IMLMBgjLZlnPG4lYDfz4zGrJ/s6Aoon321NJKuw1Kb1k5KpFu9dUY0BqLIe8xPQ2UJBpI+xXdK5MXMHQ==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.20.tgz", + "integrity": "sha512-4AAmHlv+H1/2Nmsp6QsX8YQxjC/v5QAzc+76He7K/x3iIuLCntQE2BYxonSZMiQ3M8gc/yxTfyZoPYjSDDvWMA==", "license": "MIT", "dependencies": { "ajv": "8.17.1", @@ -753,12 +772,12 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.19.tgz", - "integrity": "sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.20.tgz", + "integrity": "sha512-o2eexF1fLZU93V3utiQLNgyNaGvFhDqpITNQcI1qzv2ZkvFHg9WZjFtZKtm805JAE/DND8oAJ1p+BoxU++Qg8g==", "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", + "@angular-devkit/core": "19.2.20", "jsonc-parser": "3.3.1", "magic-string": "0.30.17", "ora": "5.4.1", @@ -887,7 +906,6 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-19.2.18.tgz", "integrity": "sha512-c76x1t+OiSstPsvJdHmV8Q4taF+8SxWKqiY750fOjpd01it4jJbU6YQqIroC6Xie7154zZIxOTHH2uTj+nm5qA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -900,14 +918,14 @@ } }, "node_modules/@angular/build": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.19.tgz", - "integrity": "sha512-SFzQ1bRkNFiOVu+aaz+9INmts7tDUrsHLEr9HmARXr9qk5UmR8prlw39p2u+Bvi6/lCiJ18TZMQQl9mGyr63lg==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-19.2.20.tgz", + "integrity": "sha512-8bQ1afN8AJ6N9lJJgxYF08M0gp4R/4SIedSJfSLohscgHumYJ1mITEygoB1JK5O9CEKlr4YyLYfgay8xr92wbQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1902.19", + "@angular-devkit/architect": "0.1902.20", "@babel/core": "7.26.10", "@babel/helper-annotate-as-pure": "7.25.9", "@babel/helper-split-export-declaration": "7.24.7", @@ -947,7 +965,7 @@ "@angular/localize": "^19.0.0 || ^19.2.0-next.0", "@angular/platform-server": "^19.0.0 || ^19.2.0-next.0", "@angular/service-worker": "^19.0.0 || ^19.2.0-next.0", - "@angular/ssr": "^19.2.19", + "@angular/ssr": "^19.2.20", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^19.0.0 || ^19.2.0-next.0", @@ -1292,9 +1310,9 @@ ] }, "node_modules/@angular/build/node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, "license": "MIT", "optional": true, @@ -1540,7 +1558,6 @@ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.19.tgz", "integrity": "sha512-PCpJagurPBqciqcq4Z8+3OtKLb7rSl4w/qBJoIMua8CgnrjvA1i+SWawhdtfI1zlY8FSwhzLwXV0CmWWfFzQPg==", "license": "MIT", - "peer": true, "dependencies": { "parse5": "^7.1.2", "tslib": "^2.3.0" @@ -1552,19 +1569,18 @@ } }, "node_modules/@angular/cli": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-19.2.19.tgz", - "integrity": "sha512-e9tAzFNOL4mMWfMnpC9Up83OCTOp2siIj8W41FCp8jfoEnw79AXDDLh3d70kOayiObchksTJVShslTogLUyhMw==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-19.2.20.tgz", + "integrity": "sha512-3vw49xDGqOi63FES/6D+Lw0Sl42FSZKowUxBMY0CnXD8L93Qwvcf4ASFmUoNJRSTOJuuife1+55vY62cpOWBdg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { - "@angular-devkit/architect": "0.1902.19", - "@angular-devkit/core": "19.2.19", - "@angular-devkit/schematics": "19.2.19", + "@angular-devkit/architect": "0.1902.20", + "@angular-devkit/core": "19.2.20", + "@angular-devkit/schematics": "19.2.20", "@inquirer/prompts": "7.3.2", "@listr2/prompt-adapter-inquirer": "2.0.18", - "@schematics/angular": "19.2.19", + "@schematics/angular": "19.2.20", "@yarnpkg/lockfile": "1.1.0", "ini": "5.0.0", "jsonc-parser": "3.3.1", @@ -1802,7 +1818,6 @@ "integrity": "sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.1.2", "@inquirer/confirm": "^5.1.6", @@ -1957,9 +1972,9 @@ } }, "node_modules/@angular/cli/node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, "license": "MIT", "optional": true, @@ -2060,7 +2075,6 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.18.tgz", "integrity": "sha512-CrV02Omzw/QtfjlEVXVPJVXipdx83NuA+qSASZYrxrhKFusUZyK3P/Zznqg+wiAeNDbedQwMUVqoAARHf0xQrw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2077,7 +2091,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-19.2.18.tgz", "integrity": "sha512-3MscvODxRVxc3Cs0ZlHI5Pk5rEvE80otfvxZTMksOZuPlv1B+S8MjWfc3X3jk9SbyUEzODBEH55iCaBHD48V3g==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2091,7 +2104,6 @@ "integrity": "sha512-N4TMtLfImJIoMaRL6mx7885UBeQidywptHH6ACZj71Ar6++DBc1mMlcwuvbeJCd3r3y8MQ5nLv5PZSN/tHr13w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.26.9", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -2168,7 +2180,6 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.2.18.tgz", "integrity": "sha512-+QRrf0Igt8ccUWXHA+7doK5W6ODyhHdqVyblSlcQ8OciwkzIIGGEYNZom5OZyWMh+oI54lcSeyV2O3xaDepSrQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2185,7 +2196,6 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-19.2.18.tgz", "integrity": "sha512-pe40934jWhoS7DyGl7jyZdoj1gvBgur2t1zrJD+csEkTitYnW14+La2Pv6SW1pNX5nIzFsgsS9Nex1KcH5S6Tw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2231,7 +2241,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.2.18.tgz", "integrity": "sha512-eahtsHPyXTYLARs9YOlXhnXGgzw0wcyOcDkBvNWK/3lA0NHIgIHmQgXAmBo+cJ+g9skiEQTD2OmSrrwbFKWJkw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2268,13 +2277,13 @@ } }, "node_modules/@angular/pwa": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-19.2.19.tgz", - "integrity": "sha512-H6yjDmArLZDoq5w7vL6Z33ZYxD1FE/LD7wHTPwRxm0+XTFQGeXbWGp25WZMlWHwmxcsxqyQTcfK9CXtfVpeKKg==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@angular/pwa/-/pwa-19.2.20.tgz", + "integrity": "sha512-HNntCM1BtHVmOG7+sarSfKOxqDiB/JWtWPKCOw8tQ/4W55FoJYua0m9v9hXT4F4nhKoSpLow+ogvPdlnEu1Zmw==", "license": "MIT", "dependencies": { - "@angular-devkit/schematics": "19.2.19", - "@schematics/angular": "19.2.19", + "@angular-devkit/schematics": "19.2.20", + "@schematics/angular": "19.2.20", "parse5-html-rewriting-stream": "7.0.0" }, "engines": { @@ -2283,7 +2292,7 @@ "yarn": ">= 1.13.0" }, "peerDependencies": { - "@angular/cli": "^19.2.19" + "@angular/cli": "^19.2.20" }, "peerDependenciesMeta": { "@angular/cli": { @@ -2314,7 +2323,6 @@ "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-19.2.18.tgz", "integrity": "sha512-nNXrYeDIBt4t8g8RWBU11t5oyjbnccvoWC6suA71Tb51v4L1yqs+tmaFlnhaJ0jBSXB8zPHA0HQBNo9wPs+LVw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2360,7 +2368,6 @@ "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -4847,9 +4854,9 @@ } }, "node_modules/@jsonjoy.com/buffers": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.65.0.tgz", - "integrity": "sha512-eBrIXd0/Ld3p9lpDDlMaMn6IEfWqtHMD+z61u0JrIiPzsV1r7m6xDZFRxJyvIFTEO+SWdYF9EiQbXZGd8BzPfA==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5055,9 +5062,9 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.65.0.tgz", - "integrity": "sha512-Xrh7Fm/M0QAYpekSgmskdZYnFdSGnsxJ/tHaolA4bNwWdG9i65S8m83Meh7FOxyJyQAdo4d4J97NOomBLEfkDQ==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5072,9 +5079,9 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.65.0.tgz", - "integrity": "sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5089,17 +5096,17 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.65.0.tgz", - "integrity": "sha512-e0SG/6qUCnVhHa0rjDJHgnXnbsacooHVqQHxspjvlYQSkHm+66wkHw6Gql+3u/WxI/b1VsOdUi0M+fOtkgKGdQ==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/base64": "17.65.0", - "@jsonjoy.com/buffers": "17.65.0", - "@jsonjoy.com/codegen": "17.65.0", - "@jsonjoy.com/json-pointer": "17.65.0", - "@jsonjoy.com/util": "17.65.0", + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" @@ -5116,13 +5123,13 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.65.0.tgz", - "integrity": "sha512-uhTe+XhlIZpWOxgPcnO+iSCDgKKBpwkDVTyYiXX9VayGV8HSFVJM67M6pUE71zdnXF1W0Da21AvnhlmdwYPpow==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/util": "17.65.0" + "@jsonjoy.com/util": "17.67.0" }, "engines": { "node": ">=10.0" @@ -5136,14 +5143,14 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { - "version": "17.65.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.65.0.tgz", - "integrity": "sha512-cWiEHZccQORf96q2y6zU3wDeIVPeidmGqd9cNKJRYoVHTV0S1eHPy5JTbHpMnGfDvtvujQwQozOqgO9ABu6h0w==", + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/buffers": "17.65.0", - "@jsonjoy.com/codegen": "17.65.0" + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" }, "engines": { "node": ">=10.0" @@ -5758,9 +5765,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.19.tgz", - "integrity": "sha512-R9aeTrOBiRVl8I698JWPniUAAEpSvzc8SUGWSM5UXWMcHnWqd92cOnJJ1aXDGJZKXrbhMhCBx9Dglmcks5IDpg==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.20.tgz", + "integrity": "sha512-nuCjcxLmFrn0s53G67V5R19mUpYjewZBLz6Wrg7BtJkjq08xfO0QgaJg3e6wzEmj1AclH7eMKRnuQhm5otyutg==", "dev": true, "license": "MIT", "engines": { @@ -5779,7 +5786,6 @@ "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-16.0.4.tgz", "integrity": "sha512-s8llTL2SJvROhqttxvEs7Cg+6qSf4kvZPFYO+cTOY1d8DWTjlutRkWAleZcPPoeX927Dm7ALfL07G7oYDJ7z6w==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -5897,13 +5903,13 @@ } }, "node_modules/@npmcli/git/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "devOptional": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { @@ -5989,13 +5995,13 @@ } }, "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "devOptional": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/promise-spawn/node_modules/which": { @@ -6043,13 +6049,13 @@ } }, "node_modules/@npmcli/run-script/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "devOptional": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@npmcli/run-script/node_modules/which": { @@ -6868,13 +6874,13 @@ } }, "node_modules/@schematics/angular": { - "version": "19.2.19", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-19.2.19.tgz", - "integrity": "sha512-6/0pvbPCY4UHeB4lnM/5r250QX5gcLgOYbR5FdhFu+22mOPHfWpRc5tNuY9kCephDHzAHjo6fTW1vefOOmA4jw==", + "version": "19.2.20", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-19.2.20.tgz", + "integrity": "sha512-xDrYxZvk9dGA2eVqufqLYmVSMSXxVtv30pBHGGU/2xr4QzHzdmMHflk4It8eh4WMNLhn7kqnzMREwtNI3eW/Gw==", "license": "MIT", "dependencies": { - "@angular-devkit/core": "19.2.19", - "@angular-devkit/schematics": "19.2.19", + "@angular-devkit/core": "19.2.20", + "@angular-devkit/schematics": "19.2.20", "jsonc-parser": "3.3.1" }, "engines": { @@ -7393,17 +7399,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/dompurify": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz", - "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==", - "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "dompurify": "*" - } - }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -7524,17 +7519,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jszip": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@types/jszip/-/jszip-3.4.1.tgz", - "integrity": "sha512-TezXjmf3lj+zQ651r6hPqvSScqBLvyPI9FxdXBqpEwBijNGQ2NXpaFW/7joGzveYkKQUil7iiDHLo6LV71Pc0A==", - "deprecated": "This is a stub types definition. jszip provides its own type definitions, so you do not need this installed.", - "dev": true, - "license": "MIT", - "dependencies": { - "jszip": "*" - } - }, "node_modules/@types/lodash": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", @@ -7696,17 +7680,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", - "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", + "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/type-utils": "8.54.0", - "@typescript-eslint/utils": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/type-utils": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" @@ -7719,15 +7703,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.54.0", - "eslint": "^8.57.0 || ^9.0.0", + "@typescript-eslint/parser": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -7739,16 +7723,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7758,7 +7742,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, @@ -7773,17 +7757,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", - "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", + "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", "debug": "^4.4.3" }, "engines": { @@ -7794,14 +7777,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -7813,14 +7796,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", - "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.54.0", - "@typescript-eslint/types": "^8.54.0", + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", "debug": "^4.4.3" }, "engines": { @@ -7835,9 +7818,9 @@ } }, "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -7849,14 +7832,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", - "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0" + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7867,9 +7850,9 @@ } }, "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -7881,9 +7864,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", - "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", "dev": true, "license": "MIT", "engines": { @@ -7898,15 +7881,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", - "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", + "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0", - "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/utils": "8.56.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, @@ -7918,14 +7901,14 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -7937,16 +7920,16 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", - "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/typescript-estree": "8.54.0" + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7956,7 +7939,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, @@ -7966,7 +7949,6 @@ "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7976,16 +7958,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", - "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.54.0", - "@typescript-eslint/tsconfig-utils": "8.54.0", - "@typescript-eslint/types": "8.54.0", - "@typescript-eslint/visitor-keys": "8.54.0", + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", @@ -8004,9 +7986,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -8044,9 +8026,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -8062,7 +8044,6 @@ "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.26.0", @@ -8184,14 +8165,14 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", - "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.54.0", - "eslint-visitor-keys": "^4.2.1" + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -8202,9 +8183,9 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", - "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", "dev": true, "license": "MIT", "engines": { @@ -8216,13 +8197,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -8479,7 +8460,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8487,6 +8467,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -8541,7 +8534,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -8774,14 +8766,14 @@ } }, "node_modules/axios": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", - "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -9111,7 +9103,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -9225,9 +9216,9 @@ "license": "ISC" }, "node_modules/cacache/node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", + "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==", "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -9293,9 +9284,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001768", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001768.tgz", - "integrity": "sha512-qY3aDRZC5nWPgHUgIB84WL+nySuo19wk0VJpp/XI9T34lrvkyhRvNVOFJOp2kxClQhiFBu+TaUSudf6oa3vkSA==", + "version": "1.0.30001770", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz", + "integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==", "dev": true, "funding": [ { @@ -9354,7 +9345,6 @@ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -10362,7 +10352,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -10927,9 +10916,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -11127,7 +11116,6 @@ "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -11371,6 +11359,27 @@ "node": ">=0.8.x" } }, + "node_modules/eventsource": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-4.1.0.tgz", + "integrity": "sha512-2GuF51iuHX6A9xdTccMTsNb7VO0lHZihApxhvQzJB5A03DvHDd2FQepodbMaztPBmBcE/ox7o2gqaxGhYB9LhQ==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -11579,9 +11588,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-parser": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.4.tgz", - "integrity": "sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==", + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", + "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", "funding": [ { "type": "github", @@ -11590,7 +11599,7 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.1.0" + "strnum": "^2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" @@ -11966,9 +11975,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "devOptional": true, "license": "MIT", "engines": { @@ -12924,9 +12933,9 @@ "license": "MIT" }, "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "dev": true, "license": "MIT", "dependencies": { @@ -13090,8 +13099,7 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.6.0.tgz", "integrity": "sha512-niVlkeYVRwKFpmfWg6suo6H9CrNnydfBLEqefM5UjibYS+UoTjZdmvPJSiuyrRLGnFj1eYRhFd/ch+5hSlsFVA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jasmine-marbles": { "version": "0.9.2", @@ -13137,7 +13145,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -13313,7 +13320,6 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -13835,9 +13841,9 @@ } }, "node_modules/launch-editor": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", - "integrity": "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.0.tgz", + "integrity": "sha512-u+9asUHMJ99lA15VRMXw5XKfySFR9dGXwgsgS14YTbUq3GITP58mIM32At90P5fZ+MUId5Yw+IwI/yKub7jnCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13851,7 +13857,6 @@ "integrity": "sha512-tkuLHQlvWUTeQ3doAqnHbNn8T6WX1KA8yvbKG9x4VtKtIjHsVKQZCH11zRgAfbDAXC2UNIg/K9BYAAcEzUIrNg==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -14997,7 +15002,6 @@ "integrity": "sha512-dFuwFsDJMBSd1YtmLLcX5bNNUCQUlRqgf34aXA+79PmkOP+0eF8GP2949wq3+jMjmFTNm80Oo8IUYiSLwklKCQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rollup/plugin-json": "^6.1.0", "@rollup/wasm-node": "^4.24.0", @@ -15309,19 +15313,19 @@ } }, "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "devOptional": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/node-gyp/node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", + "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==", "devOptional": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -16276,7 +16280,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", @@ -16522,9 +16525,9 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -17013,7 +17016,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -17068,7 +17070,6 @@ "integrity": "sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -18214,7 +18215,6 @@ "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -18424,8 +18424,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tuf-js": { "version": "3.1.0", @@ -18482,7 +18481,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18530,7 +18528,8 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -18818,36 +18817,37 @@ "optional": true }, "node_modules/webpack": { - "version": "5.98.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", - "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "version": "5.105.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", + "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^4.3.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.11", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -19068,9 +19068,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", "dev": true, "license": "MIT", "engines": { @@ -19130,6 +19130,20 @@ "dev": true, "license": "MIT" }, + "node_modules/webpack/node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -19355,7 +19369,6 @@ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -19480,8 +19493,7 @@ "version": "0.15.1", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", - "license": "MIT", - "peer": true + "license": "MIT" } } } diff --git a/ui/ui-frontend/package.json b/ui/ui-frontend/package.json index 653ad44ff9e..d6e0f9d544d 100644 --- a/ui/ui-frontend/package.json +++ b/ui/ui-frontend/package.json @@ -105,6 +105,7 @@ "colors": "1.4.0", "d3": "^7.9.0", "dompurify": "3.2.4", + "eventsource": "4.1.0", "fast-xml-parser": "^5.3.4", "file-saver-es": "^2.0.5", "jszip": "^3.10.1", @@ -139,11 +140,9 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.32.0", "@types/d3": "^7.4.3", - "@types/dompurify": "3.2.0", "@types/file-saver-es": "^2.0.3", "@types/jasmine": "~5.1.4", "@types/jasminewd2": "^2.0.8", - "@types/jszip": "^3.4.1", "@types/lodash-es": "^4.17.12", "@types/luxon": "3.7.1", "@types/node": "^12.11.1", diff --git a/ui/ui-frontend/projects/collect/src/app/collect/archive-search-collect/archive-search-collect.component.html b/ui/ui-frontend/projects/collect/src/app/collect/archive-search-collect/archive-search-collect.component.html index de64018f8dc..3eaf7332bb2 100644 --- a/ui/ui-frontend/projects/collect/src/app/collect/archive-search-collect/archive-search-collect.component.html +++ b/ui/ui-frontend/projects/collect/src/app/collect/archive-search-collect/archive-search-collect.component.html @@ -51,10 +51,14 @@
{{ 'APPLICATION.COLLECT_APP.NAME' | translate }} : {{ projectName }}
+ +
+
+
+
{{ discussion().title }}
+@for (message of discussion().messages; track message.id) { + @if (displayNewMessageSeparator(message)) { +
New messages
+ } +
+
{{ message.authorUserInfoId }}
+
{{ message.text }}
+
{{ message.createdAt | date: 'dd/MM/yyyy à HH:mm:ss' }}
+
+} + + diff --git a/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.scss b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.scss new file mode 100644 index 00000000000..b96384902e3 --- /dev/null +++ b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.scss @@ -0,0 +1,21 @@ +.message { + border: 1px solid black; + border-radius: 10px; + margin: 5px 50px 5px 0; + background-color: var(--vitamui-secondary-100); + + &.mine { + margin-left: 50px; + margin-right: 0; + background-color: var(--vitamui-primary-100); + } + + .date { + text-align: right; + } +} + +.new-message-separator { + border-top: 1px solid var(--vitamui-red); + text-align: center; +} diff --git a/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.ts b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.ts new file mode 100644 index 00000000000..265b44e7522 --- /dev/null +++ b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussion/discussion.component.ts @@ -0,0 +1,69 @@ +/* + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2022) + * and the signatories of the "VITAM - Accord du Contributeur" agreement. + * + * contact@programmevitam.fr + * + * This software is a computer program whose purpose is to implement + * implement a digital archiving front-office system for the secure and + * efficient high volumetry VITAM solution. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +import { Component, inject, input, output } from '@angular/core'; +import { Discussion, DiscussionService, Message } from '../discussion.service'; +import { DatePipe } from '@angular/common'; +import { AuthService } from 'vitamui-library'; + +@Component({ + selector: 'app-discussion', + imports: [DatePipe], + templateUrl: './discussion.component.html', + styleUrl: './discussion.component.scss', +}) +export class DiscussionComponent { + discussion = input.required(); + lastReadAt = input(); + closeDiscussion = output(); + + private discussionService = inject(DiscussionService); + + me = inject(AuthService).userInfo; + + addMessage(message: string) { + this.discussionService.addMessage(this.discussion(), message); + } + + displayNewMessageSeparator(message: Message): boolean { + const messageDate = new Date(message.createdAt).getTime(); + const lastReadDate = new Date(this.lastReadAt() || 0).getTime(); + const messages = this.discussion().messages; + const messageIndex = messages.indexOf(message); + const first = messageIndex === 0; + return messageDate > lastReadDate && (first || new Date(messages[messageIndex - 1].createdAt).getTime() < lastReadDate); + } +} diff --git a/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.html b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.html new file mode 100644 index 00000000000..fb5201bfd1a --- /dev/null +++ b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.html @@ -0,0 +1,21 @@ +@if (currentDiscussion()) { + +} @else { +

Discussions

+ @for (discussion of discussions(); track discussion.discussion.id) { +
+
{{ discussion.discussion.title }}
+
{{ discussion.discussion.messages?.at(discussion.discussion.messages?.length - 1)?.text }}
+
+ } +

New discussion

+ + +} diff --git a/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.scss b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.scss new file mode 100644 index 00000000000..a320f5a8588 --- /dev/null +++ b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.scss @@ -0,0 +1,6 @@ +.discussion { + background-color: var(--vitamui-tertiary-100); + &.read { + background-color: var(--vitamui-primary-100); + } +} diff --git a/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.ts b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.ts new file mode 100644 index 00000000000..6b04794a27a --- /dev/null +++ b/ui/ui-frontend/projects/collect/src/app/collect/discussions/discussions.component.ts @@ -0,0 +1,89 @@ +/* + * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2019-2022) + * and the signatories of the "VITAM - Accord du Contributeur" agreement. + * + * contact@programmevitam.fr + * + * This software is a computer program whose purpose is to implement + * implement a digital archiving front-office system for the secure and + * efficient high volumetry VITAM solution. + * + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. + */ +import { Component, computed, inject, input, Signal, signal } from '@angular/core'; +import { DiscussionDto, DiscussionEntity, DiscussionService } from './discussion.service'; +import { toObservable, toSignal } from '@angular/core/rxjs-interop'; +import { filter } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { FormsModule } from '@angular/forms'; +import { DiscussionComponent } from './discussion/discussion.component'; + +@Component({ + selector: 'app-discussions', + imports: [FormsModule, DiscussionComponent], + templateUrl: './discussions.component.html', + styleUrl: './discussions.component.scss', +}) +export class DiscussionsComponent { + discussionEntity = input.required(); + discussions: Signal = toSignal( + toObservable(this.discussionEntity).pipe( + filter((entity) => !!entity), + switchMap((entity) => this.discussionService.findDiscussions(entity)), + map((discussions) => + discussions.sort((d1, d2) => new Date(d2.discussion.lastMessageAt).getTime() - new Date(d1.discussion.lastMessageAt).getTime()), + ), + ), + { initialValue: [] as DiscussionDto[] }, + ); + private readonly selectedDiscussionId = signal(null); + readonly currentDiscussion = computed(() => { + const id = this.selectedDiscussionId(); + const list = this.discussions(); + + if (!id || !list.length) return null; + return list.find((d) => d.discussion.id === id)?.discussion ?? null; + }); + currentDiscussionLastReadAt: Date; + + private discussionService = inject(DiscussionService); + + async createDiscussion(title: string) { + const discussion = await this.discussionService.createDiscussion(this.discussionEntity(), title); + this.openDiscussion({ discussion, lastReadAt: undefined, unread: true }); + } + + protected openDiscussion(discussion: DiscussionDto) { + this.selectedDiscussionId.set(discussion.discussion.id); + this.currentDiscussionLastReadAt = discussion.lastReadAt; + this.discussionService.markAsRead(discussion); + } + + protected closeDiscussion() { + this.selectedDiscussionId.set(null); + } +}