From b26b5ecc9c24aa7a7ce1a2459c114213ebe28745 Mon Sep 17 00:00:00 2001 From: Thomas Peetz Date: Thu, 29 Jan 2026 23:50:41 +0100 Subject: [PATCH] Vorbereitung Release 0.2.0 --- .gitignore | 18 +- Makefile | 9 +- compose-couchdb.yaml | 22 + compose-postgres.yaml | 38 + docker-compose.yml | 183 +- kontor-angular/.dockerignore | 3 + kontor-angular/.gitignore | 42 + kontor-angular/Dockerfile | 14 + kontor-angular/Makefile | 8 + kontor-angular/README.md | 59 + kontor-angular/angular.json | 95 + kontor-angular/nginx.conf | 37 + kontor-angular/package-lock.json | 9970 +++++++++++++++++ kontor-angular/package.json | 48 + kontor-angular/public/cross.png | Bin 0 -> 544 bytes kontor-angular/public/favicon.ico | Bin 0 -> 15086 bytes kontor-angular/public/logo.png | Bin 0 -> 17196 bytes kontor-angular/public/tick.png | Bin 0 -> 634 bytes kontor-angular/src/app/app.component.css | 9 + kontor-angular/src/app/app.component.html | 10 + kontor-angular/src/app/app.component.ts | 14 + kontor-angular/src/app/app.config.ts | 13 + kontor-angular/src/app/app.routes.ts | 26 + kontor-angular/src/app/app.spec.ts | 23 + .../src/app/common/auth/auth-service.spec.ts | 16 + .../src/app/common/auth/auth-service.ts | 55 + kontor-angular/src/app/common/auth/auth.css | 8 + kontor-angular/src/app/common/auth/auth.html | 34 + .../src/app/common/auth/auth.spec.ts | 23 + kontor-angular/src/app/common/auth/auth.ts | 55 + .../comic-artist/comic-artist.component.css | 5 + .../comic-artist/comic-artist.component.html | 5 + .../comic-artist.component.spec.ts | 23 + .../comic-artist/comic-artist.component.ts | 13 + .../comic-artists-list.component.css | 14 + .../comic-artists-list.component.html | 7 + .../comic-artists-list.component.spec.ts | 23 + .../comic-artists-list.component.ts | 38 + .../comic/comic-artists/artist.service.ts | 47 + .../comic-artists/comic-artists.component.css | 16 + .../comic-artists.component.html | 35 + .../comic-artists.component.spec.ts | 23 + .../comic-artists/comic-artists.component.ts | 25 + .../comic-comic/comic-comic.component.css | 0 .../comic-comic/comic-comic.component.html | 5 + .../comic-comic/comic-comic.component.spec.ts | 23 + .../comic-comic/comic-comic.component.ts | 13 + .../comic-comics-list.component.css | 14 + .../comic-comics-list.component.html | 10 + .../comic-comics-list.component.spec.ts | 23 + .../comic-comics-list.component.ts | 46 + .../comic-comics/comic-comics.component.css | 29 + .../comic-comics/comic-comics.component.html | 32 + .../comic-comics.component.spec.ts | 23 + .../comic-comics/comic-comics.component.ts | 27 + .../comic/comic-comics/comic.service.ts | 45 + .../comic-issue/comic-issue.component.css | 0 .../comic-issue/comic-issue.component.html | 5 + .../comic-issue/comic-issue.component.spec.ts | 23 + .../comic-issue/comic-issue.component.ts | 13 + .../comic-navigation.component.css | 0 .../comic-navigation.component.html | 5 + .../comic-navigation.component.spec.ts | 23 + .../comic-navigation.component.ts | 12 + .../comic-publisher.component.css | 0 .../comic-publisher.component.html | 5 + .../comic-publisher.component.spec.ts | 23 + .../comic-publisher.component.ts | 13 + .../comic-publishers-list.component.css | 14 + .../comic-publishers-list.component.html | 7 + .../comic-publishers-list.component.spec.ts | 23 + .../comic-publishers-list.component.ts | 37 + .../comic-publishers.component.css | 0 .../comic-publishers.component.html | 31 + .../comic-publishers.component.spec.ts | 23 + .../comic-publishers.component.ts | 25 + .../comic-publishers/publisher.service.ts | 47 + .../comic-section/comic-section.component.css | 0 .../comic-section.component.html | 2 + .../comic-section.component.spec.ts | 23 + .../comic-section/comic-section.component.ts | 13 + .../comic-section/comic-section.routes.ts | 40 + .../comic-worktype.component.css | 0 .../comic-worktype.component.html | 5 + .../comic-worktype.component.spec.ts | 23 + .../comic-worktype.component.ts | 13 + .../src/app/kontor/comic/comic.model.ts | 81 + .../app/kontor/footer/footer.component.css | 12 + .../app/kontor/footer/footer.component.html | 5 + .../kontor/footer/footer.component.spec.ts | 23 + .../src/app/kontor/footer/footer.component.ts | 12 + .../app/kontor/header/header.component.css | 11 + .../app/kontor/header/header.component.html | 5 + .../kontor/header/header.component.spec.ts | 23 + .../src/app/kontor/header/header.component.ts | 12 + .../src/app/kontor/kontor.component.css | 0 .../src/app/kontor/kontor.component.html | 1 + .../src/app/kontor/kontor.component.spec.ts | 23 + .../src/app/kontor/kontor.component.ts | 11 + .../media-actors/media-actors.component.css | 0 .../media-actors/media-actors.component.html | 1 + .../media-actors.component.spec.ts | 23 + .../media-actors/media-actors.component.ts | 11 + .../media/media-file/media-file.component.css | 0 .../media-file/media-file.component.html | 17 + .../media-file/media-file.component.spec.ts | 23 + .../media/media-file/media-file.component.ts | 13 + .../media-files-list.component.css | 14 + .../media-files-list.component.html | 7 + .../media-files-list.component.spec.ts | 23 + .../media-files-list.component.ts | 37 + .../media/media-files/media-file.model.ts | 11 + .../media/media-files/media-file.service.ts | 30 + .../media-files/media-files.component.css | 5 + .../media-files/media-files.component.html | 7 + .../media-files/media-files.component.spec.ts | 23 + .../media-files/media-files.component.ts | 12 + .../media-navigation.component.css | 0 .../media-navigation.component.html | 5 + .../media-navigation.component.spec.ts | 23 + .../media-navigation.component.ts | 12 + .../media-section/media-section.component.css | 0 .../media-section.component.html | 2 + .../media-section.component.spec.ts | 23 + .../media-section/media-section.component.ts | 13 + .../media-section/media-section.routes.ts | 31 + .../media-videos/media-videos.component.css | 0 .../media-videos/media-videos.component.html | 1 + .../media-videos.component.spec.ts | 23 + .../media-videos/media-videos.component.ts | 11 + .../navigation/navigation.component.css | 0 .../navigation/navigation.component.html | 7 + .../navigation/navigation.component.spec.ts | 23 + .../kontor/navigation/navigation.component.ts | 12 + .../tysc-cardsets/tysc-cardsets.component.css | 0 .../tysc-cardsets.component.html | 1 + .../tysc-cardsets.component.spec.ts | 23 + .../tysc-cardsets/tysc-cardsets.component.ts | 11 + .../tysc-navigation.component.css | 0 .../tysc-navigation.component.html | 7 + .../tysc-navigation.component.spec.ts | 23 + .../tysc-navigation.component.ts | 12 + .../tysc-players/tysc-players.component.css | 0 .../tysc-players/tysc-players.component.html | 1 + .../tysc-players.component.spec.ts | 23 + .../tysc-players/tysc-players.component.ts | 11 + .../tysc-positions.component.css | 0 .../tysc-positions.component.html | 1 + .../tysc-positions.component.spec.ts | 23 + .../tysc-positions.component.ts | 11 + .../tysc-section/tysc-section.component.css | 0 .../tysc-section/tysc-section.component.html | 3 + .../tysc-section.component.spec.ts | 23 + .../tysc-section/tysc-section.component.ts | 14 + .../tysc/tysc-section/tysc-section.routes.ts | 29 + .../kontor/tysc/tysc-sports/sport.model.ts | 4 + .../kontor/tysc/tysc-sports/sport.service.ts | 30 + .../tysc-sports/tysc-sports.component.css | 0 .../tysc-sports/tysc-sports.component.html | 9 + .../tysc-sports/tysc-sports.component.spec.ts | 23 + .../tysc/tysc-sports/tysc-sports.component.ts | 37 + .../tysc/tysc-team/tysc-team.component.css | 0 .../tysc/tysc-team/tysc-team.component.html | 1 + .../tysc-team/tysc-team.component.spec.ts | 23 + .../tysc/tysc-team/tysc-team.component.ts | 11 + .../tysc/tysc-teams/tysc-teams.component.css | 0 .../tysc/tysc-teams/tysc-teams.component.html | 1 + .../tysc-teams/tysc-teams.component.spec.ts | 23 + .../tysc/tysc-teams/tysc-teams.component.ts | 11 + .../tysc-vendors/tysc-vendors.component.css | 0 .../tysc-vendors/tysc-vendors.component.html | 1 + .../tysc-vendors.component.spec.ts | 23 + .../tysc-vendors/tysc-vendors.component.ts | 11 + .../src/app/shared/error.service.ts | 19 + .../shared/loading-spinner/loading-spinner.ts | 11 + .../loading-spinner/loading.spinner.css | 41 + kontor-angular/src/index.html | 13 + kontor-angular/src/main.ts | 6 + kontor-angular/src/styles.css | 95 + kontor-angular/tsconfig.app.json | 15 + kontor-angular/tsconfig.json | 34 + kontor-angular/tsconfig.spec.json | 14 + kontor-api/.coverage | Bin 53248 -> 0 bytes kontor-api/.gitignore | 3 + kontor-api/Dockerfile | 8 +- kontor-api/Makefile | 6 +- kontor-api/pyproject.toml | 11 +- kontor-api/src/apis/base.py | 7 +- kontor-api/src/apis/utils.py | 8 - kontor-api/src/apis/version1/admin.py | 52 + kontor-api/src/apis/version1/comic.py | 73 +- kontor-api/src/apis/version1/healthcheck.py | 25 + kontor-api/src/apis/version1/login.py | 41 + kontor-api/src/apis/version1/media.py | 76 - kontor-api/src/apis/version1/mediaactor.py | 48 + .../src/apis/version1/mediaactorfile.py | 33 + kontor-api/src/apis/version1/mediafile.py | 120 + kontor-api/src/apis/version1/tysc.py | 8 +- kontor-api/src/core/config.py | 18 +- kontor-api/src/core/log_conf.py | 49 + kontor-api/src/core/security.py | 156 + kontor-api/src/db/models/admin.py | 44 +- kontor-api/src/db/models/base.py | 21 +- kontor-api/src/db/models/bookshelf.py | 12 +- kontor-api/src/db/models/comic.py | 106 +- kontor-api/src/db/models/database.py | 13 +- kontor-api/src/db/models/media.py | 66 +- kontor-api/src/db/models/metadata.py | 42 - kontor-api/src/db/models/tysc.py | 25 +- kontor-api/src/db/repository/__init__.py | 0 kontor-api/src/db/repository/admin.py | 10 + .../src/db/repository/comics/__init__.py | 0 kontor-api/src/db/repository/comics/artist.py | 46 + kontor-api/src/db/repository/comics/comic.py | 87 + .../src/db/repository/comics/publisher.py | 24 + .../src/db/repository/comics/worktype.py | 32 + kontor-api/src/db/repository/media.py | 86 + kontor-api/src/db/session.py | 4 + kontor-api/src/db/utils.py | 30 + kontor-api/src/main.py | 45 +- kontor-api/src/schema/admin.py | 27 + kontor-api/src/schema/comics/artist.py | 30 +- .../src/schema/comics/artist_details.py | 22 + kontor-api/src/schema/comics/comic.py | 59 +- kontor-api/src/schema/comics/comic_details.py | 26 + kontor-api/src/schema/comics/issue.py | 8 + kontor-api/src/schema/comics/issue_details.py | 13 + kontor-api/src/schema/comics/publisher.py | 6 + .../src/schema/comics/publisher_details.py | 14 + kontor-api/src/schema/comics/volume.py | 6 + kontor-api/src/schema/comics/worktype.py | 9 + kontor-api/src/schema/media/actor.py | 18 + kontor-api/src/schema/media/actorfile.py | 16 + kontor-api/src/schema/media/file.py | 25 +- kontor-api/src/schema/media/video.py | 5 + kontor-api/src/schema/tysc/sport.py | 4 +- kontor-api/src/static/style.css | 172 + .../src/templates/admin/permissions.html | 38 + kontor-api/src/templates/admin/profiles.html | 43 + kontor-api/src/templates/auth/login.html | 40 + .../{components => comic}/artist_cards.html | 1 + .../src/templates/comic/artist_detail.html | 18 +- .../src/templates/comic/artist_edit.html | 32 + kontor-api/src/templates/comic/artists.html | 2 +- .../{components => comic}/comic_cards.html | 0 .../src/templates/comic/comic_detail.html | 47 +- .../src/templates/comic/comic_edit.html | 56 + kontor-api/src/templates/comic/comics.html | 64 +- .../src/templates/comic/issue_detail.html | 92 + .../publisher_cards.html | 0 .../src/templates/comic/publisher_detail.html | 25 + .../src/templates/comic/publishers.html | 2 +- .../src/templates/comic/worktype_detail.html | 60 + .../src/templates/comic/worktype_edit.html | 28 + kontor-api/src/templates/comic/worktypes.html | 28 + .../src/templates/components/check.html | 2 +- .../src/templates/components/footer.html | 1 + .../src/templates/components/navbar.html | 28 +- kontor-api/src/templates/index.html | 3 + .../{components => media}/actor_cards.html | 0 .../src/templates/media/actor_detail.html | 11 + kontor-api/src/templates/media/actors.html | 2 +- .../src/templates/media/add_video_link.html | 29 + .../src/templates/media/file_detail.html | 7 + kontor-api/src/templates/media/files.html | 62 +- kontor-api/src/templates/media/media_nav.html | 5 + .../src/templates/media/video_detail.html | 55 + kontor-api/src/templates/media/videos.html | 29 + kontor-api/src/templates/shared/base.html | 89 +- kontor-api/src/webapps/admin/__init__.py | 0 kontor-api/src/webapps/admin/route_admin.py | 29 + kontor-api/src/webapps/auth/__init__.py | 0 kontor-api/src/webapps/auth/forms.py | 27 + kontor-api/src/webapps/auth/route_login.py | 36 + kontor-api/src/webapps/base.py | 14 +- .../src/webapps/comic/forms/__init__.py | 0 kontor-api/src/webapps/comic/forms/artist.py | 26 + kontor-api/src/webapps/comic/forms/comic.py | 27 + .../src/webapps/comic/forms/worktype.py | 20 + kontor-api/src/webapps/comic/route_artists.py | 59 + kontor-api/src/webapps/comic/route_comics.py | 84 +- .../src/webapps/comic/route_worktype.py | 73 + kontor-api/src/webapps/media/forms.py | 20 + kontor-api/src/webapps/media/route_actors.py | 21 + kontor-api/src/webapps/media/route_media.py | 60 +- kontor-api/src/webapps/media/route_videos.py | 51 + kontor-api/tests/conftest.py | 75 + kontor-api/tests/test_main.py | 12 +- kontor-api/uv.lock | 333 +- kontor-echo/Dockerfile | 28 + kontor-echo/cmd/kontor/main.go | 54 + kontor-echo/go.mod | 39 + kontor-echo/go.sum | 68 + kontor-echo/pkg/handler/auth.go | 78 + kontor-echo/pkg/handler/comics.go | 81 + kontor-echo/pkg/handler/health.go | 17 + kontor-echo/pkg/handler/media.go | 67 + kontor-echo/pkg/schema/auth.go | 62 + kontor-echo/pkg/schema/comics.go | 140 + kontor-echo/pkg/schema/comics_test.go | 100 + kontor-echo/pkg/schema/database.go | 31 + kontor-echo/pkg/schema/media.go | 79 + kontor-echo/pkg/schema/tysc.go | 116 + kontor-echo/pkg/schema/tysc_test.go | 155 + kontor-echo/pkg/utils/auth.go | 8 + kontor-echo/pkg/utils/token.go | 38 + kontor-fiber/Dockerfile | 28 + kontor-fiber/cmd/kontor/main.go | 41 + kontor-fiber/go.mod | 42 + kontor-fiber/go.sum | 98 + kontor-fiber/pkg/handler/auth.go | 47 + kontor-fiber/pkg/handler/comics.go | 77 + kontor-fiber/pkg/handler/health.go | 9 + kontor-fiber/pkg/handler/media.go | 64 + kontor-fiber/pkg/schema/auth.go | 62 + kontor-fiber/pkg/schema/comics.go | 140 + kontor-fiber/pkg/schema/comics_test.go | 101 + kontor-fiber/pkg/schema/database.go | 50 + kontor-fiber/pkg/schema/media.go | 79 + kontor-fiber/pkg/utils/auth.go | 8 + kontor-fiber/pkg/utils/token.go | 38 + kontor-javalin/.gitignore | 33 + kontor-javalin/Dockerfile | 25 + kontor-javalin/Makefile | 8 + kontor-javalin/README.md | 3 + kontor-javalin/build.gradle | 44 + kontor-javalin/gradle.properties | 3 + kontor-javalin/gradle/libs.versions.toml | 40 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 45633 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + kontor-javalin/gradlew | 248 + kontor-javalin/gradlew.bat | 93 + kontor-javalin/settings.gradle | 1 + .../src/main/java/de/thpeetz/kontor/Main.java | 89 + .../kontor/infrastructure/AppHibernate.java | 17 + .../infrastructure/AppHibernateConfig.java | 54 + .../AppHibernateSessionFactory.java | 33 + .../thpeetz/kontor/models/comics/Artist.java | 52 + .../thpeetz/kontor/models/comics/Comic.java | 93 + .../kontor/models/comics/ComicQueries.java | 12 + .../kontor/models/comics/ComicWork.java | 53 + .../thpeetz/kontor/models/comics/Issue.java | 126 + .../kontor/models/comics/IssueWork.java | 57 + .../kontor/models/comics/Publisher.java | 77 + .../kontor/models/comics/StoryArc.java | 59 + .../kontor/models/comics/TradePaperback.java | 48 + .../thpeetz/kontor/models/comics/Volume.java | 69 + .../kontor/models/comics/Worktype.java | 53 + .../kontor/models/media/MediaActor.java | 51 + .../kontor/models/media/MediaActorFile.java | 56 + .../kontor/models/media/MediaArticle.java | 46 + .../kontor/models/media/MediaFile.java | 71 + .../kontor/models/media/MediaFileQueries.java | 11 + .../kontor/models/media/MediaVideo.java | 57 + .../de/thpeetz/kontor/web/ComicHandler.java | 17 + .../thpeetz/kontor/web/MediaFileHandler.java | 29 + .../kontor/web/model/NewMediaFile.java | 4 + .../thpeetz/kontor/web/model/ResultComic.java | 8 + .../kontor/web/model/ResultMediaFile.java | 9 + kontor-quarkus/.dockerignore | 9 + kontor-quarkus/.gitignore | 42 + kontor-quarkus/Dockerfile | 37 + kontor-quarkus/README.md | 67 + kontor-quarkus/build.gradle.kts | 57 + kontor-quarkus/gradle.properties | 7 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 62076 bytes .../gradle/wrapper/gradle-wrapper.properties | 8 + kontor-quarkus/gradlew | 245 + kontor-quarkus/gradlew.bat | 92 + kontor-quarkus/settings.gradle.kts | 13 + kontor-quarkus/src/main/docker/Dockerfile.jvm | 98 + .../src/main/docker/Dockerfile.legacy-jar | 94 + .../src/main/docker/Dockerfile.native | 29 + .../src/main/docker/Dockerfile.native-micro | 32 + .../kotlin/de/thpeetz/GreetingResource.kt | 14 + .../de/thpeetz/kontor/KontorApplication.kt | 14 + .../de/thpeetz/kontor/comics/domain/Comic.kt | 25 + .../kontor/comics/resource/ComicsResource.kt | 22 + .../src/main/resources/application.properties | 23 + .../kotlin/de/thpeetz/GreetingResourceIT.kt | 6 + .../kotlin/de/thpeetz/GreetingResourceTest.kt | 20 + kontor-schema/pyproject.toml | 2 +- kontor-schema/uv.lock | 118 +- kontor-scripts/add_actors.py | 369 + kontor-scripts/add_link.py | 81 + kontor-scripts/add_links.py | 216 + kontor-scripts/config.py | 136 +- kontor-scripts/db/__init__.py | 0 kontor-scripts/db/models/__init__.py | 84 + kontor-scripts/db/models/admin.py | 205 + kontor-scripts/{schema => db/models}/base.py | 21 +- kontor-scripts/db/models/bookshelf.py | 159 + kontor-scripts/db/models/comic.py | 352 + kontor-scripts/db/models/database.py | 66 + kontor-scripts/db/models/media.py | 224 + kontor-scripts/db/models/tysc.py | 259 + kontor-scripts/db/repository/__init__.py | 0 kontor-scripts/download.py | 140 +- kontor-scripts/export.py | 58 +- kontor-scripts/find_links.py | 332 + kontor-scripts/import.py | 186 +- kontor-scripts/json_to_postgres.py | 152 + kontor-scripts/kontor.py | 64 + kontor-scripts/pyproject.toml | 8 +- kontor-scripts/read_list.py | 89 +- kontor-scripts/read_queue.py | 37 + kontor-scripts/requirements.txt | 1 - kontor-scripts/schema/admin.py | 78 - kontor-scripts/schema/bookshelf.py | 50 - kontor-scripts/schema/comic.py | 100 - kontor-scripts/schema/database.py | 399 - kontor-scripts/schema/media.py | 99 - kontor-scripts/schema/metadata.py | 42 - kontor-scripts/schema/tysc.py | 100 - kontor-scripts/update_title.py | 35 +- kontor-scripts/uv.lock | 198 +- kontor-servicemix/Dockerfile | 20 + kontor-servicemix/Makefile | 5 + kontor-spring/Dockerfile | 26 +- kontor-spring/build.gradle | 14 +- kontor-spring/gradle.properties | 2 +- kontor-spring/gradle/libs.versions.toml | 6 + .../thpeetz/kontor/admin/AdminConstants.java | 9 +- .../kontor/admin/SetupModuleAdmin.java | 320 +- .../kontor/admin/data/MetaDataColumn.java | 69 - .../kontor/admin/data/MetaDataTable.java | 40 - .../thpeetz/kontor/admin/data/ModuleData.java | 25 - .../repository/MetaDataColumnRepository.java | 18 - .../repository/MetaDataTableRepository.java | 9 - .../repository/ModuleDataRepository.java | 16 - .../services/KontorUserDetailsService.java | 10 +- .../admin/services/MetaDataService.java | 243 - .../kontor/admin/services/ModuleService.java | 76 - .../kontor/admin/views/MetaDataForm.java | 123 - .../kontor/admin/views/MetaDataView.java | 193 - .../kontor/admin/views/ModuleDataForm.java | 100 - .../kontor/admin/views/ModuleDataView.java | 140 - .../bookshelf/SetupModuleBookshelf.java | 36 - .../thpeetz/kontor/comics/ComicConstants.java | 8 + .../kontor/comics/SetupModuleComics.java | 1156 +- .../de/thpeetz/kontor/comics/data/Artist.java | 7 +- .../de/thpeetz/kontor/comics/data/Comic.java | 6 +- .../kontor/comics/data/ComicRepository.java | 19 - .../de/thpeetz/kontor/comics/data/Issue.java | 76 +- .../thpeetz/kontor/comics/data/IssueWork.java | 48 + .../thpeetz/kontor/comics/data/Publisher.java | 29 +- .../thpeetz/kontor/comics/data/StoryArc.java | 19 +- .../de/thpeetz/kontor/comics/data/Volume.java | 19 +- .../thpeetz/kontor/comics/data/Worktype.java | 5 +- .../ArtistRepository.java | 3 +- .../comics/repository/ComicRepository.java | 39 + .../ComicWorkRepository.java | 3 +- .../{data => repository}/IssueRepository.java | 3 +- .../repository/IssueWorkRepository.java | 15 + .../PublisherRepository.java | 3 +- .../StoryArcRepository.java | 3 +- .../TradePaperbackRepository.java | 3 +- .../VolumeRepository.java | 3 +- .../WorktypeRepository.java | 3 +- .../kontor/comics/services/ComicService.java | 102 +- .../kontor/comics/views/ArtistForm.java | 10 +- .../kontor/comics/views/ComicForm.java | 10 +- .../kontor/comics/views/ComicView.java | 28 +- .../kontor/comics/views/IssueForm.java | 53 +- .../kontor/comics/views/IssueView.java | 17 +- .../kontor/comics/views/IssueWorkForm.java | 115 + .../kontor/comics/views/IssueWorkView.java | 118 + .../kontor/comics/views/PublisherForm.java | 18 +- .../kontor/comics/views/PublisherView.java | 48 +- .../kontor/comics/views/WorktypeView.java | 13 +- .../kontor/common/views/ComicIssueField.java | 63 + .../kontor/common/views/FilterOption.java | 21 + .../kontor/common/views/KontorLayoutUtil.java | 10 +- .../kontor/common/views/SearchFilter.java | 36 + .../common/views/SearchFilterField.java | 57 + .../common/views/SeparateMainLayout.java | 6 - .../kontor/common/views/YearMonthField.java | 54 + .../data/services/DataManagementService.java | 13 - .../integration/routes/AddLinkFromQueue.java | 28 + .../integration/routes/ReadQueueRoute.java | 16 + .../services/AddLinkProcessor.java | 45 + .../integration/services/AddLinkService.java | 22 + .../kontor/media/SetupModuleMedia.java | 10 - .../thpeetz/kontor/media/data/MediaActor.java | 3 + .../thpeetz/kontor/media/data/MediaFile.java | 1 - .../media/data/MediaFileRepository.java | 14 - .../MediaActorFileRepository.java | 4 +- .../MediaActorRepository.java | 4 +- .../MediaArticleRepository.java | 4 +- .../media/repository/MediaFileRepository.java | 31 + .../MediaVideoRepository.java | 4 +- .../media/services/MediaArticleService.java | 2 +- .../media/services/MediaFileService.java | 60 +- .../media/services/MediaVideoService.java | 2 +- .../kontor/media/views/MediaActorForm.java | 3 +- .../kontor/media/views/MediaActorView.java | 27 +- .../kontor/media/views/MediaFileView.java | 25 +- .../kontor/security/SecurityConfig.java | 7 +- .../thpeetz/kontor/tysc/SetupModuleTysc.java | 428 - .../de/thpeetz/kontor/tysc/data/CardSet.java | 4 + .../de/thpeetz/kontor/tysc/data/Rooster.java | 10 +- .../de/thpeetz/kontor/tysc/data/Vendor.java | 13 +- .../kontor/tysc/services/SportService.java | 7 +- .../kontor/tysc/views/CardSetView.java | 79 +- .../thpeetz/kontor/tysc/views/CardView.java | 4 +- .../src/main/resources/application.yml | 52 +- .../src/main/resources/logback-spring.xml | 2 +- .../de/thpeetz/kontor/ApplicationTests.java | 21 +- .../kontor/comics/data/ArtistTest.java | 1 + .../thpeetz/kontor/comics/data/ComicTest.java | 4 +- .../thpeetz/kontor/comics/data/IssueTest.java | 1 + .../kontor/comics/data/PublisherTest.java | 1 + .../kontor/comics/data/StoryArcTest.java | 3 +- .../comics/data/TradePaperbackTest.java | 1 + .../kontor/comics/data/VolumeTest.java | 3 +- .../kontor/comics/data/WorktypeTest.java | 2 +- .../ArtistRepositoryTest.java | 3 +- .../ComicRepositoryTest.java | 3 +- .../ComicWorkRepositoryTest.java | 3 +- .../IssueRepositoryTest.java | 3 +- .../PublisherRepositoryTest.java | 3 +- .../StoryArcRepositoryTest.java | 3 +- .../TradePaperbackRepositoryTest.java | 3 +- .../VolumeRepositoryTest.java | 3 +- .../WorktypeRepositoryTest.java | 9 +- .../kontor/media/data/MediaArticleTest.java | 1 + .../kontor/media/data/MediaFileTest.java | 2 + .../kontor/media/data/MediaVideoTest.java | 2 + .../media/services/MediaFileServiceTest.java | 5 +- kontor-vue/.dockerignore | 4 + kontor-vue/.gitattributes | 1 + kontor-vue/.gitignore | 26 + kontor-vue/.prettierrc.json | 6 + kontor-vue/Dockerfile | 14 + kontor-vue/README.md | 56 + kontor-vue/babel.config.js | 5 + kontor-vue/cypress.config.ts | 8 + kontor-vue/cypress/e2e/example.cy.ts | 8 + kontor-vue/cypress/fixtures/example.json | 5 + kontor-vue/cypress/support/commands.ts | 39 + kontor-vue/cypress/support/e2e.ts | 20 + kontor-vue/cypress/tsconfig.json | 9 + kontor-vue/env.d.ts | 1 + kontor-vue/eslint.config.ts | 39 + kontor-vue/index.html | 13 + kontor-vue/jsconfig.json | 19 + kontor-vue/package-lock.json | 8985 +++++++++++++++ kontor-vue/package.json | 53 + kontor-vue/public/favicon.ico | Bin 0 -> 4286 bytes kontor-vue/public/index.html | 17 + kontor-vue/src/App.vue | 43 + kontor-vue/src/assets/base.css | 51 + kontor-vue/src/assets/logo.png | Bin 0 -> 6849 bytes kontor-vue/src/assets/logo.svg | 1 + kontor-vue/src/assets/main.css | 209 + kontor-vue/src/components/MainHeader.vue | 12 + kontor-vue/src/components/MainNavbar.vue | 14 + .../components/__tests__/MainHeader.spec.ts | 11 + kontor-vue/src/main.js | 4 + kontor-vue/src/main.ts | 14 + kontor-vue/src/router/index.ts | 26 + kontor-vue/src/stores/counter.ts | 12 + kontor-vue/src/views/ComicsView.vue | 13 + kontor-vue/src/views/HomeView.vue | 8 + kontor-vue/tsconfig.app.json | 12 + kontor-vue/tsconfig.json | 17 + kontor-vue/tsconfig.node.json | 19 + kontor-vue/tsconfig.vitest.json | 11 + kontor-vue/vite.config.ts | 20 + kontor-vue/vitest.config.ts | 14 + kontor-vue/vue.config.js | 4 + 571 files changed, 35728 insertions(+), 5022 deletions(-) create mode 100644 compose-couchdb.yaml create mode 100644 compose-postgres.yaml create mode 100644 kontor-angular/.dockerignore create mode 100644 kontor-angular/.gitignore create mode 100644 kontor-angular/Dockerfile create mode 100644 kontor-angular/Makefile create mode 100644 kontor-angular/README.md create mode 100644 kontor-angular/angular.json create mode 100644 kontor-angular/nginx.conf create mode 100644 kontor-angular/package-lock.json create mode 100644 kontor-angular/package.json create mode 100644 kontor-angular/public/cross.png create mode 100644 kontor-angular/public/favicon.ico create mode 100644 kontor-angular/public/logo.png create mode 100644 kontor-angular/public/tick.png create mode 100644 kontor-angular/src/app/app.component.css create mode 100644 kontor-angular/src/app/app.component.html create mode 100644 kontor-angular/src/app/app.component.ts create mode 100644 kontor-angular/src/app/app.config.ts create mode 100644 kontor-angular/src/app/app.routes.ts create mode 100644 kontor-angular/src/app/app.spec.ts create mode 100644 kontor-angular/src/app/common/auth/auth-service.spec.ts create mode 100644 kontor-angular/src/app/common/auth/auth-service.ts create mode 100644 kontor-angular/src/app/common/auth/auth.css create mode 100644 kontor-angular/src/app/common/auth/auth.html create mode 100644 kontor-angular/src/app/common/auth/auth.spec.ts create mode 100644 kontor-angular/src/app/common/auth/auth.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists/artist.service.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.ts rename kontor-scripts/schema/__init__.py => kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.css (100%) create mode 100644 kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-comics/comic.service.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.css create mode 100644 kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.html create mode 100644 kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.ts create mode 100644 kontor-angular/src/app/kontor/comic/comic.model.ts create mode 100644 kontor-angular/src/app/kontor/footer/footer.component.css create mode 100644 kontor-angular/src/app/kontor/footer/footer.component.html create mode 100644 kontor-angular/src/app/kontor/footer/footer.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/footer/footer.component.ts create mode 100644 kontor-angular/src/app/kontor/header/header.component.css create mode 100644 kontor-angular/src/app/kontor/header/header.component.html create mode 100644 kontor-angular/src/app/kontor/header/header.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/header/header.component.ts create mode 100644 kontor-angular/src/app/kontor/kontor.component.css create mode 100644 kontor-angular/src/app/kontor/kontor.component.html create mode 100644 kontor-angular/src/app/kontor/kontor.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/kontor.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-actors/media-actors.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-actors/media-actors.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-actors/media-actors.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-actors/media-actors.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-file/media-file.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-file/media-file.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-file/media-file.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-file/media-file.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-file.model.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-file.service.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-files.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-files.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-files.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-files/media-files.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-section/media-section.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-section/media-section.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-section/media-section.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-section/media-section.component.ts create mode 100644 kontor-angular/src/app/kontor/media/media-section/media-section.routes.ts create mode 100644 kontor-angular/src/app/kontor/media/media-videos/media-videos.component.css create mode 100644 kontor-angular/src/app/kontor/media/media-videos/media-videos.component.html create mode 100644 kontor-angular/src/app/kontor/media/media-videos/media-videos.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/media/media-videos/media-videos.component.ts create mode 100644 kontor-angular/src/app/kontor/navigation/navigation.component.css create mode 100644 kontor-angular/src/app/kontor/navigation/navigation.component.html create mode 100644 kontor-angular/src/app/kontor/navigation/navigation.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/navigation/navigation.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.routes.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/sport.model.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/sport.service.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.css create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.html create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.spec.ts create mode 100644 kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.ts create mode 100644 kontor-angular/src/app/shared/error.service.ts create mode 100644 kontor-angular/src/app/shared/loading-spinner/loading-spinner.ts create mode 100644 kontor-angular/src/app/shared/loading-spinner/loading.spinner.css create mode 100644 kontor-angular/src/index.html create mode 100644 kontor-angular/src/main.ts create mode 100644 kontor-angular/src/styles.css create mode 100644 kontor-angular/tsconfig.app.json create mode 100644 kontor-angular/tsconfig.json create mode 100644 kontor-angular/tsconfig.spec.json delete mode 100644 kontor-api/.coverage delete mode 100644 kontor-api/src/apis/utils.py create mode 100644 kontor-api/src/apis/version1/admin.py create mode 100644 kontor-api/src/apis/version1/healthcheck.py create mode 100644 kontor-api/src/apis/version1/login.py delete mode 100644 kontor-api/src/apis/version1/media.py create mode 100644 kontor-api/src/apis/version1/mediaactor.py create mode 100644 kontor-api/src/apis/version1/mediaactorfile.py create mode 100644 kontor-api/src/apis/version1/mediafile.py create mode 100644 kontor-api/src/core/log_conf.py create mode 100644 kontor-api/src/core/security.py delete mode 100644 kontor-api/src/db/models/metadata.py create mode 100644 kontor-api/src/db/repository/__init__.py create mode 100644 kontor-api/src/db/repository/admin.py create mode 100644 kontor-api/src/db/repository/comics/__init__.py create mode 100644 kontor-api/src/db/repository/comics/artist.py create mode 100644 kontor-api/src/db/repository/comics/comic.py create mode 100644 kontor-api/src/db/repository/comics/publisher.py create mode 100644 kontor-api/src/db/repository/comics/worktype.py create mode 100644 kontor-api/src/db/repository/media.py create mode 100644 kontor-api/src/db/utils.py create mode 100644 kontor-api/src/schema/admin.py create mode 100644 kontor-api/src/schema/comics/artist_details.py create mode 100644 kontor-api/src/schema/comics/comic_details.py create mode 100644 kontor-api/src/schema/comics/issue.py create mode 100644 kontor-api/src/schema/comics/issue_details.py create mode 100644 kontor-api/src/schema/comics/publisher.py create mode 100644 kontor-api/src/schema/comics/publisher_details.py create mode 100644 kontor-api/src/schema/comics/volume.py create mode 100644 kontor-api/src/schema/comics/worktype.py create mode 100644 kontor-api/src/schema/media/actor.py create mode 100644 kontor-api/src/schema/media/actorfile.py create mode 100644 kontor-api/src/schema/media/video.py create mode 100644 kontor-api/src/static/style.css create mode 100644 kontor-api/src/templates/admin/permissions.html create mode 100644 kontor-api/src/templates/admin/profiles.html create mode 100644 kontor-api/src/templates/auth/login.html rename kontor-api/src/templates/{components => comic}/artist_cards.html (82%) create mode 100644 kontor-api/src/templates/comic/artist_edit.html rename kontor-api/src/templates/{components => comic}/comic_cards.html (100%) create mode 100644 kontor-api/src/templates/comic/comic_edit.html create mode 100644 kontor-api/src/templates/comic/issue_detail.html rename kontor-api/src/templates/{components => comic}/publisher_cards.html (100%) create mode 100644 kontor-api/src/templates/comic/worktype_detail.html create mode 100644 kontor-api/src/templates/comic/worktype_edit.html create mode 100644 kontor-api/src/templates/comic/worktypes.html create mode 100644 kontor-api/src/templates/components/footer.html rename kontor-api/src/templates/{components => media}/actor_cards.html (100%) create mode 100644 kontor-api/src/templates/media/add_video_link.html create mode 100644 kontor-api/src/templates/media/media_nav.html create mode 100644 kontor-api/src/templates/media/video_detail.html create mode 100644 kontor-api/src/templates/media/videos.html create mode 100644 kontor-api/src/webapps/admin/__init__.py create mode 100644 kontor-api/src/webapps/admin/route_admin.py create mode 100644 kontor-api/src/webapps/auth/__init__.py create mode 100644 kontor-api/src/webapps/auth/forms.py create mode 100644 kontor-api/src/webapps/auth/route_login.py create mode 100644 kontor-api/src/webapps/comic/forms/__init__.py create mode 100644 kontor-api/src/webapps/comic/forms/artist.py create mode 100644 kontor-api/src/webapps/comic/forms/comic.py create mode 100644 kontor-api/src/webapps/comic/forms/worktype.py create mode 100644 kontor-api/src/webapps/comic/route_artists.py create mode 100644 kontor-api/src/webapps/comic/route_worktype.py create mode 100644 kontor-api/src/webapps/media/forms.py create mode 100644 kontor-api/src/webapps/media/route_actors.py create mode 100644 kontor-api/src/webapps/media/route_videos.py create mode 100644 kontor-api/tests/conftest.py create mode 100644 kontor-echo/Dockerfile create mode 100644 kontor-echo/cmd/kontor/main.go create mode 100644 kontor-echo/go.mod create mode 100644 kontor-echo/go.sum create mode 100644 kontor-echo/pkg/handler/auth.go create mode 100644 kontor-echo/pkg/handler/comics.go create mode 100644 kontor-echo/pkg/handler/health.go create mode 100644 kontor-echo/pkg/handler/media.go create mode 100644 kontor-echo/pkg/schema/auth.go create mode 100644 kontor-echo/pkg/schema/comics.go create mode 100644 kontor-echo/pkg/schema/comics_test.go create mode 100644 kontor-echo/pkg/schema/database.go create mode 100644 kontor-echo/pkg/schema/media.go create mode 100644 kontor-echo/pkg/schema/tysc.go create mode 100644 kontor-echo/pkg/schema/tysc_test.go create mode 100644 kontor-echo/pkg/utils/auth.go create mode 100644 kontor-echo/pkg/utils/token.go create mode 100644 kontor-fiber/Dockerfile create mode 100644 kontor-fiber/cmd/kontor/main.go create mode 100644 kontor-fiber/go.mod create mode 100644 kontor-fiber/go.sum create mode 100644 kontor-fiber/pkg/handler/auth.go create mode 100644 kontor-fiber/pkg/handler/comics.go create mode 100644 kontor-fiber/pkg/handler/health.go create mode 100644 kontor-fiber/pkg/handler/media.go create mode 100644 kontor-fiber/pkg/schema/auth.go create mode 100644 kontor-fiber/pkg/schema/comics.go create mode 100644 kontor-fiber/pkg/schema/comics_test.go create mode 100644 kontor-fiber/pkg/schema/database.go create mode 100644 kontor-fiber/pkg/schema/media.go create mode 100644 kontor-fiber/pkg/utils/auth.go create mode 100644 kontor-fiber/pkg/utils/token.go create mode 100644 kontor-javalin/.gitignore create mode 100644 kontor-javalin/Dockerfile create mode 100644 kontor-javalin/Makefile create mode 100644 kontor-javalin/README.md create mode 100644 kontor-javalin/build.gradle create mode 100644 kontor-javalin/gradle.properties create mode 100644 kontor-javalin/gradle/libs.versions.toml create mode 100644 kontor-javalin/gradle/wrapper/gradle-wrapper.jar create mode 100644 kontor-javalin/gradle/wrapper/gradle-wrapper.properties create mode 100755 kontor-javalin/gradlew create mode 100644 kontor-javalin/gradlew.bat create mode 100644 kontor-javalin/settings.gradle create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/Main.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/infrastructure/AppHibernate.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/infrastructure/AppHibernateConfig.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/infrastructure/AppHibernateSessionFactory.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Artist.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Comic.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/ComicQueries.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/ComicWork.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Issue.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/IssueWork.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Publisher.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/StoryArc.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/TradePaperback.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Volume.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/comics/Worktype.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaActor.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaActorFile.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaArticle.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaFile.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaFileQueries.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/models/media/MediaVideo.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/web/ComicHandler.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/web/MediaFileHandler.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/web/model/NewMediaFile.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/web/model/ResultComic.java create mode 100644 kontor-javalin/src/main/java/de/thpeetz/kontor/web/model/ResultMediaFile.java create mode 100644 kontor-quarkus/.dockerignore create mode 100644 kontor-quarkus/.gitignore create mode 100644 kontor-quarkus/Dockerfile create mode 100644 kontor-quarkus/README.md create mode 100644 kontor-quarkus/build.gradle.kts create mode 100644 kontor-quarkus/gradle.properties create mode 100644 kontor-quarkus/gradle/wrapper/gradle-wrapper.jar create mode 100644 kontor-quarkus/gradle/wrapper/gradle-wrapper.properties create mode 100755 kontor-quarkus/gradlew create mode 100644 kontor-quarkus/gradlew.bat create mode 100644 kontor-quarkus/settings.gradle.kts create mode 100644 kontor-quarkus/src/main/docker/Dockerfile.jvm create mode 100644 kontor-quarkus/src/main/docker/Dockerfile.legacy-jar create mode 100644 kontor-quarkus/src/main/docker/Dockerfile.native create mode 100644 kontor-quarkus/src/main/docker/Dockerfile.native-micro create mode 100644 kontor-quarkus/src/main/kotlin/de/thpeetz/GreetingResource.kt create mode 100644 kontor-quarkus/src/main/kotlin/de/thpeetz/kontor/KontorApplication.kt create mode 100644 kontor-quarkus/src/main/kotlin/de/thpeetz/kontor/comics/domain/Comic.kt create mode 100644 kontor-quarkus/src/main/kotlin/de/thpeetz/kontor/comics/resource/ComicsResource.kt create mode 100644 kontor-quarkus/src/main/resources/application.properties create mode 100644 kontor-quarkus/src/native-test/kotlin/de/thpeetz/GreetingResourceIT.kt create mode 100644 kontor-quarkus/src/test/kotlin/de/thpeetz/GreetingResourceTest.kt create mode 100644 kontor-scripts/add_actors.py create mode 100644 kontor-scripts/add_link.py create mode 100644 kontor-scripts/add_links.py create mode 100644 kontor-scripts/db/__init__.py create mode 100644 kontor-scripts/db/models/__init__.py create mode 100644 kontor-scripts/db/models/admin.py rename kontor-scripts/{schema => db/models}/base.py (51%) create mode 100644 kontor-scripts/db/models/bookshelf.py create mode 100644 kontor-scripts/db/models/comic.py create mode 100644 kontor-scripts/db/models/database.py create mode 100644 kontor-scripts/db/models/media.py create mode 100644 kontor-scripts/db/models/tysc.py create mode 100644 kontor-scripts/db/repository/__init__.py create mode 100644 kontor-scripts/find_links.py create mode 100644 kontor-scripts/json_to_postgres.py create mode 100644 kontor-scripts/kontor.py create mode 100644 kontor-scripts/read_queue.py delete mode 100644 kontor-scripts/schema/admin.py delete mode 100644 kontor-scripts/schema/bookshelf.py delete mode 100644 kontor-scripts/schema/comic.py delete mode 100644 kontor-scripts/schema/database.py delete mode 100644 kontor-scripts/schema/media.py delete mode 100644 kontor-scripts/schema/metadata.py delete mode 100644 kontor-scripts/schema/tysc.py create mode 100644 kontor-servicemix/Dockerfile create mode 100644 kontor-servicemix/Makefile delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/data/MetaDataColumn.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/data/MetaDataTable.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/data/ModuleData.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/repository/MetaDataColumnRepository.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/repository/MetaDataTableRepository.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/repository/ModuleDataRepository.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/services/MetaDataService.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/services/ModuleService.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/views/MetaDataForm.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/views/MetaDataView.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/views/ModuleDataForm.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/admin/views/ModuleDataView.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/ComicRepository.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/data/IssueWork.java rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/ArtistRepository.java (86%) create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/repository/ComicRepository.java rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/ComicWorkRepository.java (85%) rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/IssueRepository.java (87%) create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/repository/IssueWorkRepository.java rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/PublisherRepository.java (86%) rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/StoryArcRepository.java (87%) rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/TradePaperbackRepository.java (90%) rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/VolumeRepository.java (74%) rename kontor-spring/src/main/java/de/thpeetz/kontor/comics/{data => repository}/WorktypeRepository.java (86%) create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueWorkForm.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/comics/views/IssueWorkView.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/common/views/ComicIssueField.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/common/views/FilterOption.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/common/views/SearchFilter.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/common/views/SearchFilterField.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/common/views/YearMonthField.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/integration/routes/AddLinkFromQueue.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/integration/routes/ReadQueueRoute.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/integration/services/AddLinkProcessor.java create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/integration/services/AddLinkService.java delete mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/media/data/MediaFileRepository.java rename kontor-spring/src/main/java/de/thpeetz/kontor/media/{data => repository}/MediaActorFileRepository.java (61%) rename kontor-spring/src/main/java/de/thpeetz/kontor/media/{data => repository}/MediaActorRepository.java (85%) rename kontor-spring/src/main/java/de/thpeetz/kontor/media/{data => repository}/MediaArticleRepository.java (84%) create mode 100644 kontor-spring/src/main/java/de/thpeetz/kontor/media/repository/MediaFileRepository.java rename kontor-spring/src/main/java/de/thpeetz/kontor/media/{data => repository}/MediaVideoRepository.java (85%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/ArtistRepositoryTest.java (96%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/ComicRepositoryTest.java (95%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/ComicWorkRepositoryTest.java (97%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/IssueRepositoryTest.java (93%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/PublisherRepositoryTest.java (96%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/StoryArcRepositoryTest.java (93%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/TradePaperbackRepositoryTest.java (96%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/VolumeRepositoryTest.java (95%) rename kontor-spring/src/test/java/de/thpeetz/kontor/comics/{data => repository}/WorktypeRepositoryTest.java (81%) create mode 100644 kontor-vue/.dockerignore create mode 100644 kontor-vue/.gitattributes create mode 100644 kontor-vue/.gitignore create mode 100644 kontor-vue/.prettierrc.json create mode 100644 kontor-vue/Dockerfile create mode 100644 kontor-vue/README.md create mode 100644 kontor-vue/babel.config.js create mode 100644 kontor-vue/cypress.config.ts create mode 100644 kontor-vue/cypress/e2e/example.cy.ts create mode 100644 kontor-vue/cypress/fixtures/example.json create mode 100644 kontor-vue/cypress/support/commands.ts create mode 100644 kontor-vue/cypress/support/e2e.ts create mode 100644 kontor-vue/cypress/tsconfig.json create mode 100644 kontor-vue/env.d.ts create mode 100644 kontor-vue/eslint.config.ts create mode 100644 kontor-vue/index.html create mode 100644 kontor-vue/jsconfig.json create mode 100644 kontor-vue/package-lock.json create mode 100644 kontor-vue/package.json create mode 100644 kontor-vue/public/favicon.ico create mode 100644 kontor-vue/public/index.html create mode 100644 kontor-vue/src/App.vue create mode 100644 kontor-vue/src/assets/base.css create mode 100644 kontor-vue/src/assets/logo.png create mode 100644 kontor-vue/src/assets/logo.svg create mode 100644 kontor-vue/src/assets/main.css create mode 100644 kontor-vue/src/components/MainHeader.vue create mode 100644 kontor-vue/src/components/MainNavbar.vue create mode 100644 kontor-vue/src/components/__tests__/MainHeader.spec.ts create mode 100644 kontor-vue/src/main.js create mode 100644 kontor-vue/src/main.ts create mode 100644 kontor-vue/src/router/index.ts create mode 100644 kontor-vue/src/stores/counter.ts create mode 100644 kontor-vue/src/views/ComicsView.vue create mode 100644 kontor-vue/src/views/HomeView.vue create mode 100644 kontor-vue/tsconfig.app.json create mode 100644 kontor-vue/tsconfig.json create mode 100644 kontor-vue/tsconfig.node.json create mode 100644 kontor-vue/tsconfig.vitest.json create mode 100644 kontor-vue/vite.config.ts create mode 100644 kontor-vue/vitest.config.ts create mode 100644 kontor-vue/vue.config.js diff --git a/.gitignore b/.gitignore index 57bd15d..391abfa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,8 @@ -.idea/ -.theia/ .vscode/ +.idea/ +.angular/ __pycache__/ -bonus/ -icons/ -icons-shadowless/ -springboot/.factorypath -java-ee/.settings -java-ee/.project -kontor-schema/env -kontor-schema/kontor_schema.egg-info -kontor-gui/.pdm-python -kontor-gui/dist -fastapi/.coverage +node_modules/ +.editorconfig db-password.txt +couchdb-password.txt diff --git a/Makefile b/Makefile index bc51f4a..df78fff 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ kontor_api := kontor-api kontor_spring := kontor-spring +kontor_angular := kontor-angular +TARGET=docker -.PHONY: all $(kontor_spring) $(kontor_api) -all: $(kontor_spring) $(kontor_api) +.PHONY: all $(kontor_spring) $(kontor_api) $(kontor_angular) -$(kontor_spring) $(kontor_api): +all: $(kontor_spring) $(kontor_api) $(kontor_angular) + +$(kontor_spring) $(kontor_api) $(kontor_angular): $(MAKE) --directory=$@ $(TARGET) diff --git a/compose-couchdb.yaml b/compose-couchdb.yaml new file mode 100644 index 0000000..18b3586 --- /dev/null +++ b/compose-couchdb.yaml @@ -0,0 +1,22 @@ +services: + couchdb: + image: couchdb + restart: unless-stopped + environment: + - COUCHDB_USER=admin + - COUCHDB_PASSWORD=admin + ports: + - 5984:5984 + networks: + - database + - frontend + volumes: + - couchdb-data:/opt/couchdb/data + secrets: + - couchdb-password + +volumes: + couchdb-data: +secrets: + couchdb-password: + file: couchdb-password.txt diff --git a/compose-postgres.yaml b/compose-postgres.yaml new file mode 100644 index 0000000..11ec0e0 --- /dev/null +++ b/compose-postgres.yaml @@ -0,0 +1,38 @@ +services: + postgres: + image: postgres + restart: unless-stopped + environment: + - POSTGRES_DB=kontor + - POSTGRES_USER=kontor + #- POSTGRES_PASSWORD_FILE=/run/secrets/db-password + - POSTGRES_PASSWORD=kontor + healthcheck: + test: ["CMD-SHELL", "pg_isready -U kontor"] + interval: 1s + timeout: 5s + retries: 10 + ports: + - 5432:5432 + networks: + - database + volumes: + - postgres-data:/var/lib/postgresql/data:rw + secrets: + - db-password + adminer: + image: adminer + ports: + - 8090:8080 + networks: + - database + - frontend +volumes: + postgres-data: +secrets: + db-password: + file: db-password.txt +networks: + database: + name: database + external: true diff --git a/docker-compose.yml b/docker-compose.yml index 55e906d..1de4dc6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,44 +1,189 @@ +include: + - ./compose-postgres.yaml services: - mariadb: - image: mariadb + activemq: + image: apache/activemq-artemis:latest-alpine restart: unless-stopped - environment: - MYSQL_ROOT_PASSWORD: kontor - MYSQL_USER: kontor - MYSQL_PASSWORD: kontor - MYSQL_DATABASE: kontor ports: - - 3316:3306 + - 61616:61616 + - 8161:8161 + - 5672:5672 networks: - - database + - integration + - frontend volumes: - - mariadb-storage:/var/lib/mysql:rw + - activemq-data:/var/lib/artemis-instance kontor: - image: kontor + build: + context: ./kontor-spring + dockerfile: Dockerfile + tags: + - kontor:0.2.0-SNAPSHOT + image: kontor:0.2.0-SNAPSHOT restart: unless-stopped networks: - database + - integration - frontend ports: - - 8000:8000 + - 8100:8100 + volumes: + - images-data:/data/images depends_on: - - mariadb + postgres: + condition: service_healthy kontor-api: - image: kontor-api + build: + context: ./kontor-api + dockerfile: Dockerfile + tags: + - kontor-api:0.2.0-SNAPSHOT + image: kontor-api:0.2.0-SNAPSHOT restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://kontor-api:8500/health"] + interval: 10s + timeout: 5s + retries: 3 networks: - database + - integration + - frontend + ports: + - 8500:8500 + volumes: + - images-data:/data/images + depends_on: + postgres: + condition: service_healthy + kontor-fiber: + build: + context: ./kontor-fiber + dockerfile: Dockerfile + tags: + - kontor-fiber:0.2.0-SNAPSHOT + image: kontor-fiber:0.2.0-SNAPSHOT + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://kontor-fiber:8600/health"] + interval: 10s + timeout: 5s + retries: 3 + networks: + - database + - integration + - frontend + ports: + - 8600:8600 + depends_on: + postgres: + condition: service_healthy + kontor-echo: + build: + context: ./kontor-echo + dockerfile: Dockerfile + tags: + - kontor-echo:0.2.0-SNAPSHOT + image: kontor-echo:0.2.0-SNAPSHOT + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://kontor-echo:8700/health"] + interval: 10s + timeout: 5s + retries: 3 + networks: + - database + - integration + - frontend + ports: + - 8700:8700 + depends_on: + postgres: + condition: service_healthy + kontor-quarkus: + build: + context: ./kontor-quarkus + dockerfile: Dockerfile + tags: + - kontor-quarkus:0.2.0-SNAPSHOT + image: kontor-quarkus:0.2.0-SNAPSHOT + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://kontor-quarkus:8800/q/health"] + interval: 10s + timeout: 5s + retries: 3 + networks: + - database + - integration - frontend ports: - 8800:8800 depends_on: - - mariadb + postgres: + condition: service_healthy + kontor-angular: + build: + context: ./kontor-angular + dockerfile: Dockerfile + tags: + - kontor-angular:0.2.0-SNAPSHOT + image: kontor-angular:0.2.0-SNAPSHOT + restart: unless-stopped + networks: + - database + - integration + - frontend + ports: + - 8200:80 + depends_on: + kontor-api: + condition: service_healthy + kontor-vue: + build: + context: ./kontor-vue + dockerfile: Dockerfile + tags: + - kontor-vue:0.2.0-SNAPSHOT + image: kontor-vue:0.2.0-SNAPSHOT + restart: unless-stopped + networks: + - database + - integration + - frontend + ports: + - 8300:80 + depends_on: + postgres: + condition: service_healthy + kontor-javalin: + build: + context: ./kontor-javalin + dockerfile: Dockerfile + tags: + - kontor-javalin:0.2.0-SNAPSHOT + image: kontor-javalin:0.2.0-SNAPSHOT + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://kontor-javalin:8400/health"] + interval: 10s + timeout: 5s + retries: 3 + networks: + - database + - integration + - frontend + ports: + - 8400:8400 + depends_on: + postgres: + condition: service_healthy networks: - database: + integration: + name: integration frontend: - volumes: - mariadb-storage: - + activemq-data: + images-data: diff --git a/kontor-angular/.dockerignore b/kontor-angular/.dockerignore new file mode 100644 index 0000000..1502ec2 --- /dev/null +++ b/kontor-angular/.dockerignore @@ -0,0 +1,3 @@ +dist +node_modules + diff --git a/kontor-angular/.gitignore b/kontor-angular/.gitignore new file mode 100644 index 0000000..cc7b141 --- /dev/null +++ b/kontor-angular/.gitignore @@ -0,0 +1,42 @@ +# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/kontor-angular/Dockerfile b/kontor-angular/Dockerfile new file mode 100644 index 0000000..770d77a --- /dev/null +++ b/kontor-angular/Dockerfile @@ -0,0 +1,14 @@ +### STAGE 1: Build ### +FROM node:22.15-alpine AS build +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm install +COPY . . +RUN npm run build + +### STAGE 2: Run ### +FROM nginx:1.17.1-alpine +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist/kontor-angular/browser /usr/share/nginx/html +EXPOSE 80 + diff --git a/kontor-angular/Makefile b/kontor-angular/Makefile new file mode 100644 index 0000000..2a2107c --- /dev/null +++ b/kontor-angular/Makefile @@ -0,0 +1,8 @@ +.PHONY: docker dev + +docker: + docker build -t kontor-angular:0.2.0-SNAPSHOT . + +dev: + ng serve + diff --git a/kontor-angular/README.md b/kontor-angular/README.md new file mode 100644 index 0000000..c938618 --- /dev/null +++ b/kontor-angular/README.md @@ -0,0 +1,59 @@ +# KontorAngular + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.2.1. + +## Development server + +To start a local development server, run: + +```bash +ng serve +``` + +Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the project run: + +```bash +ng build +``` + +This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. + +## Running unit tests + +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/kontor-angular/angular.json b/kontor-angular/angular.json new file mode 100644 index 0000000..6c196b3 --- /dev/null +++ b/kontor-angular/angular.json @@ -0,0 +1,95 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "kontor-angular": { + "projectType": "application", + "schematics": {}, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "tsconfig.app.json", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": [ + "src/styles.css" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "kontor-angular:build:production" + }, + "development": { + "buildTarget": "kontor-angular:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular/build:extract-i18n" + }, + "test": { + "builder": "@angular/build:karma", + "options": { + "polyfills": [ + "zone.js", + "zone.js/testing" + ], + "tsConfig": "tsconfig.spec.json", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": [ + "src/styles.css" + ] + } + } + } + } + }, + "cli": { + "analytics": false + } +} diff --git a/kontor-angular/nginx.conf b/kontor-angular/nginx.conf new file mode 100644 index 0000000..c8444ce --- /dev/null +++ b/kontor-angular/nginx.conf @@ -0,0 +1,37 @@ +server { + # Root-Verzeichnis für den Server setzen (wir kopieren unsere Anwendung hierher) + root /usr/share/nginx/html; + + # Definieren der Standard-Indexdatei (Angular erstellt die Datei index.html für uns und sie befindet sich im oben genannten Verzeichnis) + index index.html; + + # Cache-Header für Medien-ASsets + location ~* \.(?:cur|jpe?g|gif|htc|ico|png|xml|otf|ttf|eot|woff|woff2|svg)$ { + access_log off; + add_header Pragma "must-revalidate, public"; + add_header Cache-Control "must-revalidate, public"; + expires max; + + tcp_nodelay off; + } + + # Cache-Header für HTML, CSS und JS-Dateien + location ~* \.(?:css|js|html)$ { + access_log off; + add_header Pragma "must-revalidate, public"; + add_header Cache-Control "must-revalidate, public"; + expires 2d; + + tcp_nodelay off; + } + + # Konfiguration für den /-Pfad + location / { + # Zunächst versuchen wir die angeforderte URI auzuliefern + # Klappt das nicht, versuchen wir es mit einem abschließenden Slash + # Klappt auch das nicht, liefern wir die index.html aus. + # Das ist nötig, damit Angular-Routen korrekt augeflöst und ausgeliefert werden + try_files $uri $uri/ /index.html; + } +} + diff --git a/kontor-angular/package-lock.json b/kontor-angular/package-lock.json new file mode 100644 index 0000000..0d13059 --- /dev/null +++ b/kontor-angular/package-lock.json @@ -0,0 +1,9970 @@ +{ + "name": "kontor-angular", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kontor-angular", + "version": "0.0.0", + "dependencies": { + "@angular/common": "^20.2.0", + "@angular/compiler": "^20.2.0", + "@angular/core": "^20.2.0", + "@angular/forms": "^20.2.0", + "@angular/platform-browser": "^20.2.0", + "@angular/router": "^20.2.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular/build": "^20.2.1", + "@angular/cli": "^20.2.1", + "@angular/compiler-cli": "^20.2.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.9.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.9.2" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.1.0.tgz", + "integrity": "sha512-sEyWjw28a/9iluA37KLGu8vjxEIlb60uxznfTUmXImy7H5NvbpSO6yYgmgH5KiD7j+zTUUihiST0jEP12IoXow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.35.0.tgz", + "integrity": "sha512-uUdHxbfHdoppDVflCHMxRlj49/IllPwwQ2cQ8DLC4LXr3kY96AHBpW0dMyi6ygkn2MtFCc6BxXCzr668ZRhLBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.35.0.tgz", + "integrity": "sha512-SunAgwa9CamLcRCPnPHx1V2uxdQwJGqb1crYrRWktWUdld0+B2KyakNEeVn5lln4VyeNtW17Ia7V7qBWyM/Skw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.35.0.tgz", + "integrity": "sha512-ipE0IuvHu/bg7TjT2s+187kz/E3h5ssfTtjpg1LbWMgxlgiaZIgTTbyynM7NfpSJSKsgQvCQxWjGUO51WSCu7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.35.0.tgz", + "integrity": "sha512-UNbCXcBpqtzUucxExwTSfAe8gknAJ485NfPN6o1ziHm6nnxx97piIbcBQ3edw823Tej2Wxu1C0xBY06KgeZ7gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.35.0.tgz", + "integrity": "sha512-/KWjttZ6UCStt4QnWoDAJ12cKlQ+fkpMtyPmBgSS2WThJQdSV/4UWcqCUqGH7YLbwlj3JjNirCu3Y7uRTClxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.35.0.tgz", + "integrity": "sha512-8oCuJCFf/71IYyvQQC+iu4kgViTODbXDk3m7yMctEncRSRV+u2RtDVlpGGfPlJQOrAY7OONwJlSHkmbbm2Kp/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.35.0.tgz", + "integrity": "sha512-FfmdHTrXhIduWyyuko1YTcGLuicVbhUyRjO3HbXE4aP655yKZgdTIfMhZ/V5VY9bHuxv/fGEh3Od1Lvv2ODNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.35.0.tgz", + "integrity": "sha512-gPzACem9IL1Co8mM1LKMhzn1aSJmp+Vp434An4C0OBY4uEJRcqsLN3uLBlY+bYvFg8C8ImwM9YRiKczJXRk0XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.35.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.35.0.tgz", + "integrity": "sha512-w9MGFLB6ashI8BGcQoVt7iLgDIJNCn4OIu0Q0giE3M2ItNrssvb8C0xuwJQyTy1OFZnemG0EB1OvXhIHOvQwWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.35.0.tgz", + "integrity": "sha512-AhrVgaaXAb8Ue0u2nuRWwugt0dL5UmRgS9LXe0Hhz493a8KFeZVUE56RGIV3hAa6tHzmAV7eIoqcWTQvxzlJeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.35.0.tgz", + "integrity": "sha512-diY415KLJZ6x1Kbwl9u96Jsz0OstE3asjXtJ9pmk1d+5gPuQ5jQyEsgC+WmEXzlec3iuVszm8AzNYYaqw6B+Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.35.0.tgz", + "integrity": "sha512-uydqnSmpAjrgo8bqhE9N1wgcB98psTRRQXcjc4izwMB7yRl9C8uuAQ/5YqRj04U0mMQ+fdu2fcNF6m9+Z1BzDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.35.0.tgz", + "integrity": "sha512-RgLX78ojYOrThJHrIiPzT4HW3yfQa0D7K+MQ81rhxqaNyNBu4F1r+72LNHYH/Z+y9I1Mrjrd/c/Ue5zfDgAEjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.2002.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2002.2.tgz", + "integrity": "sha512-amppp/UqKyj+B8hYFU16j4t6SVN+SS0AEnHivDjKy41NNJgXv+5Sm2Q2jaMHviCT3rclyT0wqwNAi0RDjyLx5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "20.2.2", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.2.2.tgz", + "integrity": "sha512-SC+f5isSWJBpEgR+R7jP++2Z14WExNWLAdKpIickLWjuL8FlGkj+kaF3dWXhh0KcXo+r6kKb4pWUptSaqer5gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.3", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-20.2.2.tgz", + "integrity": "sha512-rtL7slZjzdChQoiADKZv/Ra8D3C3tIw/WcVxd2stiLHdK/Oaf9ejx5m/X9o0QMEbNsy2Fy/RKodNqmz1CjzpCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "20.2.2", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "8.2.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/build": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-20.2.2.tgz", + "integrity": "sha512-rvlKMt3OmeenHOwejRpI4OLcyERQn6Hl4ODRWlYfNX70Ki1zu6eAD0pWULzcD+HSQd0a26Xzt3gcpEy2vOEAzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2002.2", + "@babel/core": "7.28.3", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "5.1.14", + "@vitejs/plugin-basic-ssl": "2.1.0", + "beasties": "0.3.5", + "browserslist": "^4.23.0", + "esbuild": "0.25.9", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "listr2": "9.0.1", + "magic-string": "0.30.17", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "8.0.0", + "picomatch": "4.0.3", + "piscina": "5.1.3", + "rolldown": "1.0.0-beta.32", + "sass": "1.90.0", + "semver": "7.7.2", + "source-map-support": "0.5.21", + "tinyglobby": "0.2.14", + "vite": "7.1.2", + "watchpack": "2.4.4" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "lmdb": "3.4.2" + }, + "peerDependencies": { + "@angular/compiler": "^20.0.0", + "@angular/compiler-cli": "^20.0.0", + "@angular/core": "^20.0.0", + "@angular/localize": "^20.0.0", + "@angular/platform-browser": "^20.0.0", + "@angular/platform-server": "^20.0.0", + "@angular/service-worker": "^20.0.0", + "@angular/ssr": "^20.2.2", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^20.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.8 <6.0", + "vitest": "^3.1.1" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@angular/cli": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-20.2.2.tgz", + "integrity": "sha512-0K8cmuHzRTpPzy/w0+S5o3s0JPV++9/s2JhK4aw/+OnQRpUbodoqjm1ur5k5DUBQfIHi7aM73ZIW3G43lv4F0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.2002.2", + "@angular-devkit/core": "20.2.2", + "@angular-devkit/schematics": "20.2.2", + "@inquirer/prompts": "7.8.2", + "@listr2/prompt-adapter-inquirer": "3.0.1", + "@modelcontextprotocol/sdk": "1.17.3", + "@schematics/angular": "20.2.2", + "@yarnpkg/lockfile": "1.1.0", + "algoliasearch": "5.35.0", + "ini": "5.0.0", + "jsonc-parser": "3.3.1", + "listr2": "9.0.1", + "npm-package-arg": "13.0.0", + "pacote": "21.0.0", + "resolve": "1.22.10", + "semver": "7.7.2", + "yargs": "18.0.0", + "zod": "3.25.76" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.2.4.tgz", + "integrity": "sha512-mc6Sq1cYjaPJYThnvG6x0f/E27pWksqwaNJxT1RtwhAGc1i2jsc0su6b7e5NnXEgVbdPqu1MZHAEFdXZ5+/MwQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "20.2.4", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.2.4.tgz", + "integrity": "sha512-LQzf+Azb/Ms+BavpCFIat+f1C0gUJpby2RW4yebF3JkBFKfJ7M8d49TQpF8rSnGxMRTf49mln7laz4nBYTLDGA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@angular/compiler-cli": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.2.4.tgz", + "integrity": "sha512-II2hEpfbo73dL12D42DoIHYGiTYAiO9cpwh29BIo8VD054ei4cm0oK+jCyryDQH5T3+wyCWlj0OFjcZ/GmO7HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "7.28.3", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^4.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^18.0.0" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "20.2.4", + "typescript": ">=5.8 <6.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@angular/core": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.2.4.tgz", + "integrity": "sha512-8yvfvPDWX8M7o82GBl5P1nlvm1ywQ2XZi5HWj3llKpSJE2XjzhATgPrpKwiNVnpgjZWTOwM11fpoAaRKqQjxTA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "20.2.4", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } + } + }, + "node_modules/@angular/forms": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.2.4.tgz", + "integrity": "sha512-wbgnW+GALVAmK6hgFegkwlHKw35onvh9Z5A236HCyUySEAOiaD/3CoDg5Hw4iHQAiSU6Fn2NwDiv+W0xki6WDw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/common": "20.2.4", + "@angular/core": "20.2.4", + "@angular/platform-browser": "20.2.4", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.2.4.tgz", + "integrity": "sha512-81vzW8xhnJU7AiYJKXLR2MuvawzhRDgwyNkPEep58wty5zNuIUCXdUERJSsXo7m/U2Dg1FUFfqLm4RC2UkqLzA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/animations": "20.2.4", + "@angular/common": "20.2.4", + "@angular/core": "20.2.4" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/router": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.2.4.tgz", + "integrity": "sha512-KoduI1o+iBfCBGtXMvmy/qncDIwGxd2hNt2hDkkiYZTftmSg/XUJDxJqN84ckm2WLkdJpR9EirrwfHapJBIZOQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/common": "20.2.4", + "@angular/core": "20.2.4", + "@angular/platform-browser": "20.2.4", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.2.tgz", + "integrity": "sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", + "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.18.tgz", + "integrity": "sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.2.tgz", + "integrity": "sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.18.tgz", + "integrity": "sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.18.tgz", + "integrity": "sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.2.tgz", + "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.2.1", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.17", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.6.tgz", + "integrity": "sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.1.tgz", + "integrity": "sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.2.tgz", + "integrity": "sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.0", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz", + "integrity": "sha512-3XFmGwm3u6ioREG+ynAQB7FoxfajgQnMhIu8wC5eo/Lsih4aKDg0VuIMGaOsYn7hJSJagSeaD4K8yfpkEoDEmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^3.0.7" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.1" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.4.2.tgz", + "integrity": "sha512-NK80WwDoODyPaSazKbzd3NEJ3ygePrkERilZshxBViBARNz21rmediktGHExoj9n5t9+ChlgLlxecdFKLCuCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.4.2.tgz", + "integrity": "sha512-zevaowQNmrp3U7Fz1s9pls5aIgpKRsKb3dZWDINtLiozh3jZI9fBrI19lYYBxqdyiIyNdlyiidPnwPShj4aK+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.4.2.tgz", + "integrity": "sha512-OmHCULY17rkx/RoCoXlzU7LyR8xqrksgdYWwtYa14l/sseezZ8seKWXcogHcjulBddER5NnEFV4L/Jtr2nyxeg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.4.2.tgz", + "integrity": "sha512-ZBEfbNZdkneebvZs98Lq30jMY8V9IJzckVeigGivV7nTHJc+89Ctomp1kAIWKlwIG0ovCDrFI448GzFPORANYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.4.2.tgz", + "integrity": "sha512-vL9nM17C77lohPYE4YaAQvfZCSVJSryE4fXdi8M7uWPBnU+9DJabgKVAeyDb84ZM2vcFseoBE4/AagVtJeRE7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.4.2.tgz", + "integrity": "sha512-SXWjdBfNDze4ZPeLtYIzsIeDJDJ/SdsA0pEXcUBayUIMO0FQBHfVZZyHXQjjHr4cvOAzANBgIiqaXRwfMhzmLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.4.2.tgz", + "integrity": "sha512-IY+r3bxKW6Q6sIPiMC0L533DEfRJSXibjSI3Ft/w9Q8KQBNqEIvUFXt+09wV8S5BRk0a8uSF19YWxuRwEfI90g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz", + "integrity": "sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.23.8", + "zod-to-json-schema": "^3.24.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz", + "integrity": "sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@npmcli/agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/fs": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/git": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-6.0.3.tgz", + "integrity": "sha512-GUYESQlxZRAdhs3UhbB6pVRNUELQOHXwK9ruDkwmCv2aZ5y0SApQzUJCg02p3A7Ue2J5hxvlk1YI53c00NmRyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-3.0.0.tgz", + "integrity": "sha512-fkxoPuFGvxyrH+OQzyTkX2LUEamrF4jZSmxjAtPPHHGO0dqsQ8tTKjnIS8SAnPHdk2I03BDtSMR5K/4loKg79Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-4.0.0.tgz", + "integrity": "sha512-+t5DZ6mO/QFh78PByMq1fGSAub/agLJZDRfJRMeOSNCt8s9YVlTjmGpIPwPhvXTGUIJk+WszlT0rQa1W33yzNA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-6.2.0.tgz", + "integrity": "sha512-rCNLSB/JzNvot0SEyXqWZ7tX2B5dD2a1br2Dp0vSYVo5jh8Z0EZ7lS9TsZ1UtziddB1UfNUaMCc538/HztnJGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-8.0.3.tgz", + "integrity": "sha512-Yb00SWaL4F8w+K8YGhQ55+xE4RUNdMHV43WZGsiTM92gS+lC0mGsn7I4hLug7pbao035S6bj3Y3w0cUNGLfmkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-3.2.2.tgz", + "integrity": "sha512-7VmYAmk4csGv08QzrDKScdzn11jHPFGyqJW39FyPgPuAp3zIaUmuCo1yxw9aGs+NEJuTGQ9Gwqpt93vtJubucg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-9.1.0.tgz", + "integrity": "sha512-aoNSbxtkePXUlbZB+anS1LqsJdctG5n3UVhfU47+CDdwMi6uNTBMF9gPcQRnqghQd2FGzcwwIFBruFMxjhBewg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "node-gyp": "^11.0.0", + "proc-log": "^5.0.0", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@oxc-project/runtime": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.81.0.tgz", + "integrity": "sha512-zm/LDVOq9FEmHiuM8zO4DWirv0VP2Tv2VsgaiHby9nvpq+FVrcqNYgv+TysLKOITQXWZj/roluTxFvpkHP0Iuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.81.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.81.0.tgz", + "integrity": "sha512-CnOqkybZK8z6Gx7Wb1qF7AEnSzbol1WwcIzxYOr8e91LytGOjo0wCpgoYWZo8sdbpqX+X+TJayIzo4Pv0R/KjA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.32.tgz", + "integrity": "sha512-Gs+313LfR4Ka3hvifdag9r44WrdKQaohya7ZXUXzARF7yx0atzFlVZjsvxtKAw1Vmtr4hB/RjUD1jf73SW7zDw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.32.tgz", + "integrity": "sha512-W8oMqzGcI7wKPXUtS3WJNXzbghHfNiuM1UBAGpVb+XlUCgYRQJd2PRGP7D3WGql3rR3QEhUvSyAuCBAftPQw6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.32.tgz", + "integrity": "sha512-pM4c4sKUk37noJrnnDkJknLhCsfZu7aWyfe67bD0GQHfzAPjV16wPeD9CmQg4/0vv+5IfHYaa4VE536xbA+W0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.32.tgz", + "integrity": "sha512-M8SUgFlYb5kJJWcFC8gUMRiX4WLFxPKMed3SJ2YrxontgIrEcpizPU8nLNVsRYEStoSfKHKExpQw3OP6fm+5bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.32.tgz", + "integrity": "sha512-FuQpbNC/hE//bvv29PFnk0AtpJzdPdYl5CMhlWPovd9g3Kc3lw9TrEPIbL7gRPUdhKAiq6rVaaGvOnXxsa0eww==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.32.tgz", + "integrity": "sha512-hRZygRlaGCjcNTNY9GV7dDI18sG1dK3cc7ujHq72LoDad23zFDUGMQjiSxHWK+/r92iMV+j2MiHbvzayxqynsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.32.tgz", + "integrity": "sha512-HzgT6h+CXLs+GKAU0Wvkt3rvcv0CmDBsDjlPhh4GHysOKbG9NjpKYX2zvjx671E9pGbTvcPpwy7gGsy7xpu+8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.32.tgz", + "integrity": "sha512-Ab/wbf6gdzphDbsg51UaxsC93foQ7wxhtg0SVCXd25BrV4MAJ1HoDtKN/f4h0maFmJobkqYub2DlmoasUzkvBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.32.tgz", + "integrity": "sha512-VoxqGEfh5A1Yx+zBp/FR5QwAbtzbuvky2SVc+ii4g1gLD4zww6mt/hPi5zG+b88zYPFBKHpxMtsz9cWqXU5V5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.32.tgz", + "integrity": "sha512-qZ1ViyOUDGbiZrSAJ/FIAhYUElDfVxxFW6DLT/w4KeoZN3HsF4jmRP95mXtl51/oGrqzU9l9Q2f7/P4O/o2ZZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.32.tgz", + "integrity": "sha512-hEkG3wD+f3wytV0lqwb/uCrXc4r4Ny/DWJFJPfQR3VeMWplhWGgSHNwZc2Q7k86Yi36f9NNzzWmrIuvHI9lCVw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.32.tgz", + "integrity": "sha512-k3MvDf8SiA7uP2ikP0unNouJ2YCrnwi7xcVW+RDgMp5YXVr3Xu6svmT3HGn0tkCKUuPmf+uy8I5uiHt5qWQbew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.32.tgz", + "integrity": "sha512-wAi/FxGh7arDOUG45UmnXE1sZUa0hY4cXAO2qWAjFa3f7bTgz/BqwJ7XN5SUezvAJPNkME4fEpInfnBvM25a0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.32.tgz", + "integrity": "sha512-Ej0i4PZk8ltblZtzVK8ouaGUacUtxRmTm5S9794mdyU/tYxXjAJNseOfxrnHpMWKjMDrOKbqkPqJ52T9NR4LQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz", + "integrity": "sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", + "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", + "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", + "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", + "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", + "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", + "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", + "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", + "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", + "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", + "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", + "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", + "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", + "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", + "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", + "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", + "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", + "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", + "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", + "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", + "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", + "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "20.2.2", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-20.2.2.tgz", + "integrity": "sha512-VzJsEIiBmHzJAOVaKHn1CwTuOqvI1GwZuneUk/tmyYKkKdWEgxnoNBvz1ql6eHstkLz3S9yt6aUuAgjQC+J2Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "20.2.2", + "@angular-devkit/schematics": "20.2.2", + "jsonc-parser": "3.3.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-3.1.0.tgz", + "integrity": "sha512-Mm1E3/CmDDCz3nDhFKTuYdB47EdRFRQMOE/EAbiG1MJW77/w1b3P7Qx7JSrVJs8PfwOLOVcKQCHErIwCTyPbag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-2.0.0.tgz", + "integrity": "sha512-nYxaSb/MtlSI+JWcwTHQxyNmWeWrUXJJ/G4liLrGG7+tS4vAz6LF3xRXqLH6wPIVUoZQel2Fs4ddLx4NCpiIYg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.4.3.tgz", + "integrity": "sha512-fk2zjD9117RL9BjqEwF7fwv7Q/P9yGsMV4MUJZ/DocaQJ6+3pKr+syBq1owU5Q5qGw5CUbXzm+4yJ2JVRDQeSA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-3.1.0.tgz", + "integrity": "sha512-knzjmaOHOov1Ur7N/z4B1oPqZ0QX5geUfhrVaqVlu+hl0EAoL4o+l0MSULINcD5GCWe3Z0+YJO8ues6vFlW0Yw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "make-fetch-happen": "^14.0.2", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-3.1.1.tgz", + "integrity": "sha512-eFFvlcBIoGwVkkwmTi/vEQFSva3xs5Ot3WmBcjgjVdiaoelBLQaQ/ZBfhlG0MnG0cmTYScPpk7eDdGDWUcFUmg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.1", + "tuf-js": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-2.1.1.tgz", + "integrity": "sha512-hVJD77oT67aowHxwT4+M6PGOp+E2LtLdTK3+FC0lBO9T7sYwItDMXZ7Z07IDCvR1M717a4axbIWckrW67KMP/w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-3.0.1.tgz", + "integrity": "sha512-UUYHISyhCU3ZgN8yaear3cGATHb3SMuKHsQ/nVbHXcmnBf+LzQ/cQfhNG+rfaSHgqGKNEm2cOCLVLELStUQ1JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jasmine": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.9.tgz", + "integrity": "sha512-8t4HtkW4wxiPVedMpeZ63n3vlWxEIquo/zc1Tm8ElU+SqVV7+D3Na2PWaJUp179AzTragMWVwkMv7mvty0NfyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz", + "integrity": "sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/algoliasearch": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.35.0.tgz", + "integrity": "sha512-Y+moNhsqgLmvJdgTsO4GZNgsaDWv8AOGAaPeIeHKlDn/XunoAqYbA+XNpBd1dW8GOXAUDyxC9Rxc7AV4kpFcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.1.0", + "@algolia/client-abtesting": "5.35.0", + "@algolia/client-analytics": "5.35.0", + "@algolia/client-common": "5.35.0", + "@algolia/client-insights": "5.35.0", + "@algolia/client-personalization": "5.35.0", + "@algolia/client-query-suggestions": "5.35.0", + "@algolia/client-search": "5.35.0", + "@algolia/ingestion": "1.35.0", + "@algolia/monitoring": "1.35.0", + "@algolia/recommend": "5.35.0", + "@algolia/requester-browser-xhr": "5.35.0", + "@algolia/requester-fetch": "5.35.0", + "@algolia/requester-node-http": "5.35.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/beasties": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.3.5.tgz", + "integrity": "sha512-NaWu+f4YrJxEttJSm16AzMIFtVldCvaJ68b1L098KpqXmxt9xOLtKoLkKxb8ekhOrLqEJAbvT6n6SEvB/sac7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", + "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001737", + "electron-to-chromium": "^1.5.211", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001741", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", + "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.215", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.215.tgz", + "integrity": "sha512-TIvGp57UpeNetj/wV/xpFNpWGb0b/ROw372lHPx5Aafx02gjTBtWnEEcaSX3W2dLM3OSdGGyHX/cHl01JQsLaQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", + "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "punycode": "^1.4.1", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", + "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.1.tgz", + "integrity": "sha512-R1QfovbPsKmosqTnPoRFiJ7CF9MLRgb53ChvMZm+r4p76/+8yKDy17qLL2PKInORy2RkZZekuK0efYgmzTkXyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.0.tgz", + "integrity": "sha512-gEf705MZLrDPkbbhi8PnoO4ZwYgKoNL+ISZ3AjZMht2r3N5tuTwncyDi6Fv2/qDnMmZxgs0yI8WDOyR8q3G+SQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.1.tgz", + "integrity": "sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-walk": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", + "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/immutable": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-5.0.0.tgz", + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jasmine-core": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.9.0.tgz", + "integrity": "sha512-OMUvF1iI6+gSRYOhMrH4QYothVLN9C3EJ6wm4g7zLJlnaTl8zbaPOr0bTw70l7QxkoM7sVFOWo83u9B2Fe2Zng==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/karma": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.7.2", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.1.tgz", + "integrity": "sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma-coverage/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/karma-jasmine": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", + "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", + "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "jasmine-core": "^4.0.0 || ^5.0.0", + "karma": "^6.0.0", + "karma-jasmine": "^5.0.0" + } + }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", + "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/karma/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/karma/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/karma/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/karma/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/karma/node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/karma/node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/karma/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/listr2": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", + "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lmdb": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.4.2.tgz", + "integrity": "sha512-nwVGUfTBUwJKXd6lRV8pFNfnrCC1+l49ESJRM19t/tFb/97QfJEixe5DYRvug5JO7DSFKoKaVy7oGMt5rVqZvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.4.2", + "@lmdb/lmdb-darwin-x64": "3.4.2", + "@lmdb/lmdb-linux-arm": "3.4.2", + "@lmdb/lmdb-linux-arm64": "3.4.2", + "@lmdb/lmdb-linux-x64": "3.4.2", + "@lmdb/lmdb-win32-arm64": "3.4.2", + "@lmdb/lmdb-win32-x64": "3.4.2" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/log4js": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/make-dir": { + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-fetch-happen": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.5.tgz", + "integrity": "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==", + "dev": true, + "license": "MIT", + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-gyp": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.4.2.tgz", + "integrity": "sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "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==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-releases": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.20.tgz", + "integrity": "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-4.0.0.tgz", + "integrity": "sha512-IxaQZDMsqfQ2Lz37VvyyEtKLe8FsRZuysmedy/N06TU1RyVppYKXrO4xIhR0F+7ubIBox6Q7nir6fQI3ej39iA==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-install-checks": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-7.1.2.tgz", + "integrity": "sha512-z9HJBCYw9Zr8BqXcllKIs5nI+QggAImbBdHphOzVYrz2CB4iQ6FzWyKmlqDZua+51nAu7FcemlbTc9VgQN5XDQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-package-arg": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.0.tgz", + "integrity": "sha512-+t2etZAGcB7TbbLHfDwooV9ppB2LhhcT6A+L9cahsf9mEUAoQ6CktLEVvEnpD0N5CkX7zJqnPGaFtoQDy9EkHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-packlist": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.1.tgz", + "integrity": "sha512-vaC03b2PqJA6QqmwHi1jNU8fAPXEnnyv4j/W4PVfgm24C4/zZGSVut3z0YUeN0WIFCo1oGOL02+6LbvFK7JL4Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-10.0.0.tgz", + "integrity": "sha512-r4fFa4FqYY8xaM7fHecQ9Z2nE9hgNfJR+EmoKv0+chvzWkBcORX3r0FpTByP+CbOVJDladMXnPQGVN8PBLGuTQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-18.0.2.tgz", + "integrity": "sha512-LeVMZBBVy+oQb5R6FDV9OlJCcWDU+al10oKpe+nsvcHnG24Z3uM3SvJYKfGJlfGjVU8v9liejCrUR/M5HO5NEQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^3.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^14.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^12.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ordered-binary": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.0.tgz", + "integrity": "sha512-IQh2aMfMIDbPjI/8a3Edr+PiOpcsB7yo8NdW7aHWVaoR/pcDldunMvnnwbk/auPGqmKeAdxtZl7MHX/QmPwhvQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pacote": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.0.0.tgz", + "integrity": "sha512-lcqexq73AMv6QNLo7SOpz0JJoaGdS3rBFgF122NZVl1bApo2mfu+XzUBU/X/XsiJu+iUmKpekRayqQYAs+PhkA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^10.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/pacote/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/pacote/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/pacote/node_modules/npm-package-arg": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz", + "integrity": "sha512-f1NpFjNI9O4VbKMOlA5QoBq/vSQPORHcTZ2feJpFkTHJ9eQkdlmZEKSjcAhxTGInC7RlEyScT9ui67NaOsjFWA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", + "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0", + "parse5": "^8.0.0", + "parse5-sax-parser": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/piscina": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.3.tgz", + "integrity": "sha512-0u3N7H4+hbr40KjuVn2uNhOcthu/9usKhnw5vT3J7ply79v3D3M8naI00el9Klcy16x557VsEkkUQaHCWFXC/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.x" + }, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz", + "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true, + "license": "MIT" + }, + "node_modules/proc-log": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-beta.32", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.32.tgz", + "integrity": "sha512-vxI2sPN07MMaoYKlFrVva5qZ1Y7DAZkgp7MQwTnyHt4FUMz9Sh+YeCzNFV9JYHI6ZNwoGWLCfCViE3XVsRC1cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/runtime": "=0.81.0", + "@oxc-project/types": "=0.81.0", + "@rolldown/pluginutils": "1.0.0-beta.32", + "ansis": "^4.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.32", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.32", + "@rolldown/binding-darwin-x64": "1.0.0-beta.32", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.32", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.32", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.32", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.32", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.32", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.32", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.32", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.32", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.32", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.32", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.32" + } + }, + "node_modules/rollup": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", + "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.50.1", + "@rollup/rollup-android-arm64": "4.50.1", + "@rollup/rollup-darwin-arm64": "4.50.1", + "@rollup/rollup-darwin-x64": "4.50.1", + "@rollup/rollup-freebsd-arm64": "4.50.1", + "@rollup/rollup-freebsd-x64": "4.50.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", + "@rollup/rollup-linux-arm-musleabihf": "4.50.1", + "@rollup/rollup-linux-arm64-gnu": "4.50.1", + "@rollup/rollup-linux-arm64-musl": "4.50.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", + "@rollup/rollup-linux-ppc64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-musl": "4.50.1", + "@rollup/rollup-linux-s390x-gnu": "4.50.1", + "@rollup/rollup-linux-x64-gnu": "4.50.1", + "@rollup/rollup-linux-x64-musl": "4.50.1", + "@rollup/rollup-openharmony-arm64": "4.50.1", + "@rollup/rollup-win32-arm64-msvc": "4.50.1", + "@rollup/rollup-win32-ia32-msvc": "4.50.1", + "@rollup/rollup-win32-x64-msvc": "4.50.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-3.1.0.tgz", + "integrity": "sha512-ZpzWAFHIFqyFE56dXqgX/DkDRZdz+rRcjoIk/RQU4IX0wiCv1l8S7ZrXDHcCc+uaf+6o7w3h2l3g6GYG5TKN9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "@sigstore/sign": "^3.1.0", + "@sigstore/tuf": "^3.1.0", + "@sigstore/verify": "^2.1.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/ssri": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-3.1.0.tgz", + "integrity": "sha512-3T3T04WzowbwV2FDiGXBbr81t64g1MUGGJRgT4x5o97N+8ArdhVCAF9IxFrxuSJmM3E5Asn7nKHkao0ibcZXAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "3.0.1", + "debug": "^4.4.1", + "make-fetch-happen": "^14.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", + "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/unique-slug": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.2.tgz", + "integrity": "sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.2.tgz", + "integrity": "sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.6", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } + }, + "node_modules/zone.js": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "license": "MIT" + } + } +} diff --git a/kontor-angular/package.json b/kontor-angular/package.json new file mode 100644 index 0000000..2a59b56 --- /dev/null +++ b/kontor-angular/package.json @@ -0,0 +1,48 @@ +{ + "name": "kontor-angular", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "prettier": { + "printWidth": 100, + "singleQuote": true, + "overrides": [ + { + "files": "*.html", + "options": { + "parser": "angular" + } + } + ] + }, + "private": true, + "dependencies": { + "@angular/common": "^20.2.0", + "@angular/compiler": "^20.2.0", + "@angular/core": "^20.2.0", + "@angular/forms": "^20.2.0", + "@angular/platform-browser": "^20.2.0", + "@angular/router": "^20.2.0", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.15.0" + }, + "devDependencies": { + "@angular/build": "^20.2.1", + "@angular/cli": "^20.2.1", + "@angular/compiler-cli": "^20.2.0", + "@types/jasmine": "~5.1.0", + "jasmine-core": "~5.9.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.2.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.9.2" + } +} \ No newline at end of file diff --git a/kontor-angular/public/cross.png b/kontor-angular/public/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..6b9fa6dd36ee8165272a13dd263f573507c78ca6 GIT binary patch literal 544 zcmV+*0^j|KP)L-ku(! z6_?D-?!0+#=VtbVZQGdTnZt~apI_HPK#=zVadHM((E`e*C+RoFb)Qo8-U{Lb7{`Tz zw4B8FZ|o?Wox+p=1wp47C;7ar*Xu~;a?<=sjPv>+otDjJ6FaGt!YnNyxQQhp)G1V! zk;r6ZtyV)c8pTbiRAnHRNXTxti%=+p$4aG2*+mMM&xrdiU^`VPk^N*+HX98^7!HT% zwA%;A{T)GxeQ|RcxyzV%! z$AbYD+)i1R64zB?q}NmTz}5|04~J#YG_goA*Eq(QJvp7pG14hUj1pZ^t>3S*xqHUO ze~r;}zTY_XkZ*}d@gm!;N90h8nBQenBUZ_ukZKNicn*hc_Pmc!Jn|2=s<~}>!Sb>Qm3!QP46b_JFw5YU70Tu$X}=T}ez@@t%j iG9vD)nDux55?}x$+|UyQVK_bj0000g85YMFFeU*Uvl=i4v)C*qgnb;$GQ=3XTe9{Y%c`mO%su)noNCCQ*@t1WXn|B(hQ7i~ zrUK8|pUkD6#lNo!bt$6)jR!&C?`P5G(`e((P($RaLeq+o0Vd~f11;qB05kdbAOm?r zXv~GYr_sibQO9NGTCdT;+G(!{4Xs@4fPak8#L8PjgJwcs-Mm#nR_Z0s&u?nDX5^~@ z+A6?}g0|=4e_LoE69pPFO`yCD@BCjgKpzMH0O4Xs{Ahc?K3HC5;l=f zg>}alhBXX&);z$E-wai+9TTRtBX-bWYY@cl$@YN#gMd~tM_5lj6W%8ah4;uZ;jP@Q zVbuel1rPA?2@x9Y+u?e`l{Z4ngfG5q5BLH5QsEu4GVpt{KIp1?U)=3+KQ;%7ec8l* zdV=zZgN5>O3G(3L2fqj3;oBbZZw$Ij@`Juz@?+yy#OPw)>#wsTewVgTK9BGt5AbZ&?K&B3GVF&yu?@(Xj3fR3n+ZP0%+wo)D9_xp>Z$`A4 zfV>}NWjO#3lqumR0`gvnffd9Ka}JJMuHS&|55-*mCD#8e^anA<+sFZVaJe7{=p*oX zE_Uv?1>e~ga=seYzh{9P+n5<+7&9}&(kwqSaz;1aD|YM3HBiy<))4~QJSIryyqp| z8nGc(8>3(_nEI4n)n7j(&d4idW1tVLjZ7QbNLXg;LB ziHsS5pXHEjGJZb59KcvS~wv;uZR-+4qEqow`;JCfB*+b^UL^3!?;-^F%yt=VjU|v z39SSqKcRu_NVvz!zJzL0CceJaS6%!(eMshPv_0U5G`~!a#I$qI5Ic(>IONej@aH=f z)($TAT#1I{iCS4f{D2+ApS=$3E7}5=+y(rA9mM#;Cky%b*Gi0KfFA`ofKTzu`AV-9 znW|y@19rrZ*!N2AvDi<_ZeR3O2R{#dh1#3-d%$k${Rx42h+i&GZo5!C^dSL34*AKp z27mTd>k>?V&X;Nl%GZ(>0s`1UN~Hfyj>KPjtnc|)xM@{H_B9rNr~LuH`Gr5_am&Ep zTjZA8hljNj5H1Ipm-uD9rC}U{-vR!eay5&6x6FkfupdpT*84MVwGpdd(}ib)zZ3Ky z7C$pnjc82(W_y_F{PhYj?o!@3__UUvpX)v69aBSzYj3 zdi}YQkKs^SyXyFG2LTRz9{(w}y~!`{EuAaUr6G1M{*%c+kP1olW9z23dSH!G4_HSK zzae-DF$OGR{ofP*!$a(r^5Go>I3SObVI6FLY)N@o<*gl0&kLo-OT{Tl*7nCz>Iq=? zcigIDHtj|H;6sR?or8Wd_a4996GI*CXGU}o;D9`^FM!AT1pBY~?|4h^61BY#_yIfO zKO?E0 zJ{Pc`9rVEI&$xxXu`<5E)&+m(7zX^v0rqofLs&bnQT(1baQkAr^kEsk)15vlzAZ-l z@OO9RF<+IiJ*O@HE256gCt!bF=NM*vh|WVWmjVawcNoksRTMvR03H{p@cjwKh(CL4 z7_PB(dM=kO)!s4fW!1p0f93YN@?ZSG` z$B!JaAJCtW$B97}HNO9(x-t30&E}Mo1UPi@Av%uHj~?T|!4JLwV;KCx8xO#b9IlUW zI6+{a@Wj|<2Y=U;a@vXbxqZNngH8^}LleE_4*0&O7#3iGxfJ%Id>+sb;7{L=aIic8 z|EW|{{S)J-wr@;3PmlxRXU8!e2gm_%s|ReH!reFcY8%$Hl4M5>;6^UDUUae?kOy#h zk~6Ee_@ZAn48Bab__^bNmQ~+k=02jz)e0d9Z3>G?RGG!65?d1>9}7iG17?P*=GUV-#SbLRw)Hu{zx*azHxWkGNTWl@HeWjA?39Ia|sCi{e;!^`1Oec zb>Z|b65OM*;eC=ZLSy?_fg$&^2xI>qSLA2G*$nA3GEnp3$N-)46`|36m*sc#4%C|h zBN<2U;7k>&G_wL4=Ve5z`ubVD&*Hxi)r@{4RCDw7U_D`lbC(9&pG5C*z#W>8>HU)h z!h3g?2UL&sS!oY5$3?VlA0Me9W5e~V;2jds*fz^updz#AJ%G8w2V}AEE?E^=MK%Xt z__Bx1cr7+DQmuHmzn*|hh%~eEc9@m05@clWfpEFcr+06%0&dZJH&@8^&@*$qR@}o3 z@Tuuh2FsLz^zH+dN&T&?0G3I?MpmYJ;GP$J!EzjeM#YLJ!W$}MVNb0^HfOA>5Fe~UNn%Zk(PT@~9}1dt)1UQ zU*B5K?Dl#G74qmg|2>^>0WtLX#Jz{lO4NT`NYB*(L#D|5IpXr9v&7a@YsGp3vLR7L zHYGHZg7{ie6n~2p$6Yz>=^cEg7tEgk-1YRl%-s7^cbqFb(U7&Dp78+&ut5!Tn(hER z|Gp4Ed@CnOPeAe|N>U(dB;SZ?NU^AzoD^UAH_vamp6Ws}{|mSq`^+VP1g~2B{%N-!mWz<`)G)>V-<`9`L4?3dM%Qh6<@kba+m`JS{Ya@9Fq*m6$$ zA1%Ogc~VRH33|S9l%CNb4zM%k^EIpqY}@h{w(aBcJ9c05oiZx#SK9t->5lSI`=&l~ z+-Ic)a{FbBhXV$Xt!WRd`R#Jk-$+_Z52rS>?Vpt2IK<84|E-SBEoIw>cs=a{BlQ7O z-?{Fy_M&84&9|KM5wt~)*!~i~E=(6m8(uCO)I=)M?)&sRbzH$9Rovzd?ZEY}GqX+~ zFbEbLz`BZ49=2Yh-|<`waK-_4!7`ro@zlC|r&I4fc4oyb+m=|c8)8%tZ-z5FwhzDt zL5kB@u53`d@%nHl0Sp)Dw`(QU&>vujEn?GPEXUW!Wi<+4e%BORl&BIH+SwRcbS}X@ z01Pk|vA%OdJKAs17zSXtO55k!;%m9>1eW9LnyAX4uj7@${O6cfii`49qTNItzny5J zH&Gj`e}o}?xjQ}r?LrI%FjUd@xflT3|7LA|ka%Q3i}a8gVm<`HIWoJGH=$EGClX^C0lysQJ>UO(q&;`T#8txuoQ_{l^kEV9CAdXuU1Ghg8 zN_6hHFuy&1x24q5-(Z7;!poYdt*`UTdrQOIQ!2O7_+AHV2hgXaEz7)>$LEdG z<8vE^Tw$|YwZHZDPM!SNOAWG$?J)MdmEk{U!!$M#fp7*Wo}jJ$Q(=8>R`Ats?e|VU?Zt7Cdh%AdnfyN3MBWw{ z$OnREvPf7%z6`#2##_7id|H%Y{vV^vWXb?5d5?a_y&t3@p9t$ncHj-NBdo&X{wrfJ zamN)VMYROYh_SvjJ=Xd!Ga?PY_$;*L=SxFte!4O6%0HEh%iZ4=gvns7IWIyJHa|hT z2;1+e)`TvbNb3-0z&DD_)Jomsg-7p_Uh`wjGnU1urmv1_oVqRg#=C?e?!7DgtqojU zWoAB($&53;TsXu^@2;8M`#z{=rPy?JqgYM0CDf4v@z=ZD|ItJ&8%_7A#K?S{wjxgd z?xA6JdJojrWpB7fr2p_MSsU4(R7=XGS0+Eg#xR=j>`H@R9{XjwBmqAiOxOL` zt?XK-iTEOWV}f>Pz3H-s*>W z4~8C&Xq25UQ^xH6H9kY_RM1$ch+%YLF72AA7^b{~VNTG}Tj#qZltz5Q=qxR`&oIlW Nr__JTFzvMr^FKp4S3v*( literal 0 HcmV?d00001 diff --git a/kontor-angular/public/logo.png b/kontor-angular/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7499bdfc05ead6ca171fd3629a53959dbf059615 GIT binary patch literal 17196 zcmeIZXEfYh-!LjyB2`F`kSLK5C89?3AqYYA-bIfx>KKfcNJ0=KdK;n}H6psyi`aLHBC(1VPOvYGTb6UR--Kt{$wru0-s z$2%22Y3R=IEUk4To3pdBo}Y&=>!teJLiOL9mkj*>%25A%^U`~%GgCCzq|SV&xh8(* z?>wJ#>!RxC*exZY#?G{}@?UvS^D?GFidLxmvZXNWb8Fr z6ZLE7mfG8u#M65RF!NhJ2sgJ+=Ve&1YO>j1iGNxQTO{yk-h=fGpwm9Ya zH$q|eHWp;v;f#EVKbMA!deUwQ zsSX4*@|~EdDmX&@rj2hkLf<(*IB4AWt3 z?e88n1R7o8nh`SA>|5`~SQs9DWdRU=d;6OJbmuBL(<@J2+N~DL3AhpF3M|`wXAEMxZ4=g#PLBzJ`b|?B zMOWn?m)SL_I2Icf$HN}MDFNggytE!UvB|v)5k_i5+m>l!Vq%}1f2dL4VP|=}m*8B* z4cSb|wNGYO>Q9`)u~U_o_J6}Ls`i?ae|Dp!qSB=gR(AA14t%5(ZPGi>Oc~-JoHEp4 zQaI#*nwgm~y5oV=D;#={H}hXg;tQXt)~piuV+qiexj4pH?1_NEV$DoUVwbrh6tcDf zuJIn<->|q^Qkx{_+E-z21QIrztI~XIrP9M2Df@84gSwQ>UeE97g~lU?2LirCX7zdIZCvKVNfjxm*kR60XV6)&XF zUmOW&m+QtD-WYwvYROHb_ZSgUgXuaO~O-6w%r`#96N5v z^^$=lq0Gb-W`C~DH2dNRh_fahZhTaM`$SrqX%;v&o_emT`=!u>A?Nn+k3!uzxwy!7 zOK>3+hD}S3fK+>SwDV{2N2K~Bv3rC|oBqD;kDqVj6L5kS1kCvo*2*v zI|$uI@l)iaXjNYY(#je3u!0>oBVs{U4RnE(K(H*+(4>tsi~D`h6{y1j_}#`kzrNnL zmn)!q16j}J6aM)Uu`5n%X>2U%(*n4D1LLJtdVS+&h9_-mY?y|f)zvQ4y@sN;^@>?| zj_NH3k)7K~59XCoFiBYBsE{ns%h7S<3#(6JLwzNRZpeSg|R^HJ0bUs)xLOWW20=e%MsX36?O+v#)2u={Db3@^l>kD_j~;%n497694d@* z*zdoy;B?15PPw=+{5twcdT7Q^uX^jRh>(ijh%K^1(xS152KKe#Qi4 z_p|Ys0t#ay0zHmNLHCsG^i&MTsdtyVjVfamv0=-=+Y)epu0N|hDYr7SA&Q6B)m+|l z4`RtLj=<>b--|;q1OB)F^}>=v6lLi=Ei7|`WC@NjBuntI0_BluJoZAvlvdfvb{ z96@48Ld4BNn`pF!`P9&6-EQP>5ijAOPwat~kE!e&`VXz_6s-a3sClzvve3&E4xzUW z&}Qo7GQS7AcE7*Su)on_EeH%7=0$jzV}(&>R4=954mF@-00%|W_Uvr-u5agY!0FFg z*OW^^Py7rXsdi7~#V!828qx&grx$%Jgu%nPAsjTU_t~Wq`c3NIO?xb6G>Nv;blH|C zE$<*I?ku_?5Dx;hFeB!H(Aig1p>hVm@?8%4I|+iB5iL0qS1fwm$P;Pxt5rXY88O*h z`ap4u)j!f3iQd3`lC(nX@27b4QbWW?5DOOcddyHan@%ITd6;69)~W$e*W1a@qL@S1 zkWxrBq-ebyA}P5Y`t*Lhh^IKyMyQqHx8b<(&)mK82tkwNcxmZZv60?q72izDUat~+ zj((Z#yTI;D2wFb8mV}Br|9ob8Zd8;`{V@Tp#o7g;RB4SZ8jk%bZS1+ zWC^Ly6Tq%dzqdKoRlQrgsz};EeNKj_e8~U7v|+aIlU(A@5?_>2G~3ckA!-6re{xcN z(`n1|lYyrIbJXefsa3VRn1=RS14V?>>doNl4HF-}L-a(BI2^``(h+P}#Jc<)5tVi6+eVJqwbp0dwV(!in8+ z(M!k>i|WlF*MtTdMi557f0row!ZOBGl3Mcs>ywr3=TNHLe#CD zTkB9^P{@ghw81|F%8_6np3^lBE{8o;uZ$dN#1Tdg7}?fjF35ajSJJBOR*DwY z&(01WAJ~q9totF-VBbl5qNsiD6Yrl!BCCm6XU*qleaA{*})9=`JU>j*4j+g!~ktY z(HoN=FE1+})hIQ;lQU4+?I|~%T5eE8`HBi(3{q~HXgR*A;uNN>Cwvz^!~>x-=g!oc zdjd$KQ)5@%&P$0>a@lhDn!qVW_j&EUdDgG|e);flZgIBCMb!a3%~W=8Ifo<21ua=B z*(LDfd?kbH^MVZMt=b{TEfCJ?EFX%!1k*b zuV;RjpHykZlLOH~-p5g_b=8Jm1Z;~xzC8l?F#51!zIBj)Z7k?L%T6drV(y3?oqnvk zf}|K(f<5TQdb#DBx_A4)-O3%3CN_(_rkzL<{d2gVZ6q>E2&uauG15Kj_)u(IW5n)0 zMH7hX<9P#0O0wdOJkm@jiX`ZM5D8@J_W;)XmF)c=6j(PFY#&i`eB^lqWFwg(0hwU> zOd(4%=f)*oXBJk-V1sjPZ_6i&uYx2+uv+PyScqUF-D~Yw5t3dj#fntpV4@7k!7NRy zK-&%Rc(^Zq=FuQFAE08O7{^!VIlontKr@@o9%Z8f^5A%hF%{uL^eSM496p+%ZTs+8 zh@z>YikIHOMF(K=@Tns-CqGJol~6LA1CBZQ5t}@ruV3oLPp^~AJw2^aH)zMN6dlo$ zYKV^r2efS&r4Nvnke~@P%e{xz=~lSD?SuCLQl-;%Uo8-GvwfeTSkDpfa1jW{*T(>d zc$(I-jbaP`F&Q<7O@p5>f{A;c1cp^a=34g5Ms+`VxMS4^CuGydXQd;?#$Bd><)l(X zcJNz^mwrkqRK#I6b=~q`XQOXBms;I~0W}(7_f#$sxf9jO5VCJN;S@3p)L&8cmk|Tc zvT8aT2jo`IPtK6-b`xP7cY5%6#jqvADVx&Qjj|dS>>?o2ApJnh94NwAh2ZXUG>sXQ z@;t7CC{eGZk1fHBP-M06DIYl8cAbgSc7V|6NGFv|a-HWa5icw4ctpRqtwX7u*LglCUt;vT3LGiisGp@dc zLj^+Ddn!~lO+?eYm_`%?6j9(p7k|$B&$3Tyi#)!?r4;?6ir>j(Pm!mwTx=q(dq2Nl z!pnYoK6eM(p9~XF6IQ4{^Hel9ymqD2R7DDxS;gyg;|U7#H_m%Zt}lGa{8eledqL)~BV7LL`Bu*~A;g~D!20bgc6 z>_Say7w;+nNu5^w8X=+Lx>JCg?SthFa2?4*v)UAyjvYLzfpsX*B247mwO%TIH{!PO z>b8~`U^0jhpw{P){G{jtc?&Hag54@Fz^_*#BVBi}*@90qt$vnMXRo?KOxT#2G1{M`ey0;mn0fZhDLi&(d&%TiGjSa*mJs z-lhyuQ&ljEM1fF^P)|AvFO(BsI3}v?$4@U5&|Op5BAK#v_xRviT}|PuR1i3V9m-re znVedhv|Kr{%F$0jyarOH`zckLg+qdy9tXz_;3X3i)7**3r1MCdRVj6FMnyWBl;|I9 zfqft>h9I`{2OFiOr5jJ2ltX6>kVs@`r9~X527&KE-J_N(|1~M2th91qa=mu$9pbPu z&;_@t;-D?9c})Q2@$WWD4vFS0of_cpA+O|I- z_|(NY2Z1}3A+%deSLN2$jS7dfWUlF)h>i7u1XS4(xq=%_rO1ozay^`BjfyxfTJ`4= z{O&pif^r_=U!6l1yIWfxH{?Gp@?2~qMgPru1rOhJJR}&VdF?esX1oX;s8iw9Um+gm z_%1}#Oqopf48^H>zJCey@O@mOkuMexFAcQC-gEGUGz{)9522Sya-hwJzz_8;J(K4U!uV2;@Qd90%q0 zVrh|I3{F)TfS{-P+whsucFUe)_piLGbCi5>lb%k7l`eH!%Lv>7)QLcmr*l%7_|4$q z1A=Hg4^cu)jBAGg5+P`383?U)fvuh^+XRX1gGj4g>sEzn{Tpu+RcPfE5VD;TnRA9G zwp%(CbF^X|!?ZNSUa)Ve+jSWMHANo%ye83p3k0W@LhS4xczShu>yC;eGc>fHZ-f;f zP9-JWD_5_+rBQ`rn2Xf-wnRKAj%)ot9p0D8(Jc2H7!k4iN2EzxNh z!+Ulb|8c^>;*I|t}d$??O!7>Rkv4&+y2^Ai%dgNp(;X^hdlIKCc&DCi+Mx$%kCf6Ckn_LO zFQ{LFb)elX?~#NMz0!4ki# zsgO#1^r4|s19QGpz#p#QO0974nBLM4U-8|PFSwevHR^`NA!1@~4q1s)u5Ih$0!)Cg zT4K3ybz>}tq`G=Z2`hJwntq|+>LeciTy^@9*x;JwUEuX99yYN`khq{F#vYuNAj0Pc z6-*7qT(XHpzX0ZLFzl?h9NvOnT*Ma?Bfmnq%l-k(j(E{&Ug?8~_guxKwKT6D3wG?X zb?){Q_B<067k6J{7JHXENKXRG<+J9wpt;QwFCLX^~vLT zALnfLnycuQ+r7;E3OosZ&vDsZo;&;hbl+Us)rP)u*Zy3rhH$!MyioGsoiM979M zW@PuP#t)Ub_$oLAZV0x*6g0D?4p+-%Pjd&BXc0x6VS_LDImdO6trtq2{{Rw1j z-f=)oK=lld%;jI6D#)#BjbP*XksR`Rm=?UlvF{LS9B zwRf#i^;JKhME-`o6^H?ZXc{|KI4i8uRur%`SlwiQDJ%M52=qzbe1C-%p9Kzu>o(0JWO+re zk6j0yDL3>UwQ<8u!$32bz9>x=qgHF1aLWt+7yT2F!OY^fIU;8|VqV*pkL|FP@KaQs z9JgC*IhewAQG=xL(sI_bdxEhd?#!!D*^lX+oV> zjlsjGYm>?ke?4$Nl_V@G0GXjrc>~gRU0QjEG6VX3A1Tnc`~KpIx_^j9-!D$~;WX)h zBLh&z_xYT0jC{gPz_6CV z@vVErfR%|V|D@&w*I$PVJ_~}QMtAv{qd>nUM?DxrZsh3c=JuUkNJ7?cBK@PJK*g>J z>WJ90g01owlPAiTI*23Z9TJAcuQq+@Q+^|^cCGMmrxq&7Ea7h+$WQDtY`me^m1i*>>M5!Lp#>q&@CaKo6+(Bd75bLvqifZ z6OVIt7tH574rM=p!1ArrhvD&2y;9ZvACKI8Gu}(~iiBm#vNBSKjLq&pw4sA{k_U*> zZ$0@&M#ij1ngu}SqRse5pcl09A4i8pJUl(`pO{@E#g2Cww5{KJA^%7aujzZ02{TRy z%vSeW-AyjpNoW0|@)?B62g$hm{=bxqNTGp~3RcMp(@?+pz+E&nV(|FBG;>r{CD+BE zAH_s)C0*QEA6#_@1GWM|)x_oP1b*L#uAnl=8?UP8Au2YFhW^-4j-i%8+K zl;a>Dj8RpgRRI-&k+1EpswM@)&5BOu#v@$;TA;*dAk*7+?k2{psD>spVOdR1eziNUh=9S-Mu?_pp4w4QX&-1k%Co0Kgmfq)|AKL;t# z-Er>al~frWOmnJ6xA9!zbuP?XGbDhH?U5Lb)peIAR$uK!RcgH!j8&jJ$qBP42g6O1 zzpaURs$Ic2VH#7%Zmo)B;L`AQ=W>_kuSoQ#@^_+NspdUb>QdV^oGf?Av9no#7}rla zbLVuW#--W8eLoRp5bs`51+ldGFC&#a(^oG@a4wQN9Z>skFKR~cY@`g=Zmx)d_RB(g zVA=|S_vV$y%u(DBGhH9vi+p^1rQu&f`F=ymO}TPFqrl@-vOUXIQx%)#IwgF$R>ov5 z*~0Q$RvTUH)2PKtNyyqY=Ae!{`$q;9WVx9L!^!Et@ZFaxR|N z?Ca+2=Qdf`fqwTh;am&}31K+(D>InjT*RE52ygdH3Nc3w{raVeXH@{j+5_(|Z-Sh! z>DLT_ykXYUNs9{ol2EVM>w|=nLnxXi2u)7HS)Um|cm>_7WV^4h(APZ!6a!F} zzioK@h(m?LodXYxdn1)W4JNOE-p{pS z^!Sa6_11bf_V@RHhM%Qf_#w}p92(?IkKW!~HtUp5Qb{!sK|_5^;lC^_#nQDfSH$xQ z+LP7t)Fv*=ZfW#g%?dFCvkba#ub{VBE>;HEehrU=*Fk5uDwcde>CLy|=iJ==rlxp) zzB4u&eOKDH=H#i+srQ=dbE`G_!Y8Cf%2L%)-RU#;B$_l~t5d?~J3fD=`?!$sff*qt zAMB&*Hf3g$76gj^5vJ>)(-0ArMD%}wy8WB^a;?R7UpTj5mtz<=krTLN8sJpMLp?QV z=h9*o1**a$&j3&iKM#IQFH60b=Mo9V#EqY{KvKG6wdUiufbT9rUNo5Xe<7G^>gh#c zvhV-oG41wW)gjKUC6ra%75>48F!64GYGbn%;CsT)#}|yX_CPt`1euYUTh8COHUHQ~ zI7O_?L>1*HSLitr$@vxe5bbeTur_2)i-QJy{%rjBU7mdw(q7I5` z6We{G0tA!3=yVGfd*bP8>hr)-y1#Xc42>K=O~Lio=;rtPL8pyav*t6&yC`27ljG%_ z{xsz8xa-_Hax#1@1l@;_ZNFvgEj82#hv8#Xh}kS5E{^E$x>T{1)Jz~JpQNINT`_Qv zjzUFfg}I_w=C}rh*$uG`{N0CA+X#pP%0Yv8yak;9%FK5_Me;5fu4k}jLB2+C0^|fi z&NI`lHJl+9iN5DvO~DVt>hI*bo=)7M-441L-ZI?SWVDT6mLf_Hd}FS~^AYP~sDY~8 ziZ6cMj2FLLD-9I1?B*l|C^Lhw$a&)929Rgl?FCaaGwdFrK4xn4RtYn8BONU)P@|8> z!s`7F8>OXYM=|iDo2+6!AzpOhX{ z`y0OB--&uJ_&)wS*}R|4I>oQK4p2EJ?Yrr4M>wj}UN;||o0PH~x>lkr~F z$adGA_cI38I#EGubeC)IJMoq$H;-?PIn7Tr-$7kZb<$#K!aIWzj_W=qmut;A7xN>U zWgaTmj7cQi{@%{(wCQB_qsMjUWfg`ykPna|UGILPP?E~+s^zmOntePd->N+JkBQq^ zwCFC(W>4-K@z8I|IJd$KBSF|f=rumuL$6bjPu^S0I+a;wxvAf~7JuMG5z;iVMQ_45 zwys(?X?AG%1;W_lS{KNG1YaE0S? ztvv0vw4!Qo7Tsn@yLGg0H4z5E+$-~Q<4eKD&UIc=Nh;of5P6xZ z_epCi!N$)lwM?*Pcj#o{p5n*~xstweZYUC*iu2 ziShc2^IlDX(@p18l{Jq8%WfIs^>eSqArRBUg@lBJ zky8J<$;#nKwLB}lT@w??_EnW{^+V$o^9BSa8rxcT+Ff;}o>khQpIQoM{d$RaOk-=0 z2rb{*pXl&?PVf_vr9z*ttN#AsDIvApb6ESR2J!$f7n1SPaj(sv^NR#w2gR!%@=(WbCkG?WCQ8N?oEWC;<5WrjGqdG0_ z4e?Jn_q4RM{8VxcZ<$sPxiMx`Ae_=|P*7>bx%hbOUD6uqGC$B;4xEd&VBQUic6F)3 zi112P3=hMDvl0pH8x}$AIjaZDm?kHw`Q_z~bzq@X>rc5WF29H~#kTiZ_w@8sHVhX! zLq}`nJ$=tZ#v=OU`0`gj))AhezPk7Z@G^~R?{0mN2GEb~>5nVhtvB;Bb~wX|iZ7Pc z%rH*K%anfVCH_)ZQ+vvsFtzJI?_8QY>FmNYKjyzRmt%!dGb@}vI!e7#!6Yxkm)|kV zZGHuD?cBXyJb2medZWwsky+#AX;EzTv%^hX9s14G(h@4}Q*w)?48bo%v+qj5Ci&t@ zvnZ-vWV@#@!^_N!v9$&LN&#SV`f2{igUFpPEc&zi}`-Q`JN%fgt*)m`FvqwD44!v!J_ zu-p_ilHSW1b|Q4inV;SOlQ*?{0AFRljJTv5x#(13bl&(L7*Y#`vNieta7ZLK{Sa#D z>`2)S%8g0tL5?IPd_EK*<2N>9YRQ@;1RZX`7f%29=u0aPDH$V;lef*n@y>%|$DMX5eAi=iEwoIO zblHE}7c)RGrVbnr%+;a_Hpe!mHcW4}x@C+lng<^5L|n4Z%gbAyp8m0H{j1&D5^8l@ zD1A>?o<`gA*poDbM`?4f;*$yuXu9l-p~94O3W3csS_F}$=S_J{o|vbGE^3t^Z;4PD zN?Oy`*PrgqP|1diZP_OpZ0_kq4jp-f^;oM9NQaRk^>!(`!J zSL{#XB@8|2LJ-x~PXuAiW(?hf3H*W7@{B77WPnC^*lcd*Ns;t3<#CnpWc*-xwk4Gw6iRQWZ+M&R(~Y;xaZz`|`e7o71;gdqmz(x0 z6S`dG{)OC}^Ua`x-?x`&5G9q~i#*85^)fS8F}dbEvn8)JY5XO5cKV&9J?zhtTDs-_ z1YY#kfmZAOCNH)hmCSPSwoj>~oB+p7P-x||{6XsBGAj>B7&?yeg5L5d^Yu>w0l6N2 zeiNf+KFMqI@3>L-r?0NxI}X6L@zq{2{;s@(fFD2a8J-f6VoDls_MGdCW*gh@6)U^F zao+p7Hss+_`*W>lzH9CTKQZAjL?eza&`ejGSTiHcrZhcQOf?N!oWJEkD$??wJjNdzVI$A`KFbhPrH_IwvCzYW`iI+@OBNR!1(h^Ifj zSug+QQwK27Qy+#pE3({>nPBAAz%7xO^0BVB)I2=rp>JQXwDJeZjQ^nhXH8 zFmcqH9dw@=^D1(^uwTx}{2qdgafa2?o2d_s(4i>G{;bUXVN*mG1oc|G|dT?4yp(yB2LBhRqT{DRSa#oIF-t4)YR&$)zd6)O1NeN50i)G>e@%R6WMX<80NMY_ zrc|H!Ua=ksQ2hs#;S4YXdST}D!Io&YwMT1ue%!P62M8jBS2^?zIHwBrRiI69;1L$I zVh=42zmTlok^c7!DS!CM<$31enARO?W4%YED&JuKt%j5bxjqpwCd*>YLoa zyX+G}1|mKQw=(lO=}SQ@U`l?=foWebctoj*75fVL9u+eh4?1$iczJ6G=Mo>5O=)q- z`y*#qGam)i(i^$=5gm9+HTW4vC1!m*#Sh31_6YR&T+EFP)8$aR#0oVy zq)5)|)v(dk5V;*N0Q+1d=Ucn=^p25D0?1wqfEfj?)f(c9GJ|~Qs!nnD-#Ab-Y+IS~ z(&i{1;!&aw7Ijnshk?a&-NkD{j!O~8Ca`~gPoqVerlw$v zwBl}oC`Eq*lgZMJ?Ccax$W@dbv6*Z7?I43~jW1_d<_aS-bNs=rvH0XJ;S%0Rt06p` zG~W)>E=p2i2Se|L0gb&K7oJ=s_rLJ4)T1XF&{-#@eHOv9?1s%?cz7L`lWx@EdQ^@61=z+d? zaYdWjYtZKg&5V`l?w42lC}?4SyBU_5W8HW$o+Yb&$6%Zss0|p;W61D6+bu71;r7~Y z{d>=7Hj5v(e+yg|2Q}Dg)=BVFEe$4eCNeTAjlMHv>tz4)?|;x?BF>rY$ZMg82^8+V zW=@IAL)>w>_9cNSxl7}Xb&ZXsW(|IZ`4BHc!^vo)_r|>u91erg_F8jl*zG>_i$xr# z?h=VZ;dFfNrzwJAlD)cwU(l4anM$I)i;FrQk4Nd3niU`K7n&_(67ZGqqC*kS`a7?n zv@iqW@9$@KdL#%FdxAI|PG9=;s2s65+y0a9*99u(d^$ce;7jyQ_5)8A0t;Lk_7#p# z4hhDXjkP*L0hQF=6B2A8)gh#W*Wf^&I%q91VAip|1k{^1Z&prw!f@_oJ_p+}4QkB18r|6ZnQE>%4|QUm`PLZz|-+J4Ym`S1}cGr@#yAvv6RyMj*KO zr~TQmQe0JXdbl=Ow>;OGAaZg-#08e7Ne4D;;-vldH0~>92JFuz#08dA=p7y&F1N>U zIATr!PWe$%2a7))%K-hr>Jl(%b+9vHJ|evlh}rcq)N4IFGZ-2a2`(4TVE)zD*LOK9 zN=oZa;8EEDK(9#prc=dKN*&*Z~?~qgoe|TLx$7igvKKqtJjrtV6+0gVYUjW4T$p$ z0JIbO-IFvbQPLU%}<08E=#;3Kqz(=B6M z8g)r%zM+!(vb*QCHldmBw;4)8)|oaNaM4dnU;1P(>tJstid$Mu?`VE&KO$|1#3?}V z#>&LHhu{o=1}gAmD}8w;N*aq;VU4QAQhj!&g}qlA&_R1|{6NTz7!~gOHSC_?sicoS zV*^k99isp;ghIRCv|^?bwdkjS@9OCN`IILmhE8OyT0YP-_lZ_7l3OvMDiAV(`=PrYva%j3V9>eEa z5kTe+qE7dyJY8Ks9`4wOE%c`2s(a1#kc0~w9H+c&+hnV2OKQr71MkK zLWis{pTz{f&{ut7JO>Eo5EvLZgX7}vRXIxFGrxUH?F2~YAW32YVIjag+9wwPq)>V4 z>GR1tdV0yZ#&+%cNSPDBS=Lg`KZjiwcW`rc{R}psS5DOibdCXWYiwEV9(~i_UoGzy zKEVLhB&jE=&WqrjIvd-)TzR**tG!l7+%uhDyNQ~YA^uO)% z0Rt>U&4!q5=Z^x;@~3WbwK%HJytJ^vd*ByeEtp_{cp*uA@iUFbyBG%-m)>zYZ#aRN zmmXlWzd#ZJA^}&md2qCgaajhP!vw^}^t*%KZ>WlHY~un?O~Ex>@aZ^kw}X3GMNqjp zAEkynuT(#9efI@@3!vq3F)g6cI0#gwD8T0wAh%3Xa{$zQe}RfwQlmEwQYd-F-^IlR z+PekB2q(^F*3v6|T7>l{PR2D264xdRP5KD9#!{f(cC$g*Bza~aXTtiP9Mu5TB&iL0 z<9+}E3)xx9OD_PI@?Xj2*R4nFDEkA}FUP1$X@aqZk$0XzM*KJ1IhKp7u;bNJ%4R_F za}Tx$)Q1iUje%KTuxMX>`{LrAo;U=AdYvT3Ayjv;izpIdmZzFRNa&CJG@TwMiJg(- z&PMBD^n^6r-Pl)h^18#ZvpTG&zGShYg_2^fOnWQZn$wkV}U0T1{=xU{#cg_WZXjK$K%&fXcqL8xowV6nG`aOgi)=i~G8^5XS+#Ova2$0q=~4Sf89e1d{JUDahc^`pk-h%cYDi!LwEMzwfOVKleC2wAkAlC?ZGF& z%TKx%3yb7G>&0cPJxGuL9HMRG_UGZBCnx(qC%IarHz0n&tu_7)|S>n!jHv-h5ilbpDq6#jDjVA@>uY(AXq9OBp@R8Sd{?$26DJ`#1E?EfLkpND@@<=;F0A=y6*|AQ_6_gQ6a^=~%0 zdb&IP5dmu}J{u<+sEsp>#3X@#G0ECW9A*!5viUC-$vDCOJBxtqi91<1+d(+Id8}=0 zEj*oI98$`%{|7w&wN;YuKcN1itYd4K$mX5uyr2F@fdffp{&DSHtl4|Bn9=ukpCx`#%PTUr-D(@b7;C zhJXJjrnw{;1KBM=6&|E`fsNrGL!Y6%zUh}QUl`(@V)PmQFtotEKmafTHP0uP}7&%m4pcKQ#X)BiAJ2y+PrtBI>9eEIt2-_c7)?*Lsf z5vX5*Af@m-wBJRV%#Fiz=BdPr0!2^a2d-yv7gSU);Z6{`~Oy?E5qSnHUln4*Y%!){F!Y1~5WXoC44g zb7l_)X~q^V6MmWR7e3wj|L|Wb!|^}Y86N$^h+kv_Kw-fP!~#If$6(B4$)LlK#&G6; zC&ShMSAb$5tA9Xg5dOsg@-z^@3;;QS9f&!gG&3|;{Da~@Q2ZB({s%XJ5&#fj0J|In U+D>(nEdT%j07*qoM6N<$g0@&8X#fBK literal 0 HcmV?d00001 diff --git a/kontor-angular/src/app/app.component.css b/kontor-angular/src/app/app.component.css new file mode 100644 index 0000000..6e5ac82 --- /dev/null +++ b/kontor-angular/src/app/app.component.css @@ -0,0 +1,9 @@ +h1 { + color: blue; +} + +.app { + font-family: Arial, Helvetica, sans-serif; + /* max-width: 500px; */ + margin: auto; +} diff --git a/kontor-angular/src/app/app.component.html b/kontor-angular/src/app/app.component.html new file mode 100644 index 0000000..604f43b --- /dev/null +++ b/kontor-angular/src/app/app.component.html @@ -0,0 +1,10 @@ +
+ + +
+ +
+ + +
+ diff --git a/kontor-angular/src/app/app.component.ts b/kontor-angular/src/app/app.component.ts new file mode 100644 index 0000000..d4b268e --- /dev/null +++ b/kontor-angular/src/app/app.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; +import { KontorHeaderComponent } from "./kontor/header/header.component"; +import { KontorFooterComponent } from './kontor/footer/footer.component'; +import { NavigationComponent } from "./kontor/navigation/navigation.component"; + +@Component({ + selector: 'app-root', + imports: [RouterOutlet, KontorHeaderComponent, KontorFooterComponent, NavigationComponent], + templateUrl: './app.component.html', + styleUrl: './app.component.css' +}) +export class AppComponent { +} diff --git a/kontor-angular/src/app/app.config.ts b/kontor-angular/src/app/app.config.ts new file mode 100644 index 0000000..5c2022a --- /dev/null +++ b/kontor-angular/src/app/app.config.ts @@ -0,0 +1,13 @@ +import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter, withComponentInputBinding } from '@angular/router'; +import { routes } from './app.routes'; +import { provideHttpClient } from '@angular/common/http'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideBrowserGlobalErrorListeners(), + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes, withComponentInputBinding()), + provideHttpClient(), + ] +}; diff --git a/kontor-angular/src/app/app.routes.ts b/kontor-angular/src/app/app.routes.ts new file mode 100644 index 0000000..631b87d --- /dev/null +++ b/kontor-angular/src/app/app.routes.ts @@ -0,0 +1,26 @@ +import { Routes } from '@angular/router'; +import { KontorComponent } from './kontor/kontor.component'; +import { Auth } from './common/auth/auth'; +import { ComicSectionComponent } from './kontor/comic/comic-section/comic-section.component'; +import { comicRoutes } from './kontor/comic/comic-section/comic-section.routes'; +import { TyscSectionComponent } from './kontor/tysc/tysc-section/tysc-section.component'; +import { tyscRoutes } from './kontor/tysc/tysc-section/tysc-section.routes'; +import { MediaSectionComponent } from './kontor/media/media-section/media-section.component'; +import { mediaRoutes } from './kontor/media/media-section/media-section.routes'; + +export const routes: Routes = [ + { path: '', component: KontorComponent, }, + { path: 'login', component: Auth, }, + { + path: 'comic', component: ComicSectionComponent, + children: comicRoutes, + }, + { + path: 'tysc', component: TyscSectionComponent, + children: tyscRoutes, + }, + { + path: 'media', component: MediaSectionComponent, + children: mediaRoutes, + }, +]; diff --git a/kontor-angular/src/app/app.spec.ts b/kontor-angular/src/app/app.spec.ts new file mode 100644 index 0000000..9834b5f --- /dev/null +++ b/kontor-angular/src/app/app.spec.ts @@ -0,0 +1,23 @@ +import { TestBed } from '@angular/core/testing'; +import { App } from './app'; + +describe('App', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [App], + }).compileComponents(); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(App); + const app = fixture.componentInstance; + expect(app).toBeTruthy(); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('h1')?.textContent).toContain('Hello, kontor-angular'); + }); +}); diff --git a/kontor-angular/src/app/common/auth/auth-service.spec.ts b/kontor-angular/src/app/common/auth/auth-service.spec.ts new file mode 100644 index 0000000..ef933a9 --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth-service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthService } from './auth-service'; + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AuthService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/common/auth/auth-service.ts b/kontor-angular/src/app/common/auth/auth-service.ts new file mode 100644 index 0000000..27d9035 --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth-service.ts @@ -0,0 +1,55 @@ +import { HttpClient, HttpParams } from '@angular/common/http'; +import { inject, Injectable } from '@angular/core'; +import { catchError, Observable, throwError } from 'rxjs'; + + +interface AuthResponseData { + kind: string; + idToken: string; + email: string; + refreshToken: string; + expiresIn: string; +} + +export interface TokenData { + access_token: string; + token_type: string; +} + +@Injectable({providedIn: 'root'}) +export class AuthService { + private http = inject(HttpClient); + + signup(email: string, password: string) { + return this.http.post('http://localhost:8800/signup', + { + username: email, + password: password + } + ).pipe(catchError(errorRes => { + let errorMessage = 'An unknown error occurred!'; + const err = Error(errorMessage); + if (!errorRes.error) { + return throwError(() => err); + } + switch(errorRes.statusText) { + case 'ERROR': + errorMessage = 'Uups...'; + } + return throwError(() => Error(errorMessage)); + })); + } + + login(email: string, password: string): Observable { + const params = new HttpParams() + .set('username', email) + .append('password', password); + return this.http.post('http://127.0.0.1:8800/api/login/token', params, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + } + } + ); + } +} diff --git a/kontor-angular/src/app/common/auth/auth.css b/kontor-angular/src/app/common/auth/auth.css new file mode 100644 index 0000000..3b9c625 --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth.css @@ -0,0 +1,8 @@ + +button { + text-align: center; + padding: 10px; + border-radius: 10px; + margin-left: 14px; + +} diff --git a/kontor-angular/src/app/common/auth/auth.html b/kontor-angular/src/app/common/auth/auth.html new file mode 100644 index 0000000..9511125 --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth.html @@ -0,0 +1,34 @@ +
+
+ @if(error) { +
+

{{ error }}

+
+ } + @if(isLoading) { +
+ +
+ } + @else { +
+
+ + +
+
+ + +
+
+ + +
+
+ } +
+
diff --git a/kontor-angular/src/app/common/auth/auth.spec.ts b/kontor-angular/src/app/common/auth/auth.spec.ts new file mode 100644 index 0000000..fb883cb --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Auth } from './auth'; + +describe('Auth', () => { + let component: Auth; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [Auth] + }) + .compileComponents(); + + fixture = TestBed.createComponent(Auth); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/common/auth/auth.ts b/kontor-angular/src/app/common/auth/auth.ts new file mode 100644 index 0000000..b9f1fde --- /dev/null +++ b/kontor-angular/src/app/common/auth/auth.ts @@ -0,0 +1,55 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { NgForm } from '@angular/forms'; +import { AuthService, TokenData } from './auth-service'; +import { LoadingSpinner } from "../../shared/loading-spinner/loading-spinner"; +import { Observable } from 'rxjs'; +import { HttpErrorResponse } from '@angular/common/http'; + +@Component({ + selector: 'app-auth', + imports: [FormsModule, LoadingSpinner], + templateUrl: './auth.html', + styleUrl: './auth.css' +}) +export class Auth { + isLoginMode = true; + isLoading = false; + error: string | null = null; + + constructor(private authService: AuthService) {} + + onSwitchMode() { + this.isLoginMode =!this.isLoginMode; + } + + onSubmit(form: NgForm) { + if (!form.valid) { + return; + } + const email = form.value.email; + const password = form.value.password; + + let authObservable: Observable; + + this.isLoading = true; + if (this.isLoginMode) { + authObservable = this.authService.login(email, password); + } else { + authObservable = this.authService.signup(email, password) + } + + authObservable.subscribe({ + next: token => { + console.log(token); + localStorage.setItem('userToken', JSON.stringify(token)); + this.isLoading = false; + }, + error: err => { + console.log(err); + this.isLoading = false; + } + }); + form.reset(); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.css b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.css new file mode 100644 index 0000000..c34bfa6 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.css @@ -0,0 +1,5 @@ +div { + border-radius: 6px; + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1); + overflow: hidden; +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.html b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.html new file mode 100644 index 0000000..b702b13 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.spec.ts new file mode 100644 index 0000000..19737d5 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicArtistComponent } from './comic-artist.component'; + +describe('ComicArtistComponent', () => { + let component: ComicArtistComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicArtistComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicArtistComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.ts b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.ts new file mode 100644 index 0000000..99a7938 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artist/comic-artist.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { Artist } from '../comic.model'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-comic-artist', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-artist.component.html', + styleUrl: './comic-artist.component.css' +}) +export class ComicArtistComponent { + artist = input.required(); +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.css b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.css new file mode 100644 index 0000000..d95c44d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.css @@ -0,0 +1,14 @@ +ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + gap: 0.5rem; + overflow: auto; +} + +@media (min-width: 768px) { + ul { + flex-direction: column; + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.html b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.html new file mode 100644 index 0000000..1bbc4f3 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.html @@ -0,0 +1,7 @@ +
    + @for (artist of artists(); track artist.id) { +
  • + +
  • + } +
diff --git a/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.spec.ts new file mode 100644 index 0000000..dd0c4d3 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicArtistsListComponent } from './comic-artists-list.component'; + +describe('ComicArtistsListComponent', () => { + let component: ComicArtistsListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicArtistsListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicArtistsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.ts b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.ts new file mode 100644 index 0000000..44e22cc --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists-list/comic-artists-list.component.ts @@ -0,0 +1,38 @@ +import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { Artist } from '../comic.model'; +import { ComicArtistComponent } from '../comic-artist/comic-artist.component'; +import { ArtistService } from '../comic-artists/artist.service'; + +@Component({ + selector: 'app-comic-artists-list', + imports: [ComicArtistComponent], + templateUrl: './comic-artists-list.component.html', + styleUrl: './comic-artists-list.component.css' +}) +export class ComicArtistsListComponent implements OnInit { + + artists = signal([]); + isFetching = signal(false); + error = signal(''); + private artistService = inject(ArtistService); + private destroyRef = inject(DestroyRef); + + ngOnInit() { + this.isFetching.set(true); + const subscription = this.artistService.loadArtists().subscribe({ + next: (artists) => { + this.artists.set(artists); + }, + error: (error: Error) => { + this.error.set(error.message); + }, + complete: () => { + this.isFetching.set(false); + }, + }); + + this.destroyRef.onDestroy(() => { + subscription.unsubscribe(); + }); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/artist.service.ts b/kontor-angular/src/app/kontor/comic/comic-artists/artist.service.ts new file mode 100644 index 0000000..a755f91 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists/artist.service.ts @@ -0,0 +1,47 @@ +import { inject, Injectable, signal } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { catchError, map, throwError } from "rxjs"; +import { ErrorService } from "../../../shared/error.service"; +import { Artist, ArtistDetails } from "../comic.model"; + +@Injectable({ + providedIn: 'root', +}) +export class ArtistService { + private errorService = inject(ErrorService); + private httpClient = inject(HttpClient); + private artists = signal([]); + + loadedArtists = this.artists.asReadonly(); + + loadArtists() { + return this.fetchArtists('http://127.0.0.1:8800/api/comics/artists', 'Someting went wrong fetching artists. Please try again later-'); + } + + loadArtistDetails(artistId: string | null) { + return this.fetchArtistDetails('http://127.0.0.1:8800/api/comics/artists/' + artistId, 'Someting went wrong fetching comic artists. Please try again later.'); + } + + private fetchArtists(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => resData), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } + + private fetchArtistDetails(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => { + console.log(resData); + return resData; + }), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.css b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.css new file mode 100644 index 0000000..4008df7 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.css @@ -0,0 +1,16 @@ +.grid-container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 20px; +} +section { + margin-left: 10px; + padding: 10px; + background-color: darkgrey; + border-radius: 10px; + margin-bottom: 10px; +} +article { + margin-left: 10px; + padding: 5px; +} diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html new file mode 100644 index 0000000..af4861d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.html @@ -0,0 +1,35 @@ +
+
+ +
+
+ @if (artist()) { +
+

{{ artist().name }}

+ {{ artist().name }} +
+
+ @for (work of artist().comic_works; track work.worktype.id) { + + @for (comic of work.comics; track comic.id) { +
+ +
+ } + } +
+
+ @for (work of artist().issue_works; track work.worktype.id) { + + @for (issue of work.issues; track issue.id) { +
+ +
+ } + } +
+ } @else { +

Artist Details

+ } +
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.spec.ts new file mode 100644 index 0000000..99f3089 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicArtistsComponent } from './comic-artists.component'; + +describe('ComicArtistsComponent', () => { + let component: ComicArtistsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicArtistsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicArtistsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.ts b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.ts new file mode 100644 index 0000000..9542c18 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-artists/comic-artists.component.ts @@ -0,0 +1,25 @@ +import { Component, inject, input } from '@angular/core'; +import { ComicArtistsListComponent } from '../comic-artists-list/comic-artists-list.component'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; +import { ArtistService } from './artist.service'; +import { ComicComicComponent } from "../comic-comic/comic-comic.component"; +import { ComicWorktypeComponent } from "../comic-worktype/comic-worktype.component"; +import { ArtistDetails } from '../comic.model'; + +@Component({ + selector: 'app-comic-artists', + imports: [ComicArtistsListComponent, ComicComicComponent, ComicWorktypeComponent], + templateUrl: './comic-artists.component.html', + styleUrl: './comic-artists.component.css' +}) +export class ComicArtistsComponent { + artist = input.required(); +} + +export const artistResolver: ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const artistService = inject(ArtistService); + const artistId = route.paramMap.get('artistId'); + const artistDetails = artistService.loadArtistDetails(artistId); + console.log(artistDetails); + return artistDetails; +}; diff --git a/kontor-scripts/schema/__init__.py b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.css similarity index 100% rename from kontor-scripts/schema/__init__.py rename to kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.css diff --git a/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.html b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.html new file mode 100644 index 0000000..ac9bb02 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.spec.ts new file mode 100644 index 0000000..c390c8d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicComicComponent } from './comic-comic.component'; + +describe('ComicComicComponent', () => { + let component: ComicComicComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicComicComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicComicComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.ts b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.ts new file mode 100644 index 0000000..ad24f26 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comic/comic-comic.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { Comic } from '../comic.model'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-comic-comic', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-comic.component.html', + styleUrl: './comic-comic.component.css' +}) +export class ComicComicComponent { + comic = input.required(); +} diff --git a/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.css b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.css new file mode 100644 index 0000000..d95c44d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.css @@ -0,0 +1,14 @@ +ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + gap: 0.5rem; + overflow: auto; +} + +@media (min-width: 768px) { + ul { + flex-direction: column; + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.html b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.html new file mode 100644 index 0000000..5b03ea9 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.html @@ -0,0 +1,10 @@ +
+ +
+
    + @for (comic of comics(); track comic.id) { +
  • + +
  • + } +
diff --git a/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.spec.ts new file mode 100644 index 0000000..a68ff6d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicComicsListComponent } from './comic-comics-list.component'; + +describe('ComicComicsListComponent', () => { + let component: ComicComicsListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicComicsListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicComicsListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.ts b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.ts new file mode 100644 index 0000000..cb2e912 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics-list/comic-comics-list.component.ts @@ -0,0 +1,46 @@ +import { Component, computed, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { Comic } from '../comic.model'; +import { ComicService } from '../comic-comics/comic.service'; +import { ComicComicComponent } from '../comic-comic/comic-comic.component'; + +@Component({ + selector: 'app-comic-comics-list', + imports: [ComicComicComponent], + templateUrl: './comic-comics-list.component.html', + styleUrl: './comic-comics-list.component.css', +}) +export class ComicComicsListComponent implements OnInit { + comicsFetched = signal(undefined); + searchQuery = signal(''); + comics = computed(() => { + const sq = this.searchQuery(); + return this.comicsFetched()?.filter(c => c.title.toLowerCase().includes(sq.toLowerCase())); + }); + isFetching = signal(false); + error = signal(''); + private comicsService = inject(ComicService); + private destroyRef = inject(DestroyRef); + + ngOnInit() { + this.isFetching.set(true); + const subscription = this.comicsService.loadComics().subscribe({ + next: (comics) => { + this.comicsFetched.set(comics); + }, + error: (error: Error) => { + this.error.set(error.message); + }, + complete: () => { + this.isFetching.set(false); + }, + }); + + this.destroyRef.onDestroy(() => { + subscription.unsubscribe(); + }); + } + + search(query: string) { + this.searchQuery.set(query); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.css b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.css new file mode 100644 index 0000000..9ec0bbd --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.css @@ -0,0 +1,29 @@ +.float-parent-element { + width: 50%; +} +.float-child-element { + float: left; + width: 50%; + border-width: 10px; + border-color: black; +} +.float-details-element { + border: 1px solid darkgreen; + background-color: lightgreen; + margin: 5px; + padding: 1rem; + height: 100%; +} + +.parent { + border: 1px solid black; + margin: 1rem; + padding: 2rem 2rem; + text-align: left; +} +.child { + display: inline-block; + border: 1px solid red; + padding: 1rem 1rem; + vertical-align: top; +} diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html new file mode 100644 index 0000000..7f8a5ac --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.html @@ -0,0 +1,32 @@ +
+
+ +
+
+ @if (comic()) { +
+

{{ comic().title }}

+ {{ comic().title }} + +
+
+ @for (issue of comic().issues; track issue.id) { + + } +
+
+ @for (work of comic().works; track work.worktype.id) { + + @for (artist of work.artists; track artist.id) { +
+ +
+ } + } +
+ } @else { +

Comic Details

+ } +
+
+ diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.spec.ts new file mode 100644 index 0000000..66a2c25 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicComicsComponent } from './comic-comics.component'; + +describe('ComicComicsComponent', () => { + let component: ComicComicsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicComicsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicComicsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts new file mode 100644 index 0000000..983f1a1 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic-comics.component.ts @@ -0,0 +1,27 @@ +import { Component, inject, input } from '@angular/core'; +import { ComicComicsListComponent } from "../comic-comics-list/comic-comics-list.component"; +import { ComicDetails } from '../comic.model'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; +import { ComicService } from './comic.service'; +import { ComicWorktypeComponent } from '../comic-worktype/comic-worktype.component'; +import { ComicArtistComponent } from '../comic-artist/comic-artist.component'; +import { ComicIssueComponent } from '../comic-issue/comic-issue.component'; +import { ComicPublisherComponent } from "../comic-publisher/comic-publisher.component"; + +@Component({ + selector: 'app-comic-comics', + imports: [ComicComicsListComponent, ComicWorktypeComponent, ComicArtistComponent, ComicIssueComponent, ComicPublisherComponent], + templateUrl: './comic-comics.component.html', + styleUrl: './comic-comics.component.css' +}) +export class ComicComicsComponent { + comic = input.required(); +} + +export const comicResolver: ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const comicService = inject(ComicService); + const comicId = route.paramMap.get('comicId'); + const comicDetails = comicService.loadComicDetails(comicId); + console.log(comicDetails); + return comicDetails; +}; diff --git a/kontor-angular/src/app/kontor/comic/comic-comics/comic.service.ts b/kontor-angular/src/app/kontor/comic/comic-comics/comic.service.ts new file mode 100644 index 0000000..76a8d35 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-comics/comic.service.ts @@ -0,0 +1,45 @@ +import { HttpClient } from "@angular/common/http"; +import { inject, Injectable, signal } from "@angular/core"; +import { Comic, ComicDetails } from "../comic.model"; +import { catchError, map, throwError } from "rxjs"; + +@Injectable({ + providedIn: 'root' +}) +export class ComicService { + private httpClient = inject(HttpClient); + private comics = signal([]); + + loadedComics = this.comics.asReadonly(); + + loadComics() { + return this.fetchComics('http://127.0.0.1:8800/api/comics/comics', 'Someting went wrong fetching comics. Please try again later.'); + } + + loadComicDetails(comicId: string | null) { + return this.fetchComicDetails('http://127.0.0.1:8800/api/comics/comics/' + comicId, 'Someting went wrong fetching comics. Please try again later.'); + } + + private fetchComicDetails(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => { + console.log(resData); + return resData; + }), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } + + private fetchComics(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => resData), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.css b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html new file mode 100644 index 0000000..a96f8c1 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts new file mode 100644 index 0000000..51c1fb0 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicIssueComponent } from './comic-issue.component'; + +describe('ComicIssueComponent', () => { + let component: ComicIssueComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicIssueComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicIssueComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts new file mode 100644 index 0000000..ec004e6 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-issue/comic-issue.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { Issue } from '../comic.model'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-comic-issue', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-issue.component.html', + styleUrl: './comic-issue.component.css' +}) +export class ComicIssueComponent { + issue = input.required(); +} diff --git a/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.css b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.html b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.html new file mode 100644 index 0000000..87b4fd0 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.spec.ts new file mode 100644 index 0000000..faab5bb --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicNavigationComponent } from './comic-navigation.component'; + +describe('ComicNavigationComponent', () => { + let component: ComicNavigationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicNavigationComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicNavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.ts b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.ts new file mode 100644 index 0000000..62dce29 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-navigation/comic-navigation.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-comic-navigation', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-navigation.component.html', + styleUrl: './comic-navigation.component.css' +}) +export class ComicNavigationComponent { + +} diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.css b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html new file mode 100644 index 0000000..e964901 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts new file mode 100644 index 0000000..10036f5 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicPublisherComponent } from './comic-publisher.component'; + +describe('ComicPublisherComponent', () => { + let component: ComicPublisherComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicPublisherComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicPublisherComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts new file mode 100644 index 0000000..33d903b --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publisher/comic-publisher.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { Publisher } from '../comic.model'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-comic-publisher', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-publisher.component.html', + styleUrl: './comic-publisher.component.css' +}) +export class ComicPublisherComponent { + publisher = input.required(); +} diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css new file mode 100644 index 0000000..d95c44d --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.css @@ -0,0 +1,14 @@ +ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + gap: 0.5rem; + overflow: auto; +} + +@media (min-width: 768px) { + ul { + flex-direction: column; + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html new file mode 100644 index 0000000..6592f11 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.html @@ -0,0 +1,7 @@ +
    + @for (publisher of publishers(); track publisher.id) { +
  • + +
  • + } +
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts new file mode 100644 index 0000000..c83a6fe --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicPublishersListComponent } from './comic-publishers-list.component'; + +describe('ComicPublishersListComponent', () => { + let component: ComicPublishersListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicPublishersListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicPublishersListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts new file mode 100644 index 0000000..6f47536 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers-list/comic-publishers-list.component.ts @@ -0,0 +1,37 @@ +import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { Publisher } from '../comic.model'; +import { PublisherService } from '../comic-publishers/publisher.service'; +import { ComicPublisherComponent } from "../comic-publisher/comic-publisher.component"; + +@Component({ + selector: 'app-comic-publishers-list', + imports: [ComicPublisherComponent], + templateUrl: './comic-publishers-list.component.html', + styleUrl: './comic-publishers-list.component.css' +}) +export class ComicPublishersListComponent implements OnInit { + publishers = signal([]); + isFetching = signal(false); + error = signal(''); + private publisherService = inject(PublisherService); + private destroyRef = inject(DestroyRef); + + ngOnInit() { + this.isFetching.set(true); + const subscription = this.publisherService.loadPublishers().subscribe({ + next: (publishers) => { + this.publishers.set(publishers); + }, + error: (error: Error) => { + this.error.set(error.message); + }, + complete: () => { + this.isFetching.set(false); + }, + }); + + this.destroyRef.onDestroy(() => { + subscription.unsubscribe(); + }); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.css b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html new file mode 100644 index 0000000..bb16b77 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.html @@ -0,0 +1,31 @@ +
+
+ +
+
+ @if (publisher()) { +
+

{{ publisher().name }}

+ @if (publisher().parent_publisher) { + + } +
+
+ @for (imprint of publisher().imprints; track imprint.id) { +
+ +
+ } +
+
+ @for (comic of publisher().comics; track comic.id) { +
+ +
+ } +
+ } @else { +

Publisher Details

+ } +
+
diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.spec.ts new file mode 100644 index 0000000..184f6e7 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicPublishersComponent } from './comic-publishers.component'; + +describe('ComicPublishersComponent', () => { + let component: ComicPublishersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicPublishersComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicPublishersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts new file mode 100644 index 0000000..ad8f894 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers/comic-publishers.component.ts @@ -0,0 +1,25 @@ +import { Component, inject, input } from '@angular/core'; +import { Publisher, PublisherDetails } from '../comic.model'; +import { ComicPublishersListComponent } from '../comic-publishers-list/comic-publishers-list.component'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; +import { PublisherService } from './publisher.service'; +import { ComicPublisherComponent } from "../comic-publisher/comic-publisher.component"; +import { ComicComicComponent } from "../comic-comic/comic-comic.component"; + +@Component({ + selector: 'app-comic-publishers', + imports: [ComicPublishersListComponent, ComicPublisherComponent, ComicComicComponent], + templateUrl: './comic-publishers.component.html', + styleUrl: './comic-publishers.component.css' +}) +export class ComicPublishersComponent { + publisher = input.required(); +} + +export const publisherResolver: ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const publisherService = inject(PublisherService); + const publisherId = route.paramMap.get('publisherId'); + const publisherDetails = publisherService.loadPublisherDetails(publisherId); + console.log(publisherDetails); + return publisherDetails; +}; diff --git a/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts b/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts new file mode 100644 index 0000000..7ff0bff --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-publishers/publisher.service.ts @@ -0,0 +1,47 @@ +import { inject, Injectable, signal } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { catchError, map, throwError } from "rxjs"; +import { ErrorService } from "../../../shared/error.service"; +import { Publisher, PublisherDetails } from "../comic.model"; + +@Injectable({ + providedIn: 'root', +}) +export class PublisherService { + private errorService = inject(ErrorService); + private httpClient = inject(HttpClient); + private publishers = signal([]); + + loadedPublishers = this.publishers.asReadonly(); + + loadPublishers() { + return this.fetchPublishers('http://127.0.0.1:8800/api/comics/publishers', 'Someting went wrong fetching artists. Please try again later-'); + } + + loadPublisherDetails(artistId: string | null) { + return this.fetchPublisherDetails('http://127.0.0.1:8800/api/comics/publishers/' + artistId, 'Someting went wrong fetching comic artists. Please try again later.'); + } + + private fetchPublishers(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => resData), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } + + private fetchPublisherDetails(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => { + console.log(resData); + return resData; + }), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } +} diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.css b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.html b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.html new file mode 100644 index 0000000..570e4d6 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.html @@ -0,0 +1,2 @@ + + diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.spec.ts new file mode 100644 index 0000000..9acbb1a --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicSectionComponent } from './comic-section.component'; + +describe('ComicSectionComponent', () => { + let component: ComicSectionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicSectionComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicSectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.ts b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.ts new file mode 100644 index 0000000..76c2cef --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; +import { ComicNavigationComponent } from "../comic-navigation/comic-navigation.component"; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'app-comic-section', + imports: [ComicNavigationComponent, RouterOutlet], + templateUrl: './comic-section.component.html', + styleUrl: './comic-section.component.css' +}) +export class ComicSectionComponent { + +} diff --git a/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts new file mode 100644 index 0000000..cc57991 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-section/comic-section.routes.ts @@ -0,0 +1,40 @@ +import { Routes } from "@angular/router"; +import { artistResolver, ComicArtistsComponent } from "../comic-artists/comic-artists.component"; +import { ComicPublishersComponent, publisherResolver } from './../comic-publishers/comic-publishers.component'; +import { ComicComicsComponent, comicResolver } from "../comic-comics/comic-comics.component"; + +export const comicRoutes: Routes = [ + { + path: 'comics', + component: ComicComicsComponent + }, + { + path: 'comics/:comicId', + component: ComicComicsComponent, + resolve: { + comic: comicResolver + } + }, + { + path: 'publisher', + component: ComicPublishersComponent + }, + { + path: 'publisher/:publisherId', + component: ComicPublishersComponent, + resolve: { + publisher: publisherResolver + } + }, + { + path: 'artist', + component: ComicArtistsComponent + }, + { + path: 'artist/:artistId', + component: ComicArtistsComponent, + resolve: { + artist: artistResolver + } + }, +]; diff --git a/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.css b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.html b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.html new file mode 100644 index 0000000..a9709ce --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.spec.ts b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.spec.ts new file mode 100644 index 0000000..88c4876 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ComicWorktypeComponent } from './comic-worktype.component'; + +describe('ComicWorktypeComponent', () => { + let component: ComicWorktypeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ComicWorktypeComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ComicWorktypeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.ts b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.ts new file mode 100644 index 0000000..260ad68 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic-worktype/comic-worktype.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; +import { Worktype } from '../comic.model'; + +@Component({ + selector: 'app-comic-worktype', + imports: [RouterLink, RouterLinkActive], + templateUrl: './comic-worktype.component.html', + styleUrl: './comic-worktype.component.css' +}) +export class ComicWorktypeComponent { + worktype = input.required(); +} diff --git a/kontor-angular/src/app/kontor/comic/comic.model.ts b/kontor-angular/src/app/kontor/comic/comic.model.ts new file mode 100644 index 0000000..85da285 --- /dev/null +++ b/kontor-angular/src/app/kontor/comic/comic.model.ts @@ -0,0 +1,81 @@ +export interface Artist { + id: string; + name: string; +} + +export interface Worktype { + id: string; + name: string; +} + +export interface Publisher { + id: string; + name: string; +} + +export interface Comic { + id: string; + title: string; + completed: boolean; +} + +export interface Volume { + id: string; + name: string; +} + +export interface Issue { + id: string; + issue_number: string; + in_stock: boolean; + is_read: boolean; + comic: Comic; + volume: Volume; +} + +export interface ComicWork { + worktype: string; +} + +export interface ComicWorktypeArtists { + worktype: Worktype; + artists: Artist[]; +} + +export interface PublisherDetails { + id: string; + name: string; + parent_publisher: Publisher; + imprints: Publisher[]; + comics: Comic[]; +} + +export interface ComicDetails { + id: string; + created: string; + title: string; + completed: boolean; + current_order: boolean; + weblink: string; + publisher: Publisher; + issues: Issue[]; + volumes: Volume[]; + works: ComicWorktypeArtists[]; +} + +export interface ArtistWorktypeComics { + worktype: Worktype; + comics: Comic[]; +} + +export interface ArtistWorktypeIssues { + worktype: Worktype; + issues: Issue[]; +} +export interface ArtistDetails { + id: string; + name: string; + weblink: string; + comic_works: ArtistWorktypeComics[]; + issue_works: ArtistWorktypeIssues[]; +} diff --git a/kontor-angular/src/app/kontor/footer/footer.component.css b/kontor-angular/src/app/kontor/footer/footer.component.css new file mode 100644 index 0000000..1a660c1 --- /dev/null +++ b/kontor-angular/src/app/kontor/footer/footer.component.css @@ -0,0 +1,12 @@ +/* Footer */ +.footer { + padding: 20px; + text-align: center; + background-color: lightblue; + position: sticky; + bottom: 0px; +} + +.footer a { + font-size: 20px; +} diff --git a/kontor-angular/src/app/kontor/footer/footer.component.html b/kontor-angular/src/app/kontor/footer/footer.component.html new file mode 100644 index 0000000..912cc1d --- /dev/null +++ b/kontor-angular/src/app/kontor/footer/footer.component.html @@ -0,0 +1,5 @@ + + + diff --git a/kontor-angular/src/app/kontor/footer/footer.component.spec.ts b/kontor-angular/src/app/kontor/footer/footer.component.spec.ts new file mode 100644 index 0000000..0f4e3e0 --- /dev/null +++ b/kontor-angular/src/app/kontor/footer/footer.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KontorFooterComponent } from './footer.component'; + +describe('KontorFooterComponent', () => { + let component: KontorFooterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [KontorFooterComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KontorFooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/footer/footer.component.ts b/kontor-angular/src/app/kontor/footer/footer.component.ts new file mode 100644 index 0000000..7ded191 --- /dev/null +++ b/kontor-angular/src/app/kontor/footer/footer.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'kontor-footer', + imports: [], + templateUrl: './footer.component.html', + styleUrl: './footer.component.css' +}) +export class KontorFooterComponent { + footerUrl = "https://kontor.thpeetz.de"; + footerLink = "kontor.thpeetz.de"; +} diff --git a/kontor-angular/src/app/kontor/header/header.component.css b/kontor-angular/src/app/kontor/header/header.component.css new file mode 100644 index 0000000..b3b2fe7 --- /dev/null +++ b/kontor-angular/src/app/kontor/header/header.component.css @@ -0,0 +1,11 @@ +/* Header/Blog Title */ +.header { + padding: 30px; + text-align: center; + background-color: lightblue; +} + +.header h1 { + font-size: 50px; +} + diff --git a/kontor-angular/src/app/kontor/header/header.component.html b/kontor-angular/src/app/kontor/header/header.component.html new file mode 100644 index 0000000..3191f24 --- /dev/null +++ b/kontor-angular/src/app/kontor/header/header.component.html @@ -0,0 +1,5 @@ +
+
+

{{ title() }}

+
+
diff --git a/kontor-angular/src/app/kontor/header/header.component.spec.ts b/kontor-angular/src/app/kontor/header/header.component.spec.ts new file mode 100644 index 0000000..e5cc393 --- /dev/null +++ b/kontor-angular/src/app/kontor/header/header.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KontorHeaderComponent } from './header.component'; + +describe('Header', () => { + let component: KontorHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [KontorHeaderComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KontorHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/header/header.component.ts b/kontor-angular/src/app/kontor/header/header.component.ts new file mode 100644 index 0000000..3b8a262 --- /dev/null +++ b/kontor-angular/src/app/kontor/header/header.component.ts @@ -0,0 +1,12 @@ +import { Component, signal } from '@angular/core'; + +@Component({ + selector: 'kontor-header', + imports: [], + templateUrl: './header.component.html', + styleUrl: './header.component.css' +}) +export class KontorHeaderComponent { + protected readonly title = signal('Kontor'); + +} diff --git a/kontor-angular/src/app/kontor/kontor.component.css b/kontor-angular/src/app/kontor/kontor.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/kontor.component.html b/kontor-angular/src/app/kontor/kontor.component.html new file mode 100644 index 0000000..cf1adeb --- /dev/null +++ b/kontor-angular/src/app/kontor/kontor.component.html @@ -0,0 +1 @@ +

kontor works!

diff --git a/kontor-angular/src/app/kontor/kontor.component.spec.ts b/kontor-angular/src/app/kontor/kontor.component.spec.ts new file mode 100644 index 0000000..1b5bc70 --- /dev/null +++ b/kontor-angular/src/app/kontor/kontor.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { KontorComponent } from './kontor.component'; + +describe('Kontor', () => { + let component: KontorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [KontorComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(KontorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/kontor.component.ts b/kontor-angular/src/app/kontor/kontor.component.ts new file mode 100644 index 0000000..bb432f4 --- /dev/null +++ b/kontor-angular/src/app/kontor/kontor.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-kontor', + imports: [], + templateUrl: './kontor.component.html', + styleUrl: './kontor.component.css' +}) +export class KontorComponent { + +} diff --git a/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.css b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.html b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.html new file mode 100644 index 0000000..3904b79 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.html @@ -0,0 +1 @@ +

media-actors works!

diff --git a/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.spec.ts b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.spec.ts new file mode 100644 index 0000000..1448ea4 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaActorsComponent } from './media-actors.component'; + +describe('MediaActorsComponent', () => { + let component: MediaActorsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaActorsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaActorsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.ts b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.ts new file mode 100644 index 0000000..8fbb7f8 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-actors/media-actors.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-media-actors', + imports: [], + templateUrl: './media-actors.component.html', + styleUrl: './media-actors.component.css' +}) +export class MediaActorsComponent { + +} diff --git a/kontor-angular/src/app/kontor/media/media-file/media-file.component.css b/kontor-angular/src/app/kontor/media/media-file/media-file.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/media/media-file/media-file.component.html b/kontor-angular/src/app/kontor/media/media-file/media-file.component.html new file mode 100644 index 0000000..b735566 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-file/media-file.component.html @@ -0,0 +1,17 @@ +
+ +
diff --git a/kontor-angular/src/app/kontor/media/media-file/media-file.component.spec.ts b/kontor-angular/src/app/kontor/media/media-file/media-file.component.spec.ts new file mode 100644 index 0000000..4050101 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-file/media-file.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaFileComponent } from './media-file.component'; + +describe('MediaFileComponent', () => { + let component: MediaFileComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaFileComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaFileComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-file/media-file.component.ts b/kontor-angular/src/app/kontor/media/media-file/media-file.component.ts new file mode 100644 index 0000000..924844b --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-file/media-file.component.ts @@ -0,0 +1,13 @@ +import { Component, input } from '@angular/core'; +import { MediaFile } from '../media-files/media-file.model'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-media-file', + imports: [RouterLink, RouterLinkActive], + templateUrl: './media-file.component.html', + styleUrl: './media-file.component.css' +}) +export class MediaFileComponent { + mediafile = input.required(); +} diff --git a/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.css b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.css new file mode 100644 index 0000000..d95c44d --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.css @@ -0,0 +1,14 @@ +ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + gap: 0.5rem; + overflow: auto; +} + +@media (min-width: 768px) { + ul { + flex-direction: column; + } +} diff --git a/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.html b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.html new file mode 100644 index 0000000..1688d6b --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.html @@ -0,0 +1,7 @@ +
    + @for (mediafile of files(); track mediafile.id) { +
  • + +
  • + } +
\ No newline at end of file diff --git a/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.spec.ts b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.spec.ts new file mode 100644 index 0000000..a97b136 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaFilesListComponent } from './media-files-list.component'; + +describe('MediaFilesListComponent', () => { + let component: MediaFilesListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaFilesListComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaFilesListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.ts b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.ts new file mode 100644 index 0000000..eac3322 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files-list/media-files-list.component.ts @@ -0,0 +1,37 @@ +import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { MediaFileComponent } from '../media-file/media-file.component'; +import { MediaFileService } from '../media-files/media-file.service'; +import { MediaFile } from '../media-files/media-file.model'; + +@Component({ + selector: 'app-media-files-list', + imports: [MediaFileComponent], + templateUrl: './media-files-list.component.html', + styleUrl: './media-files-list.component.css' +}) +export class MediaFilesListComponent implements OnInit { + files = signal([]); + isFetching = signal(false); + error = signal(''); + private mediaFileService = inject(MediaFileService); + private destroyRef = inject(DestroyRef); + + ngOnInit() { + this.isFetching.set(true); + const subscription = this.mediaFileService.loadFiles().subscribe({ + next: (files) => { + this.files.set(files); + }, + error: (error: Error) => { + this.error.set(error.message); + }, + complete: () => { + this.isFetching.set(false); + }, + }); + + this.destroyRef.onDestroy(() => { + subscription.unsubscribe(); + }); + } +} diff --git a/kontor-angular/src/app/kontor/media/media-files/media-file.model.ts b/kontor-angular/src/app/kontor/media/media-files/media-file.model.ts new file mode 100644 index 0000000..9418003 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-file.model.ts @@ -0,0 +1,11 @@ +import { StreamingResourceOptions } from "@angular/core"; + +export interface MediaFile { + id: string; + title: string; + file_name: string; + cloud_link: string; + url: string; + review: boolean; + should_download: boolean; +} \ No newline at end of file diff --git a/kontor-angular/src/app/kontor/media/media-files/media-file.service.ts b/kontor-angular/src/app/kontor/media/media-files/media-file.service.ts new file mode 100644 index 0000000..96e24e7 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-file.service.ts @@ -0,0 +1,30 @@ +import { inject, Injectable, signal } from "@angular/core"; +import { ErrorService } from "../../../shared/error.service"; +import { HttpClient } from "@angular/common/http"; +import { MediaFile } from "./media-file.model"; +import { catchError, map, throwError } from "rxjs"; + +@Injectable({ + providedIn: 'root', +}) +export class MediaFileService { + private errorService = inject(ErrorService); + private httpClient = inject(HttpClient); + private files = signal([]); + + loadedFiles = this.files.asReadonly(); + + loadFiles() { + return this.fetchMediaFiles('http://127.0.0.1:8800/api/media/files', 'Someting went wrong fetching artists. Please try again later-'); + } + + private fetchMediaFiles(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => resData), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } +} diff --git a/kontor-angular/src/app/kontor/media/media-files/media-files.component.css b/kontor-angular/src/app/kontor/media/media-files/media-files.component.css new file mode 100644 index 0000000..a997f58 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-files.component.css @@ -0,0 +1,5 @@ +.grid-container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 20px; +} diff --git a/kontor-angular/src/app/kontor/media/media-files/media-files.component.html b/kontor-angular/src/app/kontor/media/media-files/media-files.component.html new file mode 100644 index 0000000..ac8ed9f --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-files.component.html @@ -0,0 +1,7 @@ +
+
+ +
+
+
+
diff --git a/kontor-angular/src/app/kontor/media/media-files/media-files.component.spec.ts b/kontor-angular/src/app/kontor/media/media-files/media-files.component.spec.ts new file mode 100644 index 0000000..c8f1c9f --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-files.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaFilesComponent } from './media-files.component'; + +describe('MediaFilesComponent', () => { + let component: MediaFilesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaFilesComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaFilesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-files/media-files.component.ts b/kontor-angular/src/app/kontor/media/media-files/media-files.component.ts new file mode 100644 index 0000000..06fbc0e --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-files/media-files.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { MediaFilesListComponent } from '../media-files-list/media-files-list.component'; + +@Component({ + selector: 'app-media-files', + imports: [MediaFilesListComponent], + templateUrl: './media-files.component.html', + styleUrl: './media-files.component.css' +}) +export class MediaFilesComponent { + +} diff --git a/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.css b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.html b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.html new file mode 100644 index 0000000..846dd50 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.html @@ -0,0 +1,5 @@ + diff --git a/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.spec.ts b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.spec.ts new file mode 100644 index 0000000..e1c7fdf --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaNavigationComponent } from './media-navigation.component'; + +describe('MediaNavigationComponent', () => { + let component: MediaNavigationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaNavigationComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaNavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.ts b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.ts new file mode 100644 index 0000000..673afd9 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-navigation/media-navigation.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-media-navigation', + imports: [RouterLink, RouterLinkActive], + templateUrl: './media-navigation.component.html', + styleUrl: './media-navigation.component.css' +}) +export class MediaNavigationComponent { + +} diff --git a/kontor-angular/src/app/kontor/media/media-section/media-section.component.css b/kontor-angular/src/app/kontor/media/media-section/media-section.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/media/media-section/media-section.component.html b/kontor-angular/src/app/kontor/media/media-section/media-section.component.html new file mode 100644 index 0000000..d31e086 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-section/media-section.component.html @@ -0,0 +1,2 @@ + + diff --git a/kontor-angular/src/app/kontor/media/media-section/media-section.component.spec.ts b/kontor-angular/src/app/kontor/media/media-section/media-section.component.spec.ts new file mode 100644 index 0000000..fa766d5 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-section/media-section.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaSectionComponent } from './media-section.component'; + +describe('MediaSectionComponent', () => { + let component: MediaSectionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaSectionComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaSectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-section/media-section.component.ts b/kontor-angular/src/app/kontor/media/media-section/media-section.component.ts new file mode 100644 index 0000000..a4c17d3 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-section/media-section.component.ts @@ -0,0 +1,13 @@ +import { Component } from '@angular/core'; +import { MediaNavigationComponent } from "../media-navigation/media-navigation.component"; +import { RouterOutlet } from '@angular/router'; + +@Component({ + selector: 'app-media-section', + imports: [MediaNavigationComponent, RouterOutlet], + templateUrl: './media-section.component.html', + styleUrl: './media-section.component.css' +}) +export class MediaSectionComponent { + +} diff --git a/kontor-angular/src/app/kontor/media/media-section/media-section.routes.ts b/kontor-angular/src/app/kontor/media/media-section/media-section.routes.ts new file mode 100644 index 0000000..8214e84 --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-section/media-section.routes.ts @@ -0,0 +1,31 @@ +import { Routes } from "@angular/router"; +import { MediaFilesComponent } from './../media-files/media-files.component'; +import { MediaActorsComponent } from '../media-actors/media-actors.component'; +import { MediaVideosComponent } from '../media-videos/media-videos.component'; + +export const mediaRoutes: Routes = [ + { + path: 'file', + component: MediaFilesComponent + }, + { + path: 'file/:fileId', + component: MediaFilesComponent, + }, + { + path: 'actor', + component: MediaActorsComponent + }, + { + path: 'actor/:actorId', + component: MediaActorsComponent, + }, + { + path: 'video', + component: MediaVideosComponent + }, + { + path: 'video/:videoId', + component: MediaVideosComponent, + }, +]; diff --git a/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.css b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.html b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.html new file mode 100644 index 0000000..2aaafcb --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.html @@ -0,0 +1 @@ +

media-videos works!

diff --git a/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.spec.ts b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.spec.ts new file mode 100644 index 0000000..ccde24c --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MediaVideosComponent } from './media-videos.component'; + +describe('MediaVideosComponent', () => { + let component: MediaVideosComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [MediaVideosComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(MediaVideosComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.ts b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.ts new file mode 100644 index 0000000..5b1f52e --- /dev/null +++ b/kontor-angular/src/app/kontor/media/media-videos/media-videos.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-media-videos', + imports: [], + templateUrl: './media-videos.component.html', + styleUrl: './media-videos.component.css' +}) +export class MediaVideosComponent { + +} diff --git a/kontor-angular/src/app/kontor/navigation/navigation.component.css b/kontor-angular/src/app/kontor/navigation/navigation.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/navigation/navigation.component.html b/kontor-angular/src/app/kontor/navigation/navigation.component.html new file mode 100644 index 0000000..b691db0 --- /dev/null +++ b/kontor-angular/src/app/kontor/navigation/navigation.component.html @@ -0,0 +1,7 @@ + diff --git a/kontor-angular/src/app/kontor/navigation/navigation.component.spec.ts b/kontor-angular/src/app/kontor/navigation/navigation.component.spec.ts new file mode 100644 index 0000000..a161d31 --- /dev/null +++ b/kontor-angular/src/app/kontor/navigation/navigation.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NavigationComponent } from './navigation.component'; + +describe('NavigationComponent', () => { + let component: NavigationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [NavigationComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(NavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/navigation/navigation.component.ts b/kontor-angular/src/app/kontor/navigation/navigation.component.ts new file mode 100644 index 0000000..c5feb48 --- /dev/null +++ b/kontor-angular/src/app/kontor/navigation/navigation.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-navigation', + imports: [RouterLink, RouterLinkActive], + templateUrl: './navigation.component.html', + styleUrl: './navigation.component.css' +}) +export class NavigationComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.css b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.html b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.html new file mode 100644 index 0000000..72cccd1 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.html @@ -0,0 +1 @@ +

tysc-cardsets works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.spec.ts new file mode 100644 index 0000000..b01812b --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscCardsetsComponent } from './tysc-cardsets.component'; + +describe('TyscCardsetsComponent', () => { + let component: TyscCardsetsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscCardsetsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscCardsetsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.ts new file mode 100644 index 0000000..fc3bc35 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-cardsets/tysc-cardsets.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-cardsets', + imports: [], + templateUrl: './tysc-cardsets.component.html', + styleUrl: './tysc-cardsets.component.css' +}) +export class TyscCardsetsComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.css b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.html b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.html new file mode 100644 index 0000000..1baa47f --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.html @@ -0,0 +1,7 @@ + diff --git a/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.spec.ts new file mode 100644 index 0000000..363a185 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscNavigationComponent } from './tysc-navigation.component'; + +describe('TyscNavigationComponent', () => { + let component: TyscNavigationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscNavigationComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscNavigationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.ts new file mode 100644 index 0000000..0a8cc16 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-navigation/tysc-navigation.component.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; +import { RouterLink, RouterLinkActive } from '@angular/router'; + +@Component({ + selector: 'app-tysc-navigation', + imports: [RouterLink, RouterLinkActive], + templateUrl: './tysc-navigation.component.html', + styleUrl: './tysc-navigation.component.css' +}) +export class TyscNavigationComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.css b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.html b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.html new file mode 100644 index 0000000..e5c03a6 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.html @@ -0,0 +1 @@ +

tysc-players works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.spec.ts new file mode 100644 index 0000000..eb0ac63 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscPlayersComponent } from './tysc-players.component'; + +describe('TyscPlayersComponent', () => { + let component: TyscPlayersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscPlayersComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscPlayersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.ts new file mode 100644 index 0000000..230670e --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-players/tysc-players.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-players', + imports: [], + templateUrl: './tysc-players.component.html', + styleUrl: './tysc-players.component.css' +}) +export class TyscPlayersComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.css b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.html b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.html new file mode 100644 index 0000000..1348c4f --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.html @@ -0,0 +1 @@ +

tysc-positions works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.spec.ts new file mode 100644 index 0000000..97425a7 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscPositionsComponent } from './tysc-positions.component'; + +describe('TyscPositionsComponent', () => { + let component: TyscPositionsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscPositionsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscPositionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.ts new file mode 100644 index 0000000..c77f1d3 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-positions/tysc-positions.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-positions', + imports: [], + templateUrl: './tysc-positions.component.html', + styleUrl: './tysc-positions.component.css' +}) +export class TyscPositionsComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.css b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.html b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.html new file mode 100644 index 0000000..4b8a158 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.html @@ -0,0 +1,3 @@ + + + diff --git a/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.spec.ts new file mode 100644 index 0000000..c8c34ec --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscSectionComponent } from './tysc-section.component'; + +describe('TyscSectionComponent', () => { + let component: TyscSectionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscSectionComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscSectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.ts new file mode 100644 index 0000000..bb33bc2 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { TyscNavigationComponent } from "../tysc-navigation/tysc-navigation.component"; +import { RouterOutlet } from '@angular/router'; +import { TyscSportsComponent } from "../tysc-sports/tysc-sports.component"; + +@Component({ + selector: 'app-tysc-section', + imports: [TyscNavigationComponent, RouterOutlet, TyscSportsComponent], + templateUrl: './tysc-section.component.html', + styleUrl: './tysc-section.component.css' +}) +export class TyscSectionComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.routes.ts b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.routes.ts new file mode 100644 index 0000000..6f2a995 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-section/tysc-section.routes.ts @@ -0,0 +1,29 @@ +import { Routes } from "@angular/router"; +import { TyscTeamsComponent } from "../tysc-teams/tysc-teams.component"; +import { TyscPlayersComponent } from "../tysc-players/tysc-players.component"; +import { TyscPositionsComponent } from "../tysc-positions/tysc-positions.component"; +import { TyscVendorsComponent } from "../tysc-vendors/tysc-vendors.component"; +import { TyscCardsetsComponent } from "../tysc-cardsets/tysc-cardsets.component"; + +export const tyscRoutes: Routes = [ + { + path: 'team', + component: TyscTeamsComponent + }, + { + path: 'player', + component: TyscPlayersComponent + }, + { + path: 'position', + component: TyscPositionsComponent + }, + { + path: 'cardset', + component: TyscCardsetsComponent + }, + { + path: 'vendor', + component: TyscVendorsComponent + }, +]; diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.model.ts b/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.model.ts new file mode 100644 index 0000000..a9bc9a2 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.model.ts @@ -0,0 +1,4 @@ +export interface Sport { + id: string; + name: string; +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.service.ts b/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.service.ts new file mode 100644 index 0000000..bae168c --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-sports/sport.service.ts @@ -0,0 +1,30 @@ +import { HttpClient } from "@angular/common/http"; +import { inject, Injectable, signal } from "@angular/core"; +import { catchError, map, throwError } from "rxjs"; +import { ErrorService } from "../../../shared/error.service"; +import { Sport } from "./sport.model"; + +@Injectable({ + providedIn: 'root', +}) +export class SportService { + private errorService = inject(ErrorService); + private httpClient = inject(HttpClient); + private sports = signal([]); + + loadedSports = this.sports.asReadonly(); + + loadSports() { + return this.fetchSports('http://127.0.0.1:8800/api/tysc/sports', 'Someting went wrong fetching sports. Please try again later-'); + } + + private fetchSports(url: string, errorMessage: string) { + return this.httpClient.get(url).pipe( + map((resData) => resData), + catchError((error) => { + console.log(error); + return throwError(() => new Error(errorMessage)); + }) + ); + } +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.css b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.html b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.html new file mode 100644 index 0000000..1f62960 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.html @@ -0,0 +1,9 @@ +

tysc-sports works!

+

sport-list works!

+
    + @for (sport of sports(); track sport.id) { +
  • +

    {{ sport.name }}

    +
  • + } +
diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.spec.ts new file mode 100644 index 0000000..5854048 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscSportsComponent } from './tysc-sports.component'; + +describe('TyscSportsComponent', () => { + let component: TyscSportsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscSportsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscSportsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.ts new file mode 100644 index 0000000..7808133 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-sports/tysc-sports.component.ts @@ -0,0 +1,37 @@ +import { Component, DestroyRef, inject, OnInit, signal } from '@angular/core'; +import { Sport } from './sport.model'; +import { SportService } from './sport.service'; + +@Component({ + selector: 'app-tysc-sports', + imports: [], + templateUrl: './tysc-sports.component.html', + styleUrl: './tysc-sports.component.css' +}) +export class TyscSportsComponent implements OnInit { + sports = signal(undefined); + isFetching = signal(false); + error = signal(''); + private sportService = inject(SportService); + private destroyRef = inject(DestroyRef); + + + ngOnInit() { + this.isFetching.set(true); + const subscription = this.sportService.loadSports().subscribe({ + next: (sports) => { + this.sports.set(sports); + }, + error: (error: Error) => { + this.error.set(error.message); + }, + complete: () => { + this.isFetching.set(false); + }, + }); + + this.destroyRef.onDestroy(() => { + subscription.unsubscribe(); + }); + } +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.css b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.html b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.html new file mode 100644 index 0000000..d4584d4 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.html @@ -0,0 +1 @@ +

tysc-team works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.spec.ts new file mode 100644 index 0000000..15d76cb --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscTeamComponent } from './tysc-team.component'; + +describe('TyscTeamComponent', () => { + let component: TyscTeamComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscTeamComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscTeamComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.ts new file mode 100644 index 0000000..62ca09c --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-team/tysc-team.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-team', + imports: [], + templateUrl: './tysc-team.component.html', + styleUrl: './tysc-team.component.css' +}) +export class TyscTeamComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.css b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.html b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.html new file mode 100644 index 0000000..8cfc44f --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.html @@ -0,0 +1 @@ +

tysc-teams works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.spec.ts new file mode 100644 index 0000000..dc60252 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscTeamsComponent } from './tysc-teams.component'; + +describe('TyscTeamsComponent', () => { + let component: TyscTeamsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscTeamsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscTeamsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.ts new file mode 100644 index 0000000..070d4c3 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-teams/tysc-teams.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-teams', + imports: [], + templateUrl: './tysc-teams.component.html', + styleUrl: './tysc-teams.component.css' +}) +export class TyscTeamsComponent { + +} diff --git a/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.css b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.css new file mode 100644 index 0000000..e69de29 diff --git a/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.html b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.html new file mode 100644 index 0000000..3b47744 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.html @@ -0,0 +1 @@ +

tysc-vendors works!

diff --git a/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.spec.ts b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.spec.ts new file mode 100644 index 0000000..6bbd10f --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TyscVendorsComponent } from './tysc-vendors.component'; + +describe('TyscVendorsComponent', () => { + let component: TyscVendorsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TyscVendorsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TyscVendorsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.ts b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.ts new file mode 100644 index 0000000..7071433 --- /dev/null +++ b/kontor-angular/src/app/kontor/tysc/tysc-vendors/tysc-vendors.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-tysc-vendors', + imports: [], + templateUrl: './tysc-vendors.component.html', + styleUrl: './tysc-vendors.component.css' +}) +export class TyscVendorsComponent { + +} diff --git a/kontor-angular/src/app/shared/error.service.ts b/kontor-angular/src/app/shared/error.service.ts new file mode 100644 index 0000000..7befc28 --- /dev/null +++ b/kontor-angular/src/app/shared/error.service.ts @@ -0,0 +1,19 @@ +import { Injectable, signal } from "@angular/core"; + +@Injectable({ + providedIn: 'root' +}) +export class ErrorService { + private _error = signal(''); + + error = this._error.asReadonly(); + + showError(message: string) { + console.log(message); + this._error.set(message); + } + + clearError() { + this._error.set(''); + } +} diff --git a/kontor-angular/src/app/shared/loading-spinner/loading-spinner.ts b/kontor-angular/src/app/shared/loading-spinner/loading-spinner.ts new file mode 100644 index 0000000..d46bf34 --- /dev/null +++ b/kontor-angular/src/app/shared/loading-spinner/loading-spinner.ts @@ -0,0 +1,11 @@ +import { Component } from "@angular/core" + +@Component({ + selector: 'app-loading-spinner', + template: '
', + styleUrls: ['./loading.spinner.css'] +}) +export class LoadingSpinner {} + + + diff --git a/kontor-angular/src/app/shared/loading-spinner/loading.spinner.css b/kontor-angular/src/app/shared/loading-spinner/loading.spinner.css new file mode 100644 index 0000000..413e640 --- /dev/null +++ b/kontor-angular/src/app/shared/loading-spinner/loading.spinner.css @@ -0,0 +1,41 @@ + +.lds-ring, +.lds-ring div { + box-sizing: border-box; +} +.lds-ring { + display: inline-block; + position: relative; + width: 80px; + height: 80px; +} +.lds-ring div { + box-sizing: border-box; + display: block; + position: absolute; + width: 64px; + height: 64px; + margin: 8px; + border: 8px solid currentColor; + border-radius: 50%; + animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; + border-color: currentColor transparent transparent transparent; +} +.lds-ring div:nth-child(1) { + animation-delay: -0.45s; +} +.lds-ring div:nth-child(2) { + animation-delay: -0.3s; +} +.lds-ring div:nth-child(3) { + animation-delay: -0.15s; +} +@keyframes lds-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + diff --git a/kontor-angular/src/index.html b/kontor-angular/src/index.html new file mode 100644 index 0000000..5bd5d34 --- /dev/null +++ b/kontor-angular/src/index.html @@ -0,0 +1,13 @@ + + + + + Kontor + + + + + + + + diff --git a/kontor-angular/src/main.ts b/kontor-angular/src/main.ts new file mode 100644 index 0000000..35b00f3 --- /dev/null +++ b/kontor-angular/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig) + .catch((err) => console.error(err)); diff --git a/kontor-angular/src/styles.css b/kontor-angular/src/styles.css new file mode 100644 index 0000000..57d9c06 --- /dev/null +++ b/kontor-angular/src/styles.css @@ -0,0 +1,95 @@ +/* You can add global styles to this file, and also import other style files */ +* { + box-sizing: border-box; +} + +body { + font-family: Arial; + padding: 0px; + background: lightgrey; +} + +/* Style the top navigation bar */ +.topnav { + overflow: hidden; + background-color: darkgrey; +} + +/* Style the topnav links */ +.topnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +/* Change color on hover */ +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.topnav :last-child { + float: right; + margin-left: auto; + margin-right: 16px; +} + +.subnav { + overflow: hidden; + background-color: grey; +} + +.subnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +a { + display: inline-block; + color: white; + background-color: dodgerblue; + text-align: center; + padding: 10px; + text-decoration: none; + border-radius: 10px; + margin-left: 20px; +} + +/* Change the color of links on mouse-over */ +a:hover { + background-color: royalblue; + color: white; +} + +/* Add a color to the active/current link */ +a.active { + background-color: royalblue; + color: white; +} + +.grid-container { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 20px; +} + +section { + margin-left: 10px; + padding: 10px; + background-color: darkgrey; + border-radius: 10px; + margin-bottom: 10px; +} + +article { + margin-left: 10px; + padding: 5px; +} + diff --git a/kontor-angular/tsconfig.app.json b/kontor-angular/tsconfig.app.json new file mode 100644 index 0000000..264f459 --- /dev/null +++ b/kontor-angular/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.spec.ts" + ] +} diff --git a/kontor-angular/tsconfig.json b/kontor-angular/tsconfig.json new file mode 100644 index 0000000..e4955f2 --- /dev/null +++ b/kontor-angular/tsconfig.json @@ -0,0 +1,34 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "compileOnSave": false, + "compilerOptions": { + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "typeCheckHostBindings": true, + "strictTemplates": true + }, + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/kontor-angular/tsconfig.spec.json b/kontor-angular/tsconfig.spec.json new file mode 100644 index 0000000..04df34c --- /dev/null +++ b/kontor-angular/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/kontor-api/.coverage b/kontor-api/.coverage deleted file mode 100644 index 44d6ca261d7b921a433a3387e3cb7b53e796297f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeI4Z;aeV6~OJa*Iw`1JG-~HU4>H>3(;JT-reRDDTOA=<=-U@RD?nVLP%_UyS|*; z+x5ow=5mB`-J~S~gg}*O1gbco5=bB+B*Yh}lNSdERf{%;A_A) z-c(4)@eagdUwX5oCQN?vBL@4Bpevsf*vE`xY(jt9*p|DhH?_~?zM@)M9S+b&1c(3; zAOip21iBCDYGun7@!X?jNKFf<+1Ed1`B&cY6PSf(1 z%t!2{ab6%gTVS6F!VFMiJ11LM!rUH-kC~o5XM1+5Zu?;^wmXfn?AZC`tXe6R#0xgJ z$@1#($*r*lGJ2*QodZR6*K1(yXFaP`pSS&S(^|E#?m|7!1fjK_+pGqzx!|<8nJwQ5 z9JgiKXY6_>up1j1IF8Wb4dC@#1G-M2K_^1V=v;ktdcqq>M#UrHIjCIAjj{Fw@zfy9 z>)h%zX94-con{*w2PDE12kvH)o5==lWb7@s%?54Rvv*B%#>lZnL#a;7In}XO8-LvF zNse>xFP!3z zf_Q4PPT;R5v^7q%n!SnZ;PK7<27Ad`C&6B{uwc4#yvv}p88!}hbAO+y#xN`oJDTZ6 z1)-*IskdQep$_Kkf;+p`*SN>{Hgpge3*usPomL&YijOwb-P5*bowO&Tqv5ddRyz{7 z&XlH9X0~qTI;$>Fn_5j~yIT~sGBP5b)3_T&trbP;8W)ONa)V(sKGd`=zvION$;}4I zSfV#d#(g9@0_IGpN@f4ZX68iYYEw}n(^X})QZ9?#ut(sygx~ZUBQU4e1#XxKZoT?# zE0{Oe*B!H=;-hJ$vb(%l#jy&tDGZhKA5HNpU)aLwH(}7nue7GhnA5BBd+nu()7Aov zCT+{{pv%G-9L@kH7Hn8h*qU`a0ry|r3*j6i?8$jZy59f4zlhEiwciDuJkHKO?nr{Pd5jQ!X-@jT%m0)pl!bV?t(=nXn!rO{Cwv10v`ZD4|0n^q(2 z?${`O8W-p7b?U;|=#UlIfzz~2EW#_p9c$6@&AMm9L6}R&Mx~p%0k&3c3PW5aXYi+7 zcdMvY?!8y+cB0N0jx#kMCiSKjS3BBGt#OhY4)*-z7!0`ZYp35&kX;`R+zrowgIm~w zvmu4JRP>Y5g-CY;Lal;i78RV^?!=} zUSO|4KpPPt0z`la5CI}U1c(3;AOb{y2oM1xaC;KaQ_|fm{)@*BCQ2if=uZImO}=Y# zM;5F~u@?pQBK!O8X&}{_2oM1xKm>>Y5g-CYfCvx)B0vO)01=1@=+fO{d=(&-l}5Da zA^_h1FK3qp_G5OA9cKCbbNMIoGkM9lWCX^z{%8H``U(B6+%I#V&%G~~&R&9|v=IR! zKm>>Y5g-CYfCvzQK?&?F%R*PI&bv*!8nkUY_;|JLxewd*z^^_6FS>BOD4MX^PSyA7 z)$qaAYOv(j;c?$X!ys=Yk#D*Ud%@@ORln_e0cbf=0xhLMwbW`(%L!^VP&7RRiliip zJb17h9&?WEnJy+(5b({fiFWaSX8|I0IS*GMG4(fWV*0l8ZmSWDlp>C!&ADX^?!cQ#)($ltLuMbP`2?hS3e?mi-~O6c>SMy zkKC>N4|@6>E_+b!YJ;fi)1eLAL@}7mpuIR+|Er0uSik;P4$0kIA`-Eq^`S`LC;5qV zL~C$)w{$j>Y5x7GL43%Y3+g5&R@r_TcEM9x#)n`}!$<$%UD-2%|l@cWKB~cy1jG@!N zC>9~{j^YbHyGJzPZu;fx*SBN}kTq2J@^VgLSel82Jj8F$w-yy)haf15pl1v$W9<52 zWk`qAHvOrK|62a^%Jj;A_EfL2Ob(CccD=HqWFeK$ii(D@Ch8f8- z>@Vz(a0TEu>?*qgPx?R0zR$kHzRA7{*8!enpJk7;N7-p8N*fU%0z`la5CI}U1c(3; zAOb{y2oM1xaB~8;K!k4XO4-fCvx)B0vO)01+SpM1Tko0U|&I-i$!_{QpJ#|NlSO zHTDww6Z-@EEj$D8EA~8lj{THfVn2ZA0KNJlc?=8;bPRGBWHHb%$Y7vipkR>3 OK*m7AAcX=4.13.4", "fastapi[standard]>=0.115.12", "httpx==0.24.1", - "mariadb>=1.1.12", "sqlalchemy>=2.0.40", "platformdirs>=4.3.7", "pathlib>=1.0.1", @@ -19,7 +18,15 @@ dependencies = [ "sqlalchemy>=2.0.40", "sqlmodel>=0.0.24", "python-dotenv>=1.1.0", - "python-jose>=3.4.0", + "python-jose[cryptography]>=3.4.0", "python-multipart>=0.0.20", "natsort>=8.4.0", + "psycopg2-binary>=2.9.10", + "pytest-cov>=6.1.1", + "databases[sqlite]>=0.9.0", + "pydantic[email]>=2.11.3", + "jinja2>=3.1.6", + "asyncpg>=0.30.0", + "bcrypt>=4.3.0", + "fastapi-jwt-auth>=0.5.0", ] diff --git a/kontor-api/src/apis/base.py b/kontor-api/src/apis/base.py index e969691..fbae827 100644 --- a/kontor-api/src/apis/base.py +++ b/kontor-api/src/apis/base.py @@ -1,8 +1,11 @@ from fastapi import APIRouter -from src.apis.version1 import comic, media, tysc +from src.apis.version1 import comic, mediaactor, mediafile, mediaactorfile, tysc, admin api_router = APIRouter(prefix="/api") api_router.include_router(comic.router, prefix="/comics", tags=["comics"]) -api_router.include_router(media.router, prefix="/media", tags=["media"]) +api_router.include_router(mediafile.router, prefix="/media", tags=["media"]) +api_router.include_router(mediaactor.router, prefix="/media", tags=["media"]) +api_router.include_router(mediaactorfile.router, prefix="/media", tags=["media"]) api_router.include_router(tysc.router, prefix="/tysc", tags=["tysc"]) +api_router.include_router(admin.router, prefix="/login", tags=["login"]) diff --git a/kontor-api/src/apis/utils.py b/kontor-api/src/apis/utils.py deleted file mode 100644 index 716d2be..0000000 --- a/kontor-api/src/apis/utils.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Annotated - -from fastapi import Depends -from sqlalchemy.orm import Session - -from src.db.session import get_db - -SessionDep = Annotated[Session, Depends(get_db)] diff --git a/kontor-api/src/apis/version1/admin.py b/kontor-api/src/apis/version1/admin.py new file mode 100644 index 0000000..6214a45 --- /dev/null +++ b/kontor-api/src/apis/version1/admin.py @@ -0,0 +1,52 @@ +from datetime import timedelta +from typing import Annotated + +from fastapi import APIRouter, Body, HTTPException, status, Depends, Response +from fastapi.security import OAuth2PasswordRequestForm + +from src.core.config import settings +from src.core.security import create_access_token, authenticate_user, get_current_active_user +from src.db.models.admin import Profile +from src.schema.admin import Token, ProfileModel +from src.webapps.auth.forms import LoginForm + +router = APIRouter() + + +@router.post("/token") +def login_for_access_token(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> Token: + user = authenticate_user(form_data.username, form_data.password) + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.email, "scope": " ".join(form_data.scopes)}, expires_delta=access_token_expires + ) + return Token(access_token=access_token, token_type="bearer") + + +# @router.post("/token-cookie", response_model=Token) +def login_for_token_cookie(response: Response, form_data: LoginForm = Depends()): + user = authenticate_user(form_data.username, form_data.password) # type: ignore + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + ) + access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.email}, expires_delta=access_token_expires + ) + response.set_cookie( + key="access_token", value=f"Bearer {access_token}", httponly=True + ) + return {"access_token": access_token, "token_type": "bearer"} + + +@router.get("/profile", response_model=ProfileModel) +async def read_profile(current_user: Annotated[Profile, Depends(get_current_active_user)]): + return current_user diff --git a/kontor-api/src/apis/version1/comic.py b/kontor-api/src/apis/version1/comic.py index a558b3b..9a955f6 100644 --- a/kontor-api/src/apis/version1/comic.py +++ b/kontor-api/src/apis/version1/comic.py @@ -1,53 +1,68 @@ -from uuid import UUID from typing import List + from fastapi import APIRouter, HTTPException, status -from sqlalchemy import select -from src.apis.utils import SessionDep -from src.schema.comics.comic import ComicResponse, ComicDetailsResponse, get_comic_details, get_short_info -from src.schema.comics.artist import ArtistCreation, ArtistDetailResponse, ArtistResponse, get_artist_details -from src.db.models.comic import Comic, Artist - -router = APIRouter( - prefix="/comic", - tags=["comics"], - responses={404: {"description": "Not found"}}, +from src.core.log_conf import logger +from src.db.models.comic import Artist, Comic, Issue, Publisher +from src.db.repository.comics.artist import get_artist_details +from src.db.repository.comics.comic import ( + get_comic_details, + get_issue_details, + get_short_info, + list_comics, ) +from src.db.repository.comics.publisher import get_publisher_details +from src.db.session import SessionDep +from src.schema.comics.artist import ArtistCreation, ArtistResponse +from src.schema.comics.artist_details import ArtistDetailResponse +from src.schema.comics.comic import ComicResponse +from src.schema.comics.comic_details import ComicDetailsResponse +from src.schema.comics.issue_details import IssueDetailsResponse +from src.schema.comics.publisher import PublisherResponse +from src.schema.comics.publisher_details import PublisherDetailsResponse + +router = APIRouter() @router.get("/comics") def get_all_comics(db: SessionDep) -> List[ComicResponse]: results: List[ComicResponse] = [] - comics = db.scalars(select(Comic)).all() + comics = list_comics(db) for comic in comics: response = get_short_info(comic) results.append(response) return results + @router.get("/comics/{comic_id}", response_model=ComicDetailsResponse) -def get_comic(comic_id: UUID, db: SessionDep) -> ComicDetailsResponse: +def get_comic(comic_id: str, db: SessionDep) -> ComicDetailsResponse: comic = db.get(Comic, comic_id) if comic is None: raise HTTPException(status_code=404, detail="Comic could not be found") + logger.info(f"create ComicDetailsResponse for {comic}") response: ComicDetailsResponse = get_comic_details(comic) + logger.info(f"ComicDetailsResponse: {response}") return response + @router.get("/artists", response_model=List[ArtistResponse]) def get_all_artists(db: SessionDep) -> List[ArtistResponse]: results: List[ArtistResponse] = [] artists = db.query(Artist).all() for artist in artists: - results.append(ArtistResponse(id=artist.id, name=artist.name)) + results.append(ArtistResponse(id=artist.id, name=str(artist.name))) # type: ignore return results + @router.get("/artists/{artist_id}", response_model=ArtistDetailResponse) -def get_artist(artist_id: UUID, db: SessionDep) -> ArtistDetailResponse: +def get_artist(artist_id: str, db: SessionDep) -> ArtistDetailResponse: artist = db.get(Artist, artist_id) if artist is None: raise HTTPException(status_code=404, detail="Artist could not be found") response: ArtistDetailResponse = get_artist_details(artist) return response + @router.post("/artists", status_code=status.HTTP_201_CREATED) def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistResponse: artist: Artist = Artist() @@ -57,6 +72,32 @@ def add_artist(db: SessionDep, artist_creation: ArtistCreation) -> ArtistRespons db.commit() except: raise HTTPException(status_code=409, detail="Artist already added") - response = ArtistResponse(id=artist.id, name=artist.name) + response = ArtistResponse(id=artist.id, name=str(artist.name)) return response + +@router.get("/publishers", response_model=List[PublisherResponse]) +def get_all_publishers(db: SessionDep) -> List[PublisherResponse]: + results: List[PublisherResponse] = [] + publishers = db.query(Publisher).all() + for publisher in publishers: + results.append(PublisherResponse(id=publisher.id, name=str(publisher.name))) + return results + + +@router.get("/publishers/{publisher_id}", response_model=PublisherDetailsResponse) +def get_publisher(publisher_id: str, db: SessionDep) -> PublisherDetailsResponse: + publisher = db.get(Publisher, publisher_id) + if publisher is None: + raise HTTPException(status_code=404, detail="Publisher could not be found") + response: PublisherDetailsResponse = get_publisher_details(publisher) + return response + + +@router.get("/issues", response_model=List[IssueDetailsResponse]) +def get_issues(db: SessionDep) -> List[IssueDetailsResponse]: + results: List[IssueDetailsResponse] = [] + issues = db.query(Issue).all() + for issue in issues: + results.append(get_issue_details(issue)) + return results diff --git a/kontor-api/src/apis/version1/healthcheck.py b/kontor-api/src/apis/version1/healthcheck.py new file mode 100644 index 0000000..c531634 --- /dev/null +++ b/kontor-api/src/apis/version1/healthcheck.py @@ -0,0 +1,25 @@ +from fastapi import APIRouter, status + +from src.schema.admin import HealthCheck + +health_router = APIRouter() + + +@health_router.get( + "/health", + tags=["healthcheck"], + summary="Perform a health check", + response_description="Return HTTP status code 200 (OK)", + status_code=status.HTTP_200_OK +) +def health_check() -> HealthCheck: + """ + ## Perform a health check + Endpoint to perform a healthcheck on. This endpoint can primarily be used Docker + to ensure a robust container orchestration and management is in place. Other + services which rely on proper functioning of the API service will not deploy if this + endpoint returns any other HTTP status code except 200 (OK). + :return: + HealthCheck: Returns a JSON response with the health status + """ + return HealthCheck(status="ok") diff --git a/kontor-api/src/apis/version1/login.py b/kontor-api/src/apis/version1/login.py new file mode 100644 index 0000000..f6b28b7 --- /dev/null +++ b/kontor-api/src/apis/version1/login.py @@ -0,0 +1,41 @@ +from datetime import timedelta + +from fastapi import APIRouter, HTTPException, status +from pydantic import BaseModel + +from src.core.config import settings +from src.core.log_conf import logger +from src.core.security import authenticate_user, create_access_token +from src.schema.admin import Token + +login_router = APIRouter() + + +class LoginRequest(BaseModel): + email: str | None = None + password: str | None = None + + +@login_router.post( + "/login", + tags=["login"], + summary="Login and get token", + response_description="Return HTTP status code 200 (OK)", + status_code=status.HTTP_200_OK, +) +def login(request: LoginRequest) -> Token: + logger.info(f"login with {request.email}") + user = authenticate_user(request.email, request.password) # type: ignore + scopes = ["admin", "read"] + if not user: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user.email, "scope": " ".join(scopes)}, + expires_delta=access_token_expires, + ) + return Token(access_token=access_token, token_type="bearer") diff --git a/kontor-api/src/apis/version1/media.py b/kontor-api/src/apis/version1/media.py deleted file mode 100644 index 2fa7347..0000000 --- a/kontor-api/src/apis/version1/media.py +++ /dev/null @@ -1,76 +0,0 @@ -from typing import List -from uuid import UUID - -from fastapi import APIRouter, status, HTTPException -from sqlalchemy import select, Sequence - -from src.apis.utils import SessionDep -from src.schema.media.file import MediaFileResponse, Link, get_file_details, set_file -from src.db.models.media import MediaFile - -router = APIRouter( - prefix="/media", - tags=["media"] -) - -@router.get("/update-titles") -def update_titles(db: SessionDep) -> list[MediaFileResponse]: - results: list[MediaFileResponse] = [] - files = db.query(MediaFile).filter(MediaFile.review == 1).all() - for mediafile in files: - mediafile.update_title() - db.add(mediafile) - response = get_file_details(mediafile) - results.append(response) - db.commit() - return results - - -@router.get("/files", response_model=List[MediaFileResponse]) -def get_all_files(db: SessionDep, review: bool = False, download: bool = False) -> List[MediaFileResponse]: - results: list[MediaFileResponse] = [] - files: Sequence[MediaFile] - if review: - files = db.query(MediaFile).filter(MediaFile.review == 1).all() - elif download: - files = db.query(MediaFile).filter(MediaFile.should_download == 1).all() - else: - files = db.scalars(select(MediaFile)).all() - for mediafile in files: - response = get_file_details(mediafile) - results.append(response) - return results - -@router.get("/files/{file_id}", response_model=MediaFileResponse) -def get_file(file_id: UUID, db: SessionDep) -> MediaFileResponse: - mediafile = db.get(MediaFile, file_id) - if not mediafile: - raise HTTPException(status_code=404, detail="MediaFile could not be found") - response = get_file_details(mediafile) - return response - -@router.put("/files/{file_id}", response_model=MediaFileResponse) -def update_file(file_id: UUID, db: SessionDep, info: MediaFileResponse) -> MediaFileResponse: - mediaFile = db.get(MediaFile, file_id) - if not mediaFile: - raise HTTPException(status_code=404, detail="MediaFile could not be found") - set_file(info, mediaFile) - db.add(mediaFile) - db.commit() - return info - - -@router.post("/files", status_code=status.HTTP_201_CREATED) -def add_file(new_link: Link, db: SessionDep) -> MediaFileResponse: - print(new_link.url) - try: - mediaFile: MediaFile = MediaFile() - setattr(mediaFile, "url", new_link.url) - setattr(mediaFile, "review", 1) - setattr(mediaFile, "should_download", 1) - db.add(mediaFile) - db.commit() - except: - raise HTTPException(status_code=409, detail="Link duplicate") - response = get_file_details(mediaFile) - return response diff --git a/kontor-api/src/apis/version1/mediaactor.py b/kontor-api/src/apis/version1/mediaactor.py new file mode 100644 index 0000000..ec2c236 --- /dev/null +++ b/kontor-api/src/apis/version1/mediaactor.py @@ -0,0 +1,48 @@ +from fastapi import APIRouter, status, HTTPException +from sqlalchemy import select +from src.core.log_conf import logger +from src.db.repository.media import create_new_mediaactor, delete_mediaactor +from src.db.session import SessionDep +from src.schema.media.actor import Actor, MediaActorResponse, get_actor_details +from src.db.models.media import MediaActor + +router = APIRouter() + +@router.get("/actors", response_model=list[MediaActorResponse]) +# def get_all_files(db: SessionDep, review: bool = False, download: bool = False, current_user: Profile = Depends(get_current_user_from_token)) -> List[MediaFileResponse]: +def get_all_actors(db: SessionDep, review: bool = False, download: bool = False) -> list[MediaActorResponse]: # type: ignore + results: list[MediaActorResponse] = [] + actors = db.scalars(select(MediaActor)).all() + for mediaactor in actors: + response = MediaActorResponse(id=mediaactor.id, name=str(mediaactor.name), url=str(mediaactor.url)) + results.append(response) + return results + +@router.get("/actors/{actor_id}", response_model=MediaActorResponse) +def get_actor(actor_id: str, db: SessionDep) -> MediaActorResponse: # type: ignore + media_actor = db.get(MediaActor, actor_id) + if not media_actor: + raise HTTPException(status_code=404, detail="MediaActor could not be found") + response = get_actor_details(media_actor) + return response + +@router.delete("/actors/{actor_id}", status_code=status.HTTP_204_NO_CONTENT) +def delete_actor(actor_id: str, db: SessionDep): # type: ignore + media_actor = db.get(MediaActor, actor_id) + if not media_actor: + raise HTTPException(status_code=404, detail="MediaActor could not be found") + logger.info(f"delete MediaActor: {actor_id}") + actor_files = media_actor.media_actor_files + logger.info(f"MediaActorFiles links {len(actor_files)}") + if len(actor_files) == 0: + delete_mediaactor(db, media_actor.id) + +@router.post("/actors", status_code=status.HTTP_201_CREATED) +def add_actor(new_actor: Actor, db: SessionDep) -> MediaActorResponse: # type: ignore + logger.info(f"add actor {new_actor.url}") + try: + mediaActor: MediaActor = create_new_mediaactor(new_actor, db) + except: + raise HTTPException(status_code=409, detail="Link duplicate") + response = get_actor_details(mediaActor) + return response diff --git a/kontor-api/src/apis/version1/mediaactorfile.py b/kontor-api/src/apis/version1/mediaactorfile.py new file mode 100644 index 0000000..2d9524c --- /dev/null +++ b/kontor-api/src/apis/version1/mediaactorfile.py @@ -0,0 +1,33 @@ +from fastapi import APIRouter, status, HTTPException +from sqlalchemy import select +from src.db.models.media import MediaActorFile +from src.db.repository.media import delete_mediaactorfile +from src.db.session import SessionDep +from src.schema.media.actorfile import MediaActorFileResponse, get_actorfile_details + +router = APIRouter() + +@router.get("/actorfiles", response_model=list[MediaActorFileResponse]) +def get_all_actorfiles(db: SessionDep) -> list[MediaActorFileResponse]: # type: ignore + results: list[MediaActorFileResponse] = [] + actorfiles = db.scalars(select(MediaActorFile)).all() + for mediaactorfile in actorfiles: + response = MediaActorFileResponse(id=mediaactorfile.id, actor_id=str(mediaactorfile.media_actor_id), file_id=str(mediaactorfile.media_file_id)) + results.append(response) + return results + +@router.get("/actorfiles/{actorfile_id}", response_model=MediaActorFileResponse) +def get_actorfile(actorfile_id: str, db: SessionDep) -> MediaActorFileResponse: # type: ignore + media_actorfile = db.get(MediaActorFile, actorfile_id) + if not media_actorfile: + raise HTTPException(status_code=404, detail="MediaActor could not be found") + response = get_actorfile_details(media_actorfile) + return response + +@router.delete("/actorfiles/{actorfile_id}", status_code=status.HTTP_204_NO_CONTENT) +def delete_actorfile(actorfile_id: str, db: SessionDep): # type: ignore + media_actorfile = db.get(MediaActorFile, actorfile_id) + if not media_actorfile: + raise HTTPException(status_code=404, detail="MediaActor could not be found") + delete_mediaactorfile(db, media_actorfile.id) + diff --git a/kontor-api/src/apis/version1/mediafile.py b/kontor-api/src/apis/version1/mediafile.py new file mode 100644 index 0000000..9823fbf --- /dev/null +++ b/kontor-api/src/apis/version1/mediafile.py @@ -0,0 +1,120 @@ +from fastapi import APIRouter, status, HTTPException, Depends +from sqlalchemy import select, Sequence +from src.core.log_conf import logger +from src.db.repository.media import create_new_mediaactorfile, create_new_mediafile, delete_mediafile +from src.db.session import SessionDep +from src.schema.media.actor import MediaActorResponse +from src.schema.media.actorfile import MediaActorFileResponse +from src.schema.media.file import MediaFileResponse, Link, get_file_details, set_file +from src.db.models.media import MediaFile + +router = APIRouter() + +@router.get("/update-titles") +def update_titles(db: SessionDep) -> list[MediaFileResponse]: # type: ignore + results: list[MediaFileResponse] = [] + files = db.query(MediaFile).filter(MediaFile.review == True).all() + for mediafile in files: + mediafile.update_title() + db.add(mediafile) + response = get_file_details(mediafile) + results.append(response) + db.commit() + return results + + +@router.get("/files", response_model=list[MediaFileResponse]) +# def get_all_files(db: SessionDep, review: bool = False, download: bool = False, current_user: Profile = Depends(get_current_user_from_token)) -> List[MediaFileResponse]: +def get_all_files(db: SessionDep, review: bool = False, download: bool = False) -> list[MediaFileResponse]: # type: ignore + results: list[MediaFileResponse] = [] + files: Sequence[MediaFile] + if review: + files = db.query(MediaFile).filter(MediaFile.review == True).all() # type: ignore + elif download: + files = db.query(MediaFile).filter(MediaFile.should_download == True).all() # type: ignore + else: + files = db.scalars(select(MediaFile)).all() # type: ignore + for mediafile in files: # type: ignore + response = get_file_details(mediafile) + results.append(response) + return results + +@router.get("/files/{file_id}", response_model=MediaFileResponse) +def get_file(file_id: str, db: SessionDep) -> MediaFileResponse: # type: ignore + mediafile = db.get(MediaFile, file_id) + if not mediafile: + raise HTTPException(status_code=404, detail="MediaFile could not be found") + response = get_file_details(mediafile) + return response + +@router.delete("/files/{file_id}", status_code=status.HTTP_204_NO_CONTENT) +def delete_file(file_id: str, db: SessionDep): # type: ignore + mediafile = db.get(MediaFile, file_id) + if not mediafile: + raise HTTPException(status_code=404, detail="MediaFile could not be found") + logger.info(f"delete MediaFile: {file_id}") + actor_files = mediafile.media_actor_files + logger.info(f"MediaActorFiles links {len(actor_files)}") + if len(actor_files) == 0: + delete_mediafile(db, mediafile.id) + +@router.get("/files/{file_id}/actors", response_model=list[MediaActorResponse]) +def get_file_actors(file_id: str, db: SessionDep) -> list[MediaActorResponse]: # type: ignore + mediafile = db.get(MediaFile, file_id) + if not mediafile: + raise HTTPException(status_code=404, detail="MediaFile could not be found") + actor_files = mediafile.media_actor_files + logger.info(f"already known actors: {actor_files}") + results: list[MediaActorResponse] = [] + for actor_file in actor_files: + response = MediaActorResponse(id=actor_file.media_actor.id, name=actor_file.media_actor.name, url=actor_file.media_actor.url) + results.append(response) + return results + +@router.put("/files/{file_id}/actors", response_model=list[MediaActorFileResponse]) +def update_file_actors(file_id: str, db: SessionDep, actors: list[MediaActorResponse]) -> list[MediaActorFileResponse]: # type: ignore + mediafile = db.get(MediaFile, file_id) + if not mediafile: + raise HTTPException(status_code=404, detail="MediaFile could not be found") + actor_files = mediafile.media_actor_files + logger.info(f"already known actors: {actor_files}") + for actor in actors: + already_associated = False + for actor_file in actor_files: + if actor.id == actor_file.media_actor_id: + logger.info("alreay associated - do nothing") + already_associated = True + break + if not already_associated: + create_new_mediaactorfile(db, actor.id, mediafile.id) + db.refresh(mediafile) + actor_files = mediafile.media_actor_files + results: list[MediaActorFileResponse] = [] + for actor_file in actor_files: + response = MediaActorFileResponse(id=actor_file.id, actor_id=actor_file.media_actor_id, file_id=actor_file.media_file_id) + results.append(response) + return results + +@router.put("/files/{file_id}", response_model=MediaFileResponse) +def update_file(file_id: str, db: SessionDep, info: MediaFileResponse) -> MediaFileResponse: # type: ignore + mediaFile = db.get(MediaFile, file_id) + if not mediaFile: + raise HTTPException(status_code=404, detail="MediaFile could not be found") + set_file(info, mediaFile) + db.add(mediaFile) + db.commit() + mediafile = db.get(MediaFile, file_id) + if not mediafile: + raise HTTPException(status_code=404, detail="MediaFile could not be updated") + response = get_file_details(mediafile) + return response + +@router.post("/files", status_code=status.HTTP_201_CREATED) +def add_file(new_link: Link, db: SessionDep) -> MediaFileResponse: # type: ignore + logger.info(f"add url {new_link.url}") + try: + mediaFile: MediaFile = create_new_mediafile(new_link.url, db) + except: + raise HTTPException(status_code=409, detail="Link duplicate") + response = get_file_details(mediaFile) + return response diff --git a/kontor-api/src/apis/version1/tysc.py b/kontor-api/src/apis/version1/tysc.py index 1128771..9d68288 100644 --- a/kontor-api/src/apis/version1/tysc.py +++ b/kontor-api/src/apis/version1/tysc.py @@ -1,15 +1,11 @@ from typing import List from fastapi import APIRouter -from src.apis.utils import SessionDep +from src.db.session import SessionDep from src.schema.tysc.sport import SportResponse from src.db.models.tysc import Sport -router = APIRouter( - prefix="/tysc", - tags=["tysc"], - responses={404: {"description": "Not found"}}, -) +router = APIRouter() @router.get("/sports") def get_all_sports(db: SessionDep) -> List[SportResponse]: diff --git a/kontor-api/src/core/config.py b/kontor-api/src/core/config.py index 5f14424..135454f 100644 --- a/kontor-api/src/core/config.py +++ b/kontor-api/src/core/config.py @@ -9,15 +9,17 @@ load_dotenv(dotenv_path=env_path) class Settings: PROJECT_NAME: str = "Kontor" - PROJECT_VERSION: str = "0.1.0" - - MARIADB_USER: str = os.getenv("MARIADB_USER", "kontor") - MARIADB_PASSWORD: str = os.getenv("MARIADB_PASSWORD", "kontor") - MARIADB_SERVER: str = os.getenv("MARIADB_SERVER", "mariadb") - MARIADB_PORT: str = os.getenv("MARIADB_PORT", 3306) - MARIADB_DB: str = os.getenv("MARIADB_DB", "kontor") - DATABASE_URL: str = f"mariadb+mariadbconnector://{MARIADB_USER}:{MARIADB_PASSWORD}@{MARIADB_SERVER}:{MARIADB_PORT}/{MARIADB_DB}" + PROJECT_VERSION: str = "0.2.0" + DB_USER: str = os.getenv("DB_USER", "kontor") + DB_PASSWORD: str = os.getenv("DB_PASSWORD", "kontor") + DB_SERVER: str = os.getenv("DB_SERVER", "postgres") + DB_PORT: int = int(os.getenv("DB_PORT", 5432)) + DB_DBNAME: str = os.getenv("DB_DBNAME", "kontor") + DATABASE_URL: str = f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_SERVER}:{DB_PORT}/{DB_DBNAME}" + SECRET_KEY: str = os.getenv("SECRET_KEY", "J6GOtcwC2NJI1l0VkHu20PacPFGTxpirBxWwynoHjsc=") + ALGORITHM = "HS256" + ACCESS_TOKEN_EXPIRE_MINUTES = 60*24*7 # one week in mins settings = Settings() diff --git a/kontor-api/src/core/log_conf.py b/kontor-api/src/core/log_conf.py new file mode 100644 index 0000000..c33186f --- /dev/null +++ b/kontor-api/src/core/log_conf.py @@ -0,0 +1,49 @@ +import logging +import logging.config +from typing import Any + +LOGGING_CONFIG: dict[str, Any] = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "fmt": "%(asctime)s - %(name)s - %(levelprefix)s %(message)s", + }, + "access": { + "()": "uvicorn.logging.AccessFormatter", + "fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501 + }, + "access_file": { + "()": "uvicorn.logging.AccessFormatter", + "fmt": '%(asctime)s - %(name)s - %(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501 + "use_colors": False, + }, + }, + "handlers": { + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + "error": { + "formatter": "access", + "class": "logging.StreamHandler", + "stream": "ext://sys.stderr", + }, + }, + "loggers": { + "root": {"handlers": ["default"], "level": "INFO", "propagate": False}, + "kontor": {"handlers": ["default"], "level": "INFO", "propagate": False}, + "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False}, + "uvicorn.error": {"level": "INFO"}, + "uvicorn.access": { + "handlers": ["default"], + "level": "WARNING", + "propagate": False, + }, + }, +} + +logging.config.dictConfig(LOGGING_CONFIG) +logger = logging.getLogger("kontor") diff --git a/kontor-api/src/core/security.py b/kontor-api/src/core/security.py new file mode 100644 index 0000000..10c8796 --- /dev/null +++ b/kontor-api/src/core/security.py @@ -0,0 +1,156 @@ +import logging +from datetime import datetime, timedelta, timezone +from typing import Annotated, Dict, List, Optional + +import bcrypt +from fastapi import Depends, HTTPException, Request, Security, status +from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel +from fastapi.security import OAuth2, OAuth2PasswordBearer, SecurityScopes +from fastapi.security.utils import get_authorization_scheme_param +from jose import JWTError, jwt +from pydantic import ValidationError + +from src.core.config import settings +from src.core.log_conf import logger +from src.db.models.admin import Profile +from src.db.repository.admin import get_profile +from src.db.session import SessionLocal +from src.schema.admin import ProfileModel, TokenData + +oauth2_scheme = OAuth2PasswordBearer( + tokenUrl="/api/login/token", + scopes={"me": "read", "admin": "read"}, +) + + +class OAuth2PasswordBearerWithCookie(OAuth2): + def __init__( + self, + tokenUrl: str, + scheme_name: Optional[str] = None, + scopes: Optional[Dict[str, str]] = None, + auto_error: bool = True, + ): + if not scopes: + scopes = {} + flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes}) # type: ignore + super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error) + + async def __call__(self, request: Request) -> Optional[str]: + authorization: str = request.cookies.get("access_token") # type: ignore # changed to accept access token from httpOnly Cookie + + scheme, param = get_authorization_scheme_param(authorization) + if not authorization or scheme.lower() != "bearer": + if self.auto_error: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers={"WWW-Authenticate": "Bearer"}, + ) + else: + return None + return param + + +def authenticate_user(username: str, password: str) -> Optional[Profile]: + with SessionLocal() as db: + user = get_profile(username=username, db=db) + logger.debug(user) + if not user: + return None + if bcrypt.checkpw(password.encode(), user.password.encode()): + print("User successful authenticated") + else: + logger.info("Authentication failed!") + return user + + +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.now(timezone.utc) + expires_delta + else: + expire = datetime.now(timezone.utc) + timedelta( + minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES + ) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode( + to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM + ) + return encoded_jwt + + +async def get_current_user( + security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)] +): + if security_scopes.scopes: + authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' + else: + authenticate_value = "Bearer" + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": authenticate_value}, + ) + try: + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + username: str = payload.get("sub") # type: ignore + logger.info("username/email extracted is ", username) + if username is None: + raise credentials_exception + scope: str = payload.get("scope", "") + token_scopes: List[str] = scope.split(" ") + token_data = TokenData(scopes=token_scopes, username=username) + except (JWTError, ValidationError): + raise credentials_exception + with SessionLocal() as db: + user = get_profile(username=token_data.username, db=db) # type: ignore + if user is None: + raise credentials_exception + for scope in security_scopes.scopes: + if scope not in token_scopes: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="not enough permissions", + headers={"WWW-Authenticate": authenticate_value}, + ) + return user + + +async def get_current_active_user( + current_user: Annotated[Profile, Security(get_current_user, scopes=["me"])], +) -> ProfileModel: + if not current_user.enabled: # type: ignore + raise HTTPException(status_code=400, detail="Inactive user") + user_model = ProfileModel( + username=current_user.user_name, + email=current_user.email, # type: ignore + first_name=current_user.first_name, + last_name=current_user.last_name, # type: ignore + active=current_user.enabled, + ) # type: ignore + return user_model + + +def get_current_user_from_token(token: str = Depends(oauth2_scheme)): + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + ) + try: + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + username: str = payload.get("sub") # type: ignore + logger.info("username/email extracted is ", username) + if username is None: + raise credentials_exception + except JWTError: + raise credentials_exception + with SessionLocal() as db: + user = get_profile(username=username, db=db) + if user is None: + raise credentials_exception + return user diff --git a/kontor-api/src/db/models/admin.py b/kontor-api/src/db/models/admin.py index e16b0e0..723dffc 100644 --- a/kontor-api/src/db/models/admin.py +++ b/kontor-api/src/db/models/admin.py @@ -1,7 +1,6 @@ from datetime import datetime -from sqlalchemy import Column, ForeignKey, Integer, String -from sqlalchemy.dialects.mysql import BIT +from sqlalchemy import Column, ForeignKey, Integer, String, Boolean from sqlalchemy.orm import relationship, mapped_column, Mapped from src.db.models.base import Base, BaseMixin @@ -9,12 +8,12 @@ from src.db.models.base import Base, BaseMixin class Profile(Base, BaseMixin): __tablename__ = 'profile' - first_name = Column(String(255)) - last_name = Column(String(255)) - user_name = Column(String(255), nullable=False) - email = Column(String(255)) - password = Column(String(255)) - enabled = Column(BIT(1)) + first_name = Column(String) + last_name = Column(String) + user_name = Column(String, nullable=False) + email = Column(String) + password = Column(String) + enabled = Column(Boolean) assignments = relationship("Assignment") tokens = relationship("Token") @@ -28,20 +27,23 @@ class Profile(Base, BaseMixin): full_name += self.last_name return full_name + def __str__(self): + return f"Profile({self.id} {self.user_name}, {self.email})" + class Token(Base, BaseMixin): __tablename__ = "token" - token = Column(String(255), nullable=False, unique=True) - name = Column(String(255)) + token = Column(String, nullable=False, unique=True) + name = Column(String) last_used_date: Mapped[datetime] = mapped_column() - enabled = Column(BIT(1)) - profile_id = Column(String(255), ForeignKey("profile.id"), nullable=False) + enabled = Column(Boolean) + profile_id = Column(String, ForeignKey("profile.id"), nullable=False) profile = relationship("Profile", back_populates="tokens") class Permission(Base, BaseMixin): __tablename__ = "permission" - name = Column(String(255), nullable=False) + name = Column(String, nullable=False) assignments = relationship("Assignment") @@ -53,20 +55,14 @@ class Assignment(Base, BaseMixin): permission = relationship("Permission", back_populates="assignments") -class ModuleData(Base, BaseMixin): - __tablename__ = "module_data" - module_name = Column(String(255), nullable=False) - import_data = Column(BIT(1)) - - class MailAccount(Base, BaseMixin): __tablename__ = "mail_account" - host = Column(String(255)) + host = Column(String) port = Column(Integer) - protocol = Column(String(255)) - user_name = Column(String(255)) - password = Column(String(255)) - start_tls = Column(BIT(1)) + protocol = Column(String) + user_name = Column(String) + password = Column(String) + start_tls = Column(Boolean) class Mail(Base, BaseMixin): diff --git a/kontor-api/src/db/models/base.py b/kontor-api/src/db/models/base.py index 4a354e7..79755ff 100644 --- a/kontor-api/src/db/models/base.py +++ b/kontor-api/src/db/models/base.py @@ -1,8 +1,7 @@ import uuid from datetime import datetime -from sqlalchemy import func, Column, String -from sqlalchemy.dialects.mysql import BIT +from sqlalchemy import func, Column, String, Boolean from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column @@ -11,8 +10,8 @@ class Base(DeclarativeBase): class BaseMixin: - id = Column(String(255), primary_key=True, default=uuid.uuid4()) - # id: Mapped[str] = mapped_column(primary_key=True, default=uuid.uuid4()) + #id = Column(String, primary_key=True, default=uuid.uuid4) + id: Mapped[str] = mapped_column(primary_key=True, default=str(uuid.uuid4())) # created_date = Column(DateTime) created_date: Mapped[datetime] = mapped_column(default=func.now()) # last_modified_date = Column(DateTime) @@ -22,10 +21,10 @@ class BaseMixin: class BaseVideoMixin: - cloud_link = Column(String(255)) - file_name = Column(String(255)) - path = Column(String(255)) - review = Column(BIT(1)) - title = Column(String(255)) - url = Column(String(255), unique=True) - should_download = Column(BIT(1)) + cloud_link = Column(String, nullable=True) + file_name = Column(String, nullable=True) + path = Column(String) + review = Column(Boolean) + title = Column(String) + url = Column(String, nullable=True) + should_download = Column(Boolean) diff --git a/kontor-api/src/db/models/bookshelf.py b/kontor-api/src/db/models/bookshelf.py index d01fc6b..c2b4e4b 100644 --- a/kontor-api/src/db/models/bookshelf.py +++ b/kontor-api/src/db/models/bookshelf.py @@ -6,28 +6,28 @@ from src.db.models.base import Base, BaseMixin class Article(Base, BaseMixin): __tablename__ = 'article' - title = Column(String(length=255), unique=True) + title = Column(String, unique=True) article_authors = relationship("ArticleAuthor") class Author(Base, BaseMixin): __tablename__ = 'author' - first_name = Column(String(255)) - last_name = Column(String(255)) + first_name = Column(String) + last_name = Column(String) article_authors = relationship("ArticleAuthor") book_authors = relationship("BookAuthor") class BookshelfPublisher(Base, BaseMixin): __tablename__ = 'bookshelf_publisher' - name = Column(String(length=255), unique=True) + name = Column(String, unique=True) books = relationship("Book") class Book(Base, BaseMixin): __tablename__ = 'book' - isbn = Column(String(255), unique=True) - title = Column(String(255)) + isbn = Column(String, unique=True) + title = Column(String) year = Column(Integer, nullable=False) publisher_id = Column(String, ForeignKey('bookshelf_publisher.id'), nullable=False) publisher = relationship('BookshelfPublisher', back_populates="books") diff --git a/kontor-api/src/db/models/comic.py b/kontor-api/src/db/models/comic.py index 423ad7c..b22214a 100644 --- a/kontor-api/src/db/models/comic.py +++ b/kontor-api/src/db/models/comic.py @@ -1,15 +1,24 @@ -from typing import Dict, List +import uuid +from datetime import datetime +from typing import AnyStr, Dict, List, Optional, Any from natsort import natsorted -from sqlalchemy import Column, ForeignKey, Integer, String -from sqlalchemy.dialects.mysql import BIT -from sqlalchemy.orm import relationship +from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, func +from sqlalchemy.orm import relationship, Mapped, mapped_column from src.db.models.base import Base, BaseMixin -class Publisher(Base, BaseMixin): +class Publisher(Base): __tablename__ = "publisher" - name = Column(String(length=255), unique=True) + id: Mapped[str] = mapped_column(primary_key=True, default=uuid.uuid4) + created_date: Mapped[datetime] = mapped_column(default=func.now()) + last_modified_date: Mapped[datetime] = mapped_column(default=func.now()) + version: Mapped[int] = mapped_column(default=0) + name = Column(String, unique=True) + weblink = Column(String, nullable=True) + parent_publisher_id: Mapped[Optional[str]] = mapped_column(ForeignKey('publisher.id')) + parent_publisher: Mapped[Optional['Publisher']] = relationship("Publisher", back_populates="imprints", remote_side=[id]) + imprints: Mapped[List['Publisher']] = relationship('Publisher', back_populates="parent_publisher") comics = relationship("Comic") def __repr__(self): @@ -21,11 +30,12 @@ class Publisher(Base, BaseMixin): class Comic(Base, BaseMixin): __tablename__ = 'comic' - title = Column(String(length=255), unique=True) + title = Column(String, unique=True) publisher_id = Column(String, ForeignKey('publisher.id'), nullable=False) publisher = relationship("Publisher", back_populates="comics") - current_order = Column(BIT(1)) - completed = Column(BIT(1)) + current_order = Column(Boolean) + completed = Column(Boolean) + weblink = Column(String, nullable=True) issues = relationship("Issue", order_by="Issue.issue_number") story_arcs = relationship("StoryArc") trade_paperbacks = relationship("TradePaperback") @@ -38,10 +48,10 @@ class Comic(Base, BaseMixin): def __str__(self): return f'{self.title}({self.id})' - def get_artists(self) -> Dict[str, List[str]]: - works: Dict[str, List[str]] = {} + def get_artists(self) -> Dict[Any, List[Any]]: + works: Dict[Any, List[Any]] = {} for work in self.comic_works: - work_type = work.work_type.name + work_type = work.work_type artist = work.artist if work_type in works: works[work_type].append(artist) @@ -56,15 +66,16 @@ class Comic(Base, BaseMixin): class Volume(Base, BaseMixin): __tablename__ = "volume" - name = Column(String(length=255), nullable=False) + name = Column(String, nullable=False) comic_id = Column(String, ForeignKey("comic.id"), nullable=False) comic = relationship("Comic", back_populates="volumes") + story_arcs = relationship("StoryArc") issues = relationship("Issue") class TradePaperback(Base, BaseMixin): __tablename__ = "trade_paperback" - name = Column(String(length=255), nullable=False) + name = Column(String, nullable=False) issue_start = Column(Integer) issue_end = Column(Integer) comic_id = Column(String, ForeignKey("comic.id"), nullable=False) @@ -73,31 +84,58 @@ class TradePaperback(Base, BaseMixin): class StoryArc(Base, BaseMixin): __tablename__ = "story_arc" - name = Column(String(length=255), nullable=False) + name = Column(String, nullable=False) comic_id = Column(String, ForeignKey("comic.id"), nullable=False) comic = relationship("Comic", back_populates="story_arcs") + volume_id = Column(String, ForeignKey("volume.id"), nullable=True) + volume = relationship("Volume", back_populates="story_arcs") + issues = relationship("Issue") class Issue(Base, BaseMixin): __tablename__ = "issue" - issue_number = Column(String(255)) - in_stock = Column(BIT(1)) - is_read = Column(BIT(1)) + issue_number = Column(String) + title = Column(String, nullable=True) + published_on: Mapped[datetime] = mapped_column(nullable=True) + in_stock = Column(Boolean) + is_read = Column(Boolean) comic_id = Column(String, ForeignKey("comic.id"), nullable=False) comic = relationship("Comic", back_populates="issues") volume_id = Column(String, ForeignKey("volume.id"), nullable=True) volume = relationship("Volume", back_populates="issues") + story_arc_id = Column(String, ForeignKey("story_arc.id"), nullable=True) + story_arc = relationship("StoryArc", back_populates="issues") + issue_works = relationship("IssueWork") + + def get_full_title(self) -> str: + full_title: str = str(self.issue_number) + if self.title: + full_title += str(": " + self.title) + return full_title + + def get_artists(self) -> Dict[Any, List[Any]]: + works: Dict[Any, List[Any]] = {} + for work in self.issue_works: + work_type = work.work_type + artist = work.artist + if work_type in works: + works[work_type].append(artist) + else: + works[work_type] = [artist] + return works class Artist(Base, BaseMixin): __tablename__ = "artist" - name = Column(String(length=255), nullable=False) + name = Column(String, nullable=False) + weblink = Column(String, nullable=True) comic_works = relationship("ComicWork") + issue_works = relationship("IssueWork") - def get_comics(self) -> Dict[str, List[str]]: - works: Dict[str, List[str]] = {} + def get_comics(self) -> Dict[Any, List[Comic]]: + works: Dict[Any, List[Comic]] = {} for work in self.comic_works: - work_type = work.work_type.name + work_type = work.work_type comic = work.comic if work_type in works: works[work_type].append(comic) @@ -108,8 +146,20 @@ class Artist(Base, BaseMixin): class WorkType(Base, BaseMixin): __tablename__ = "worktype" - name = Column(String(length=255), nullable=False, unique=True) + name = Column(String, nullable=False, unique=True) comic_works = relationship("ComicWork") + issue_works = relationship("IssueWork") + + def get_artists(self) -> Dict[str, List[str]]: + works: Dict[str, List[str]] = {} + for work in self.comic_works: + comic = work.comic.title + artist = work.artist + if comic in works: + works[comic].append(artist) + else: + works[comic] = [artist] + return works def __repr__(self): return f'Worktype({self.id} {self.version} {self.name} {len(self.comic_works)})' @@ -126,3 +176,13 @@ class ComicWork(Base, BaseMixin): artist = relationship("Artist", back_populates="comic_works") work_type_id = Column(String, ForeignKey("worktype.id"), nullable=False) work_type = relationship("WorkType", back_populates="comic_works") + + +class IssueWork(Base, BaseMixin): + __tablename__ = "issue_work" + issue_id = Column(String, ForeignKey("issue.id"), nullable=False) + issue = relationship("Issue", back_populates="issue_works") + artist_id = Column(String, ForeignKey("artist.id"), nullable=False) + artist = relationship("Artist", back_populates="issue_works") + work_type_id = Column(String, ForeignKey("worktype.id"), nullable=False) + work_type = relationship("WorkType", back_populates="issue_works") diff --git a/kontor-api/src/db/models/database.py b/kontor-api/src/db/models/database.py index 0d5998b..0da5f88 100644 --- a/kontor-api/src/db/models/database.py +++ b/kontor-api/src/db/models/database.py @@ -1,10 +1,9 @@ import json import logging -import uuid from datetime import datetime from enum import Enum, auto from pathlib import Path -from typing import Any +from typing import Any, List from sqlalchemy import select from sqlalchemy.exc import IntegrityError @@ -13,7 +12,7 @@ from sqlalchemy.orm import sessionmaker from src.db.models.tysc import Card, CardSet, Rooster, Team, FieldPosition, Player, Vendor, Sport from src.db.models.comic import Issue, TradePaperback, StoryArc, Volume, ComicWork, Artist, Comic, Publisher, WorkType from src.db.models.bookshelf import ArticleAuthor, BookAuthor, BookshelfPublisher, Article, Book, Author -from src.db.models.admin import Mail, MailAccount, ModuleData, Role, User, Token, AuthorizationMatrix +from src.db.models.admin import Mail, MailAccount, ModuleData, Token, Assignment, Permission, Profile from src.db.models.metadata import MetaDataTable, MetaDataColumn from src.db.models.media import MediaVideo, MediaArticle, MediaFile, MediaActor, MediaActorFile @@ -79,10 +78,10 @@ class KontorDB: self.registry[MediaVideo.__tablename__] = MediaVideo self.registry[MetaDataColumn.__tablename__] = MetaDataColumn self.registry[MetaDataTable.__tablename__] = MetaDataTable - self.registry[AuthorizationMatrix.__tablename__] = AuthorizationMatrix + self.registry[Assignment.__tablename__] = Assignment self.registry[Token.__tablename__] = Token - self.registry[User.__tablename__] = User - self.registry[Role.__tablename__] = Role + self.registry[Profile.__tablename__] = Profile + self.registry[Permission.__tablename__] = Permission self.registry[ModuleData.__tablename__] = ModuleData self.registry[MailAccount.__tablename__] = MailAccount self.registry[Mail.__tablename__] = Mail @@ -360,7 +359,7 @@ class KontorDB: update_list[link.id] = link.title return update_list - def get_download_list(self) -> list[uuid.UUID]: + def get_download_list(self) -> List[str]: download_list = [] __session__ = sessionmaker(self.engine) _filter = { 'should_download': True} diff --git a/kontor-api/src/db/models/media.py b/kontor-api/src/db/models/media.py index 4c0b21a..d52b449 100644 --- a/kontor-api/src/db/models/media.py +++ b/kontor-api/src/db/models/media.py @@ -6,8 +6,7 @@ from pathlib import Path import requests from bs4 import BeautifulSoup -from sqlalchemy import Column, String, ForeignKey -from sqlalchemy.dialects.mysql import BIT +from sqlalchemy import Column, String, ForeignKey, Boolean from sqlalchemy.orm import relationship from src.db.models.base import Base, BaseMixin, BaseVideoMixin @@ -26,31 +25,31 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin): def update_title(self) -> None: logging.info(f"update title for {self.url}") try: - r = requests.get(self.url) + r = requests.get(str(self.url)) soup = BeautifulSoup(r.content, "html.parser") - title = soup.title.string + title = soup.title.get_text() # type: ignore self.title = title - self.review = 0 + self.review = False except: self.title = None - self.review = 1 + self.review = True self.last_modified_date = datetime.now() def download_file(self, download_dir: str, dl_tool: str): logging.info(f"download file for {self.url} to {download_dir}") - result = subprocess.run([dl_tool, self.url], cwd=download_dir, capture_output=True, text=True) + result = subprocess.run([dl_tool, self.url], cwd=download_dir, capture_output=True, text=True) # type: ignore if result.returncode == 0: output = result.stdout output = re.sub(' +', ' ', output) lines_list = output.splitlines() file_name = self.__parse_output__(lines_list) if file_name is None: - self.review = 1 - self.should_download = 1 + self.review = True + self.should_download = True self.file_name = None else: download_file = Path(file_name) - self.should_download = 0 + self.should_download = False self.file_name = download_file.name self.cloud_link = str(download_file.absolute()) self.last_modified_date = datetime.now() @@ -71,31 +70,52 @@ class MediaFile(Base, BaseMixin, BaseVideoMixin): class MediaActor(Base, BaseMixin): __tablename__ = 'media_actor' - name = Column(String(255)) + name = Column(String) + url = Column(String, unique=True, nullable=True) media_actor_files = relationship("MediaActorFile") + + def __repr__(self) -> str: + return f'MediaActor({self.id} {self.name} {self.url})' + + def __str__(self) -> str: + return f'{self.url}({self.id})' class MediaActorFile(Base, BaseMixin): __tablename__ = 'media_actor_file' - media_actor_id = Column(String(255), ForeignKey("media_actor.id"), nullable=False) + media_actor_id = Column(String, ForeignKey("media_actor.id"), nullable=False) media_actor = relationship("MediaActor", back_populates="media_actor_files") - media_file_id = Column(String(255), ForeignKey("media_file.id"), nullable=True) + media_file_id = Column(String, ForeignKey("media_file.id"), nullable=True) media_file = relationship("MediaFile", back_populates="media_actor_files") + def __repr__(self): + return f'MediaActorFile({self.id} {self.media_actor_id} {self.media_file_id})' + + def __str__(self) -> str: + return f'{self.id} {self.media_actor_id} {self.media_file_id}' class MediaArticle(Base, BaseMixin): __tablename__ = 'media_article' - review = Column(BIT(1)) - title = Column(String(255)) - url = Column(String(255), unique=True) + review = Column(Boolean) + title = Column(String) + url = Column(String, unique=True) class MediaVideo(Base, BaseMixin): __tablename__ = 'media_video' - cloud_link = Column(String(255)) - file_name = Column(String(255)) - path = Column(String(255)) - review = Column(BIT(1)) - title = Column(String(255)) - url = Column(String(255), unique=True) - should_download = Column(BIT(1)) + cloud_link = Column(String) + file_name = Column(String) + path = Column(String) + review = Column(Boolean) + title = Column(String) + url = Column(String, unique=True) + should_download = Column(Boolean) + + def __repr__(self): + return f'MediaFile({self.id} {self.title} {self.url})' + + def __str__(self): + if self.title is None: + return f'{self.url}({self.id})' + else: + return f'{self.title}({self.id})' diff --git a/kontor-api/src/db/models/metadata.py b/kontor-api/src/db/models/metadata.py deleted file mode 100644 index 081c3af..0000000 --- a/kontor-api/src/db/models/metadata.py +++ /dev/null @@ -1,42 +0,0 @@ -from sqlalchemy import Column, String, ForeignKey, Integer -from sqlalchemy.dialects.mysql import BIT -from sqlalchemy.orm import relationship - -from src.db.models.base import Base, BaseMixin - - -class MetaDataTable(Base, BaseMixin): - __tablename__ = 'meta_data_table' - table_name = Column(String(255), unique=True) - table_columns = relationship("MetaDataColumn") - - def __repr__(self): - return f'MetaDataTable({self.id} {self.table_name})' - - def __str__(self): - return f'{self.table_name}({self.id})' - - -class MetaDataColumn(Base, BaseMixin): - __tablename__ = 'meta_data_column' - column_name = Column(String(255), nullable=False) - column_sync_name = Column(String(255)) - column_type = Column(String(255)) - column_modifier = Column(String(255), nullable=True) - column_order = Column(Integer) - table_id = Column(String, ForeignKey('meta_data_table.id')) - table = relationship("MetaDataTable", back_populates="table_columns") - column_label = Column(String(255)) - filter_label = Column(String(255)) - is_shown = Column(BIT(1)) - show_filter = Column(BIT(1)) - ref_column = Column(String, nullable=True) - - def __repr__(self): - if self.column_name is None: - return f'MetaDataColumn({self.id} {self.table.table_name}.__)' - else: - return f'MetaDataColumn({self.id} {self.table.table_name}.{self.column_name})' - - def __str__(self): - return f'{self.column_name}({self.id})' diff --git a/kontor-api/src/db/models/tysc.py b/kontor-api/src/db/models/tysc.py index dae0417..3a4f553 100644 --- a/kontor-api/src/db/models/tysc.py +++ b/kontor-api/src/db/models/tysc.py @@ -1,5 +1,4 @@ -from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint -from sqlalchemy.dialects.mysql import BIT +from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Boolean from sqlalchemy.orm import relationship from src.db.models.base import Base, BaseMixin @@ -10,15 +9,15 @@ class Sport(Base, BaseMixin): __table_args__ = ( UniqueConstraint("name"), ) - name = Column(String(255), nullable=False, index=True, unique=True) + name = Column(String, nullable=False, index=True, unique=True) teams = relationship("Team") positions = relationship("FieldPosition") class Team(Base, BaseMixin): __tablename__ = "team" - name = Column(String(255), nullable=False, index=True, unique=True) - short_name = Column(String(255), nullable=False, ) + name = Column(String, nullable=False, index=True, unique=True) + short_name = Column(String, nullable=False, ) sport_id = Column(String, ForeignKey("sport.id"), nullable=False) sport = relationship("Sport", back_populates="teams") roosters = relationship("Rooster") @@ -30,8 +29,8 @@ class FieldPosition(Base, BaseMixin): UniqueConstraint("name", "sport_id"), UniqueConstraint("short_name", "sport_id"), ) - name = Column(String(255), nullable=False, index=True) - short_name = Column(String(255), nullable=False) + name = Column(String, nullable=False, index=True) + short_name = Column(String, nullable=False) sport_id = Column(String, ForeignKey("sport.id"), nullable=False, index=True) sport = relationship("Sport", back_populates="positions") roosters = relationship("Rooster") @@ -42,8 +41,8 @@ class Player(Base, BaseMixin): __table_args__ = ( UniqueConstraint("first_name", "last_name"), ) - first_name = Column(String(255), nullable=False, index=True) - last_name = Column(String(255), nullable=False, index=True) + first_name = Column(String, nullable=False, index=True) + last_name = Column(String, nullable=False, index=True) roosters = relationship("Rooster") def get_full_name(self) -> str: @@ -67,7 +66,7 @@ class Rooster(Base, BaseMixin): class Vendor(Base, BaseMixin): __tablename__ = "vendor" - name = Column(String(255), nullable=False, unique=True, index=True) + name = Column(String, nullable=False, unique=True, index=True) card_sets = relationship("CardSet") cards = relationship("Card") @@ -77,9 +76,9 @@ class CardSet(Base, BaseMixin): __table_args__ = ( UniqueConstraint("name", "vendor_id"), ) - name = Column(String(255), index=True) - parallel_set = Column(BIT(1)) - insert_set = Column(BIT(1)) + name = Column(String, index=True) + parallel_set = Column(Boolean) + insert_set = Column(Boolean) vendor_id = Column(String, ForeignKey("vendor.id"), nullable=False, index=True) vendor = relationship("Vendor", back_populates="card_sets") cards = relationship("Card") diff --git a/kontor-api/src/db/repository/__init__.py b/kontor-api/src/db/repository/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kontor-api/src/db/repository/admin.py b/kontor-api/src/db/repository/admin.py new file mode 100644 index 0000000..cc06404 --- /dev/null +++ b/kontor-api/src/db/repository/admin.py @@ -0,0 +1,10 @@ +from typing import AnyStr, Optional + +from sqlalchemy.orm import Session + +from src.db.models.admin import Profile + + +def get_profile(username: AnyStr, db: Session) -> Optional[Profile]: + profile = db.query(Profile).filter(Profile.email == username).first() + return profile diff --git a/kontor-api/src/db/repository/comics/__init__.py b/kontor-api/src/db/repository/comics/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/kontor-api/src/db/repository/comics/artist.py b/kontor-api/src/db/repository/comics/artist.py new file mode 100644 index 0000000..ec0077e --- /dev/null +++ b/kontor-api/src/db/repository/comics/artist.py @@ -0,0 +1,46 @@ +import uuid +from typing import List, Optional + +from sqlalchemy.orm import Session + +from src.core.log_conf import logger +from src.db.models.comic import Artist +from src.schema.comics.artist import AddArtist +from src.schema.comics.artist_details import ArtistDetailResponse, ArtistWorktypeComicResponse, ArtistWorktypeIssueResponse +from src.schema.comics.comic import ComicResponse +from src.schema.comics.worktype import WorktypeResponse + + +def get_artist_details(artist: Artist) -> ArtistDetailResponse: + comic_works: List[ArtistWorktypeComicResponse] = [] + comic_works_map = {} + for work in artist.comic_works: + worktype_id = work.work_type.id + if worktype_id in comic_works_map: + comic = ComicResponse(id=work.comic.id, title=work.comic.title, completed=work.comic.completed) + comic_works_map[worktype_id].comics.append(comic) + else: + comic_works_map[worktype_id] = ArtistWorktypeComicResponse( + worktype=WorktypeResponse(id=worktype_id, name=work.work_type.name), + comics=[ComicResponse(id=work.comic.id, title=work.comic.title, completed=work.comic.completed)] + ) + for value in comic_works_map.values(): + comic_works.append(value) + issue_works: List[ArtistWorktypeIssueResponse] = [] + response = ArtistDetailResponse( + id=artist.id, + name=str(artist.name), + weblink=str(artist.weblink), + comic_works=comic_works, + issue_works=issue_works, + ) + return response + +def update_artist(add_artist: AddArtist, artist_id: str, db: Session) -> Artist: + logger.info("update artist") + artist: Optional[Artist] = db.get(Artist, artist_id) + artist.name = add_artist.name + db.add(artist) + db.commit() + db.refresh(artist) + return artist diff --git a/kontor-api/src/db/repository/comics/comic.py b/kontor-api/src/db/repository/comics/comic.py new file mode 100644 index 0000000..4821d29 --- /dev/null +++ b/kontor-api/src/db/repository/comics/comic.py @@ -0,0 +1,87 @@ +from typing import Dict, List + +from sqlalchemy.orm import Session + +from src.core.log_conf import logger +from src.db.models.comic import Comic, Issue +from src.schema.comics.artist import ArtistResponse +from src.schema.comics.comic import ComicResponse, ComicSchema +from src.schema.comics.comic_details import ComicDetailsResponse, ComicWorktypeArtistResponse +from src.schema.comics.issue import IssueResponse +from src.schema.comics.issue_details import IssueDetailsResponse +from src.schema.comics.publisher import PublisherResponse +from src.schema.comics.volume import VolumeResponse +from src.schema.comics.worktype import WorktypeResponse + + +def list_comics(db: Session) -> List[Comic]: + comics = db.query(Comic).all() + return comics + + +def get_issue_details(issue: Issue) -> IssueDetailsResponse: + response = IssueDetailsResponse( + id=issue.id, + issue_number=str(issue.issue_number), + in_stock=bool(issue.in_stock), + is_read=bool(issue.is_read), + comic=ComicResponse(id=issue.comic.id, title=issue.comic.title, completed=issue.comic.completed), + volume=VolumeResponse(id=issue.volume.id, name=issue.volume.name) + ) + return response + + +def update_comic(comic: ComicSchema, comic_id: str, db: Session) -> type[Comic] | None: + logger.info(f"update_comic: {comic} with {comic_id}") + comic = db.get(Comic, comic_id) # type: ignore + return comic # type: ignore + +def get_short_info(comic: Comic) -> ComicResponse: + response = ComicResponse( + id=comic.id, + title=str(comic.title), + completed=bool(comic.completed == 1) + ) + return response + +def get_comic_details(comic: Comic) -> ComicDetailsResponse: + volumes: List[VolumeResponse] = [] + for volume in comic.volumes: + volumes.append(VolumeResponse(id=volume.id, name=volume.name)) + issues: List[IssueResponse] = [] + for issue in comic.issues: + issues.append(IssueResponse( + id=issue.id, + issue_number=issue.issue_number, + in_stock=issue.in_stock, + is_read=issue.is_read + )) + works: List[ComicWorktypeArtistResponse] = [] + works_map: Dict[str, ComicWorktypeArtistResponse] = {} + for work in comic.comic_works: + worktype_id = work.work_type.id + if worktype_id in works_map: + artist = ArtistResponse(id=work.artist.id, name=work.artist.name) + works_map[worktype_id].artists.append(artist) + logger.info(f"add artist to response map: {artist} -> {works_map}") + print(f"add artist to response map: {artist} -> {works_map}") + else: + works_map[worktype_id] = ComicWorktypeArtistResponse( + worktype=WorktypeResponse(id=worktype_id, name=work.work_type.name), + artists=[ArtistResponse(id=work.artist.id, name=work.artist.name)] + ) + for value in works_map.values(): + works.append(value) + response = ComicDetailsResponse( + id=str(comic.id), + created=str(comic.created_date), + title=str(comic.title), + completed=bool(comic.completed), + current_order=bool(comic.current_order), + weblink=str(comic.weblink), + publisher=PublisherResponse(id=comic.publisher.id, name=comic.publisher.name), + issues=issues, + volumes=volumes, + works=works + ) + return response diff --git a/kontor-api/src/db/repository/comics/publisher.py b/kontor-api/src/db/repository/comics/publisher.py new file mode 100644 index 0000000..a17da64 --- /dev/null +++ b/kontor-api/src/db/repository/comics/publisher.py @@ -0,0 +1,24 @@ +from typing import List + +from src.db.models.comic import Publisher +from src.schema.comics.comic import ComicResponse +from src.schema.comics.publisher import PublisherResponse +from src.schema.comics.publisher_details import PublisherDetailsResponse + + +def get_publisher_details(publisher: Publisher) -> PublisherDetailsResponse: + imprints: List[PublisherResponse] = [] + for imprint in publisher.imprints: + imprints.append(PublisherResponse(id=imprint.id, name=str(imprint.name))) + comics: List[ComicResponse] = [] + for comic in publisher.comics: + comics.append( + ComicResponse(id=comic.id, title=comic.title, completed=comic.completed) + ) + parent_publisher: PublisherResponse | None = None + if publisher.parent_publisher: + parent_publisher = PublisherResponse(id=publisher.parent_publisher.id, name=str(publisher.parent_publisher.name)) + response: PublisherDetailsResponse = PublisherDetailsResponse( + id=publisher.id, name=str(publisher.name), parent_publisher=parent_publisher, imprints=imprints, comics=comics + ) + return response diff --git a/kontor-api/src/db/repository/comics/worktype.py b/kontor-api/src/db/repository/comics/worktype.py new file mode 100644 index 0000000..cb545ad --- /dev/null +++ b/kontor-api/src/db/repository/comics/worktype.py @@ -0,0 +1,32 @@ +import uuid +from datetime import datetime +from typing import AnyStr + +from sqlalchemy.orm import Session + +from src.core.log_conf import logger +from src.db.models.comic import WorkType +from src.schema.comics.worktype import AddWorkType + + +def create_new_worktype(work: AddWorkType, db: Session) -> WorkType: + worktype = WorkType() + worktype.id = str(uuid.uuid4()) + worktype.created_date = datetime.now() + worktype.last_modified_date = datetime.now() + worktype.name = work.worktype + db.add(worktype) + db.commit() + db.refresh(worktype) + logger.info(f"create_new_worktype: {worktype}") + return worktype + + +def update_worktype(work: AddWorkType, worktype_id: AnyStr, db: Session) -> WorkType: + logger.info("update worktype") + worktype = db.get(WorkType, worktype_id) + worktype.name = work.worktype + db.add(worktype) + db.commit() + db.refresh(worktype) + return worktype diff --git a/kontor-api/src/db/repository/media.py b/kontor-api/src/db/repository/media.py new file mode 100644 index 0000000..e7f3acd --- /dev/null +++ b/kontor-api/src/db/repository/media.py @@ -0,0 +1,86 @@ +from sqlalchemy.orm import Session +import uuid +from datetime import datetime +from src.core.log_conf import logger +from src.db.models.media import MediaActor, MediaActorFile, MediaFile, MediaVideo +from src.schema.media.actor import Actor +from src.webapps.media.forms import AddLinkForm + + +def create_new_video(video: AddLinkForm, db: Session) -> MediaVideo: + print(video.url) + media_video = MediaVideo() + media_video.id = str(uuid.uuid4()) + media_video.url = video.url # type: ignore + media_video.created_date = datetime.now() + media_video.last_modified_date = datetime.now() + media_video.review = True # type: ignore + media_video.should_download = True # type: ignore + db.add(media_video) + db.commit() + db.refresh(media_video) + print(media_video) + return media_video + +def create_new_mediafile(link: str, db: Session) -> MediaFile: + logger.info("create MediaFile with url {link}") + media_file: MediaFile = MediaFile() + media_file.id = str(uuid.uuid4()) + media_file.url = link # type: ignore + media_file.created_date = datetime.now() + media_file.last_modified_date = datetime.now() + media_file.version = 0 + media_file.review = True + media_file.should_download = True + db.add(media_file) + db.commit() + db.refresh(media_file) + logger.info(f"created {media_file}") + return media_file + +def delete_mediafile(db: Session, media_file_id: str): + logger.info(f"delete MediaFile with id {media_file_id}") + media_file = db.get(MediaFile, media_file_id) + db.delete(media_file) + db.commit() + +def create_new_mediaactor(new_actor: Actor, db: Session) -> MediaActor: + logger.info(f"create MediaActor with url {new_actor.url}") + media_actor: MediaActor = MediaActor() + media_actor.id = str(uuid.uuid4()) + media_actor.name = str(new_actor.name) # type: ignore + media_actor.url = str(new_actor.url) # type: ignore + media_actor.created_date = datetime.now() + media_actor.last_modified_date = datetime.now() + media_actor.version = 0 + db.add(media_actor) + db.commit() + db.refresh(media_actor) + logger.info(f"created {media_actor}") + return media_actor + +def delete_mediaactor(db: Session, actor_id: str): + logger.info(f"delete MediaActor with id {actor_id}") + media_actor = db.get(MediaActor, actor_id) + db.delete(media_actor) + db.commit() + +def create_new_mediaactorfile(db: Session, actor_id: str, file_id: str) -> MediaActorFile: + logger.info(f"create MediaActorFile with actor {actor_id} and file {file_id}") + media_actor_file: MediaActorFile = MediaActorFile() + media_actor_file.id = str(uuid.uuid4()) + media_actor_file.created_date = datetime.now() + media_actor_file.last_modified_date = datetime.now() + media_actor_file.version = 0 + media_actor_file.media_actor_id = actor_id # type: ignore + media_actor_file.media_file_id = file_id # type: ignore + db.add(media_actor_file) + db.commit() + db.refresh(media_actor_file) + return media_actor_file + +def delete_mediaactorfile(db: Session, actorfile_id: str): + logger.info(f"delete MediaActorFile with id {actorfile_id}") + media_actorfile = db.get(MediaActorFile, actorfile_id) + db.delete(media_actorfile) + db.commit() \ No newline at end of file diff --git a/kontor-api/src/db/session.py b/kontor-api/src/db/session.py index 713deb6..db8c1c0 100644 --- a/kontor-api/src/db/session.py +++ b/kontor-api/src/db/session.py @@ -1,5 +1,6 @@ from typing import Generator, Annotated +from fastapi import Depends from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, Session @@ -10,6 +11,9 @@ engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(bind=engine) + def get_db() -> Generator: with SessionLocal() as db: yield db + +SessionDep: type[Session] = Annotated[Session, Depends(get_db)] diff --git a/kontor-api/src/db/utils.py b/kontor-api/src/db/utils.py new file mode 100644 index 0000000..a404754 --- /dev/null +++ b/kontor-api/src/db/utils.py @@ -0,0 +1,30 @@ +import databases + +from src.core.log_conf import logger +from src.db.session import SQLALCHEMY_DATABASE_URL + + +async def check_db_connected(): + try: + if not str(SQLALCHEMY_DATABASE_URL).__contains__("sqlite"): + database = databases.Database(SQLALCHEMY_DATABASE_URL) + if not database.is_connected: + await database.connect() + await database.execute("SELECT 1") + logger.info("Database is connected (^_^)") + except Exception as e: + print( + "Looks like db is missing or is there is some problem in connection,see below traceback" + ) + raise e + + +async def check_db_disconnected(): + try: + if not str(SQLALCHEMY_DATABASE_URL).__contains__("sqlite"): + database = databases.Database(SQLALCHEMY_DATABASE_URL) + if database.is_connected: + await database.disconnect() + logger.info("Database is Disconnected (-_-) zZZ") + except Exception as e: + raise e diff --git a/kontor-api/src/main.py b/kontor-api/src/main.py index 749d3b4..b0301f2 100644 --- a/kontor-api/src/main.py +++ b/kontor-api/src/main.py @@ -1,29 +1,62 @@ +from contextlib import asynccontextmanager + from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from src.apis.base import api_router -from src.db.session import engine -from src.webapps.base import api_router as web_app_router +from src.apis.version1.healthcheck import health_router +from src.apis.version1.login import login_router from src.core.config import settings +from src.core.log_conf import logger from src.db.models.base import Base +from src.db.session import engine +from src.db.utils import check_db_connected, check_db_disconnected +from src.webapps.base import api_router as web_app_router + + +@asynccontextmanager +async def lifespan(app: FastAPI): + await check_db_connected() + yield + await check_db_disconnected() + def include_router(app: FastAPI): app.include_router(api_router) app.include_router(web_app_router) + app.include_router(health_router) + app.include_router(login_router) + def configure_static(app: FastAPI): app.mount("/static", StaticFiles(directory="src/static"), name="static") + +def add_middle_ware(app: FastAPI): + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + def create_tables(): Base.metadata.create_all(bind=engine) -def start_application(): - app = FastAPI(title=settings.PROJECT_NAME, version=settings.PROJECT_VERSION) + +def start_application(log): + log.info(f"using database: {settings.DATABASE_URL}") + app = FastAPI( + title=settings.PROJECT_NAME, version=settings.PROJECT_VERSION, lifespan=lifespan + ) include_router(app) configure_static(app) + add_middle_ware(app) create_tables() return app -kontor = start_application() - +kontor = start_application(logger) diff --git a/kontor-api/src/schema/admin.py b/kontor-api/src/schema/admin.py new file mode 100644 index 0000000..5f9c3b4 --- /dev/null +++ b/kontor-api/src/schema/admin.py @@ -0,0 +1,27 @@ +from typing import Optional, List + +from pydantic import BaseModel + + +class Token(BaseModel): + access_token: str + token_type: str + + +class TokenData(BaseModel): + username: Optional[str] = None + scopes: List[str] = [] + + +class ProfileModel(BaseModel): + username: str + email: str + first_name: str + last_name: str + active: bool + +class HealthCheck(BaseModel): + """ + Health check model + """ + status: str = "ok" diff --git a/kontor-api/src/schema/comics/artist.py b/kontor-api/src/schema/comics/artist.py index 1b28812..e369737 100644 --- a/kontor-api/src/schema/comics/artist.py +++ b/kontor-api/src/schema/comics/artist.py @@ -1,36 +1,14 @@ -from typing import List, Dict -from uuid import UUID - from pydantic import BaseModel -from src.db.models.comic import Artist - class ArtistCreation(BaseModel): + id: str name: str class ArtistResponse(BaseModel): - id: UUID + id: str name: str -class ArtistDetailResponse(BaseModel): - id: UUID +class AddArtist(BaseModel): + id: str name: str - works: Dict[str, List[str]] - -def get_artist_details(artist: Artist) -> ArtistDetailResponse: - works = {} - for work in artist.comic_works: - work_type = work.work_type.name - comic_title = work.comic.title - if work_type in works: - works[work_type].append(comic_title) - else: - works[work_type] = [comic_title] - response = ArtistDetailResponse( - id=artist.id, - name=artist.name, - works=works - ) - return response - diff --git a/kontor-api/src/schema/comics/artist_details.py b/kontor-api/src/schema/comics/artist_details.py new file mode 100644 index 0000000..416257c --- /dev/null +++ b/kontor-api/src/schema/comics/artist_details.py @@ -0,0 +1,22 @@ +from typing import List +from pydantic import BaseModel + +from src.schema.comics.comic import ComicResponse +from src.schema.comics.issue_details import IssueDetailsResponse +from src.schema.comics.worktype import WorktypeResponse + + +class ArtistWorktypeComicResponse(BaseModel): + worktype: WorktypeResponse + comics: List[ComicResponse] + +class ArtistWorktypeIssueResponse(BaseModel): + worktype: WorktypeResponse + issues: List[IssueDetailsResponse] + +class ArtistDetailResponse(BaseModel): + id: str + name: str + weblink: str + comic_works: List[ArtistWorktypeComicResponse] + issue_works: List[ArtistWorktypeIssueResponse] diff --git a/kontor-api/src/schema/comics/comic.py b/kontor-api/src/schema/comics/comic.py index feec39d..a57c7ff 100644 --- a/kontor-api/src/schema/comics/comic.py +++ b/kontor-api/src/schema/comics/comic.py @@ -1,56 +1,17 @@ -from typing import List, Dict -from uuid import UUID - -from pydantic import BaseModel - -from src.db.models.comic import Comic +from typing import Optional +from pydantic import BaseModel, AnyUrl +from src.core.log_conf import logger class ComicResponse(BaseModel): - id: UUID + id: str title: str completed: bool -class ComicDetailsResponse(BaseModel): - id: UUID - created: str + +class ComicSchema(BaseModel): + id: str title: str - completed : bool - current_order : bool - publisher: str - volumes: List[str] - works: Dict[str, List[str]] - -def get_short_info(comic: Comic) -> ComicResponse: - response = ComicResponse( - id=comic.id, - title=comic.title, - completed=(comic.completed == 1) - ) - return response - - -def get_comic_details(comic: Comic) -> ComicDetailsResponse | None: - volumes = [] - for volume in comic.volumes: - volumes.append(volume.name) - works = {} - for work in comic.comic_works: - work_type = work.work_type.name - artist_name = work.artist.name - if work_type in works: - works[work_type].append(artist_name) - else: - works[work_type] = [artist_name] - response = ComicDetailsResponse( - id=comic.id, - created=str(comic.created_date), - title=comic.title, - completed=(comic.completed == 1), - current_order=(comic.current_order == 1), - publisher=comic.publisher.name, - volumes=volumes, - works=works - ) - return response - + weblink: Optional[AnyUrl] + completed: Optional[bool] + current_order: Optional[bool] diff --git a/kontor-api/src/schema/comics/comic_details.py b/kontor-api/src/schema/comics/comic_details.py new file mode 100644 index 0000000..16de453 --- /dev/null +++ b/kontor-api/src/schema/comics/comic_details.py @@ -0,0 +1,26 @@ +from typing import List +from pydantic import BaseModel + +from src.schema.comics.artist import ArtistResponse +from src.schema.comics.issue import IssueResponse +from src.schema.comics.publisher import PublisherResponse +from src.schema.comics.volume import VolumeResponse +from src.schema.comics.worktype import WorktypeResponse + + +class ComicWorktypeArtistResponse(BaseModel): + worktype: WorktypeResponse + artists: List[ArtistResponse] + + +class ComicDetailsResponse(BaseModel): + id: str + created: str + title: str + completed : bool + current_order : bool + weblink: str + publisher: PublisherResponse + issues: List[IssueResponse] + volumes: List[VolumeResponse] + works: List[ComicWorktypeArtistResponse] diff --git a/kontor-api/src/schema/comics/issue.py b/kontor-api/src/schema/comics/issue.py new file mode 100644 index 0000000..719114c --- /dev/null +++ b/kontor-api/src/schema/comics/issue.py @@ -0,0 +1,8 @@ +from pydantic import BaseModel + + +class IssueResponse(BaseModel): + id: str + issue_number: str + in_stock: bool + is_read: bool diff --git a/kontor-api/src/schema/comics/issue_details.py b/kontor-api/src/schema/comics/issue_details.py new file mode 100644 index 0000000..3c39799 --- /dev/null +++ b/kontor-api/src/schema/comics/issue_details.py @@ -0,0 +1,13 @@ +from pydantic import BaseModel + +from src.schema.comics.comic import ComicResponse +from src.schema.comics.volume import VolumeResponse + + +class IssueDetailsResponse(BaseModel): + id: str + issue_number: str + in_stock: bool + is_read: bool + comic: ComicResponse + volume: VolumeResponse | None diff --git a/kontor-api/src/schema/comics/publisher.py b/kontor-api/src/schema/comics/publisher.py new file mode 100644 index 0000000..bbbe175 --- /dev/null +++ b/kontor-api/src/schema/comics/publisher.py @@ -0,0 +1,6 @@ +from pydantic import BaseModel + + +class PublisherResponse(BaseModel): + id: str + name: str diff --git a/kontor-api/src/schema/comics/publisher_details.py b/kontor-api/src/schema/comics/publisher_details.py new file mode 100644 index 0000000..5c4444e --- /dev/null +++ b/kontor-api/src/schema/comics/publisher_details.py @@ -0,0 +1,14 @@ +from typing import List + +from pydantic import BaseModel + +from src.schema.comics.comic import ComicResponse +from src.schema.comics.publisher import PublisherResponse + + +class PublisherDetailsResponse(BaseModel): + id: str + name: str + parent_publisher: PublisherResponse | None + imprints: List[PublisherResponse] + comics: List[ComicResponse] diff --git a/kontor-api/src/schema/comics/volume.py b/kontor-api/src/schema/comics/volume.py new file mode 100644 index 0000000..81d7985 --- /dev/null +++ b/kontor-api/src/schema/comics/volume.py @@ -0,0 +1,6 @@ +from pydantic import BaseModel + + +class VolumeResponse(BaseModel): + id: str + name: str diff --git a/kontor-api/src/schema/comics/worktype.py b/kontor-api/src/schema/comics/worktype.py new file mode 100644 index 0000000..a072938 --- /dev/null +++ b/kontor-api/src/schema/comics/worktype.py @@ -0,0 +1,9 @@ +from pydantic import BaseModel + +class AddWorkType(BaseModel): + worktype: str + +class WorktypeResponse(BaseModel): + id: str + name: str + diff --git a/kontor-api/src/schema/media/actor.py b/kontor-api/src/schema/media/actor.py new file mode 100644 index 0000000..3ad8408 --- /dev/null +++ b/kontor-api/src/schema/media/actor.py @@ -0,0 +1,18 @@ +from datetime import datetime + +from src.db.models.media import MediaActor +from pydantic import BaseModel + + +class MediaActorResponse(BaseModel): + id: str + name: str | None + url: str + +class Actor(BaseModel): + name: str | None + url: str + +def get_actor_details(media_actor: MediaActor) -> MediaActorResponse: + reponse: MediaActorResponse = MediaActorResponse(id=media_actor.id, name=str(media_actor.name), url=str(media_actor.url)) + return reponse diff --git a/kontor-api/src/schema/media/actorfile.py b/kontor-api/src/schema/media/actorfile.py new file mode 100644 index 0000000..9d135f1 --- /dev/null +++ b/kontor-api/src/schema/media/actorfile.py @@ -0,0 +1,16 @@ +from datetime import datetime + +from src.db.models.media import MediaActorFile, MediaFile +from pydantic import BaseModel + + +class MediaActorFileResponse(BaseModel): + id: str + file_id: str + actor_id: str + +def get_actorfile_details(media_actorfile: MediaActorFile) -> MediaActorFileResponse: + response: MediaActorFileResponse = MediaActorFileResponse(id=media_actorfile.id, + file_id=str(media_actorfile.media_file_id), + actor_id=str(media_actorfile.media_actor_id)) + return response diff --git a/kontor-api/src/schema/media/file.py b/kontor-api/src/schema/media/file.py index 2c468e8..32de2c6 100644 --- a/kontor-api/src/schema/media/file.py +++ b/kontor-api/src/schema/media/file.py @@ -1,45 +1,38 @@ from datetime import datetime -from uuid import UUID from src.db.models.media import MediaFile from pydantic import BaseModel class MediaFileResponse(BaseModel): - id: UUID + id: str title: str | None = None file_name: str | None = None cloud_link: str | None = None - url: str + url: str | None = None review: bool = False should_download: bool = False class Link(BaseModel): url: str -def get_file_details(mediafile: MediaFile) -> MediaFileResponse | None: +def get_file_details(mediafile: MediaFile) -> MediaFileResponse: response = MediaFileResponse(id=mediafile.id, title=mediafile.title, file_name=mediafile.file_name, cloud_link=mediafile.cloud_link, url=str(mediafile.url), - review=(mediafile.review == 1), - should_download=(mediafile.should_download == 1)) + review=mediafile.review, + should_download=mediafile.should_download) #print(f"id: {mediafile.id}: review: {response.review} <- {mediafile.review}") #print(f"id: {mediafile.id}: download: {response.should_download} <- {mediafile.should_download}") return response def set_file(model: MediaFileResponse, mediafile: MediaFile) -> None: mediafile.file_name = model.file_name - mediafile.cloud_link = model.cloud_link - mediafile.url = model.url + mediafile.cloud_link = model.cloud_link # type: ignore + mediafile.url = model.url # type: ignore mediafile.title = model.title mediafile.last_modified_date = datetime.now() - if model.review: - mediafile.review = 1 - else: - mediafile.review = 0 - if model.should_download: - mediafile.should_download = 1 - else: - mediafile.should_download = 0 + mediafile.review = model.review + mediafile.should_download = model.should_download diff --git a/kontor-api/src/schema/media/video.py b/kontor-api/src/schema/media/video.py new file mode 100644 index 0000000..ed4319a --- /dev/null +++ b/kontor-api/src/schema/media/video.py @@ -0,0 +1,5 @@ +from pydantic import BaseModel + + +class AddLink(BaseModel): + url: str diff --git a/kontor-api/src/schema/tysc/sport.py b/kontor-api/src/schema/tysc/sport.py index 8ddbfb3..017d169 100644 --- a/kontor-api/src/schema/tysc/sport.py +++ b/kontor-api/src/schema/tysc/sport.py @@ -1,8 +1,8 @@ -from uuid import UUID +from typing import AnyStr from pydantic import BaseModel class SportResponse(BaseModel): - id: UUID + id: AnyStr name: str diff --git a/kontor-api/src/static/style.css b/kontor-api/src/static/style.css new file mode 100644 index 0000000..8b5c0c3 --- /dev/null +++ b/kontor-api/src/static/style.css @@ -0,0 +1,172 @@ +* { + box-sizing: border-box; +} + +body { + font-family: Arial; + padding: 10px; + background: lightgrey; +} + +/* Header/Blog Title */ +.header { + padding: 30px; + text-align: center; + background-color: lightblue; +} + +.header h1 { + font-size: 50px; +} + +/* Style the top navigation bar */ +.topnav { + overflow: hidden; + background-color: darkgrey; +} + +/* Style the topnav links */ +.topnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +/* Change color on hover */ +.topnav a:hover { + background-color: #ddd; + color: black; +} + +.subnav { + overflow: hidden; + background-color: grey; +} + +.subnav a { + float: left; + display: block; + color: #f2f2f2; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +.form-inline { + display: flex; + flex-flow: row wrap; + align-items: center; + padding-top: 10px; + padding-left: 20px; +} + +.form-inline label { + margin: 5px 10px 5px 0; +} + +.form-inline input { + padding-right: 50px; + margin-right: 10px; +} + +.form-inline button { + padding: 10px 20px; + background-color: dodgerblue; + border: 1px solid #ddd; + color: white; + border-radius: 10px; +} + +.form-inline button:hover { + background-color: royalblue; +} + +.pill-nav a { + display: inline-block; + color: white; + background-color: dodgerblue; + text-align: center; + padding: 10px; + text-decoration: none; + border-radius: 10px; + margin-left: 20px; +} + +/* Change the color of links on mouse-over */ +.pill-nav a:hover { + background-color: royalblue; + color: white; +} + +/* Add a color to the active/current link */ +.pill-nav a.active { + background-color: royalblue; + color: white; +} + +.maincolumn { + float:left; + width: 100%; +} +/* Create two unequal columns that floats next to each other */ +/* Left column */ +.leftcolumn { + float: left; + width: 75%; +} + +/* Right column */ +.rightcolumn { + float: left; + width: 25%; + background-color: #f1f1f1; + padding-left: 20px; +} + +/* Fake image */ +.fakeimg { + background-color: #aaa; + width: 100%; + padding: 20px; +} + +/* Add a card effect for articles */ +.card { + background-color: white; + padding: 20px; + margin-top: 20px; +} + +/* Clear floats after the columns */ +.row::after { + content: ""; + display: table; + clear: both; +} + +/* Footer */ +.footer { + padding: 20px; + text-align: center; + background: #ddd; + margin-top: 20px; +} + +/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 800px) { + .leftcolumn, .rightcolumn { + width: 100%; + padding: 0; + } +} + +/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */ +@media screen and (max-width: 400px) { + .topnav a { + float: none; + width: 100%; + } +} diff --git a/kontor-api/src/templates/admin/permissions.html b/kontor-api/src/templates/admin/permissions.html new file mode 100644 index 0000000..fa40de2 --- /dev/null +++ b/kontor-api/src/templates/admin/permissions.html @@ -0,0 +1,38 @@ +{% extends "shared/base.html" %} + +{% block title %} + Permissions +{% endblock %} + +{% block content %} + {% with msg=msg %} + {% include "components/alerts.html" %} + {% endwith %} +
+
+
+

Permissions..

+
+
+
+ + + + + + + {% for permission in permissions %} + + + + + + {% endfor %} + +
NameActions
{{permission.name}}EditDelete
+ +
+
+{% endblock %} diff --git a/kontor-api/src/templates/admin/profiles.html b/kontor-api/src/templates/admin/profiles.html new file mode 100644 index 0000000..254ec84 --- /dev/null +++ b/kontor-api/src/templates/admin/profiles.html @@ -0,0 +1,43 @@ +{% extends "shared/base.html" %} + +{% block title %} + Profiles +{% endblock %} + +{% block content %} + {% with msg=msg %} + {% include "components/alerts.html" %} + {% endwith %} +
+
+
+

Profiles..

+
+
+
+ + + + + + + + + {% for profile in profiles %} + + + + + + + + + {% endfor %} + +
UsernameFirst NameLast NameActions
{{profile.user_name}}{{profile.first_name}}{{profile.last_name}}{{profile.email}}EditDelete
+ +
+
+{% endblock %} diff --git a/kontor-api/src/templates/auth/login.html b/kontor-api/src/templates/auth/login.html new file mode 100644 index 0000000..0b2a94f --- /dev/null +++ b/kontor-api/src/templates/auth/login.html @@ -0,0 +1,40 @@ +{% extends "shared/base.html" %} + + +{% block title %} + Login +{% endblock %} + +{% block content %} +
+
+
Login to Kontor
+
+ {% for error in errors %} +
  • {{error}}
  • + {% endfor %} +
    +
    + {% if msg %} +
    + {{msg}} +
    + {% endif %} +
    +
    + +
    +
    +
    + + +
    +
    + + +
    + +
    +
    +
    + {% endblock %} diff --git a/kontor-api/src/templates/components/artist_cards.html b/kontor-api/src/templates/comic/artist_cards.html similarity index 82% rename from kontor-api/src/templates/components/artist_cards.html rename to kontor-api/src/templates/comic/artist_cards.html index 53192af..f0f5584 100644 --- a/kontor-api/src/templates/components/artist_cards.html +++ b/kontor-api/src/templates/comic/artist_cards.html @@ -1,6 +1,7 @@
    {{obj.name}}
    +

    Link : {{obj.weblink}}

    Read more
    diff --git a/kontor-api/src/templates/comic/artist_detail.html b/kontor-api/src/templates/comic/artist_detail.html index 58ee61b..b540bcd 100644 --- a/kontor-api/src/templates/comic/artist_detail.html +++ b/kontor-api/src/templates/comic/artist_detail.html @@ -20,12 +20,16 @@ Artist Name {{artist.name}} + + Link + {{artist.weblink}} + Works {% for work in artist.get_comics() %}

    - {{work}}: + {{work.name}}