diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3652ec5..9e52e96 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,18 +3,18 @@ "isRoot": true, "tools": { "husky": { - "version": "0.7.2", + "version": "0.7.1", "commands": [ "husky" ], "rollForward": false }, "csharpier": { - "version": "0.30.6", + "version": "0.29.2", "commands": [ "dotnet-csharpier" ], "rollForward": false } } -} +} \ No newline at end of file diff --git a/.dockerignore b/.dockerignore index d755b6c..f90ce74 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,5 +20,4 @@ **/secrets.dev.yaml **/values.dev.yaml LICENSE -README.md -static-pages/* +README.md \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 22061dc..e6b41f9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,7 @@ resharper_not_accessed_positional_property_local_highlighting = none # Microsoft .NET properties csharp_new_line_before_members_in_object_initializers = false -csharp_preferred_modifier_order = public, internal, protected, private, file, new, virtual, override, required, abstract, sealed, static, extern, unsafe, volatile, async, readonly:suggestion +csharp_preferred_modifier_order = public, internal, protected, private, file, new, required, abstract, virtual, sealed, static, override, extern, unsafe, volatile, async, readonly:suggestion # ReSharper properties resharper_align_multiline_binary_expressions_chain = false diff --git a/.gitignore b/.gitignore index b1e845f..c61154d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,16 +6,7 @@ config.ini *.DotSettings.user proxy-config.json .DS_Store -.idea/.idea.Foxnouns.NET/.idea/dataSources.xml -.idea/.idea.Foxnouns.NET/.idea/sqldialects.xml docker/config.ini docker/proxy-config.json docker/frontend.env - -Foxnouns.DataMigrator/apps.json -migration-tools/avatar-proxy/config.json -migration-tools/avatar-migrator/.env - -out/ -build/ diff --git a/.husky/task-runner.json b/.husky/task-runner.json index 72e6fea..8e50f6a 100644 --- a/.husky/task-runner.json +++ b/.husky/task-runner.json @@ -3,23 +3,15 @@ "tasks": [ { "name": "run-prettier", - "command": "npx", - "args": ["prettier", "-w", "${staged}"], - "include": [ - "Foxnouns.Frontend/**/*.ts", - "Foxnouns.Frontend/**/*.json", - "Foxnouns.Frontend/**/*.scss", - "Foxnouns.Frontend/**/*.js", - "Foxnouns.Frontend/**/*.svelte" - ], - "cwd": "Foxnouns.Frontend/", + "command": "pnpm", + "args": ["format"], "pathMode": "absolute" }, { "name": "run-csharpier", "command": "dotnet", - "args": ["csharpier", "${staged}"], - "include": ["**/*.cs"] + "args": [ "csharpier", "${staged}" ], + "include": [ "**/*.cs" ] } ] } diff --git a/DOCKER.md b/DOCKER.md index b670743..b485eb7 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,29 +1,10 @@ -# Running with Docker (pre-built backend and rate limiter) *(linux/arm64 only)* - -Because SvelteKit is a pain in the ass to build in a container, and processes secrets at build time, -there is no pre-built frontend image available. -If you don't want to build images on your server, I recommend running the frontend outside of Docker. -This is preconfigured in `docker-compose.prebuilt.yml`: the backend, database, and rate limiter will run in Docker, -while the frontend is run as a normal, non-containerized service. +# Running with Docker 1. Copy `docker/config.example.ini` to `docker/config.ini`, and change the settings to your liking. 2. Copy `docker/proxy-config.example.json` to `docker/proxy-config.json`, and do the same. -3. Run with `docker compose up -f docker-compose.prebuilt.yml` - -The backend will listen on port 5001 and metrics will be available on port 5002. -The rate limiter (which is what should be exposed to the outside) will listen on port 5003. -You can use `docker/Caddyfile` as an example for your reverse proxy. If you use nginx, good luck. - -# Running with Docker (local builds) - -In order to run *everything* in Docker, you'll have to build every container yourself. -The advantage of this is that it's an all-in-one solution, where you only have to point your reverse proxy at a single container. -The disadvantage is that you'll likely have to build the images on the server you'll be running them on. - -1. Configure the backend and rate limiter as in the section above. -2. Copy `docker/frontend.example.env` to `docker/frontend.env`, and configure it. -3. Build with `docker compose build -f docker-compose.local.yml` -4. Run with `docker compose up -f docker-compose.local.yml` +3. Copy `docker/frontend.example.env` to `docker/frontend.env`, and do th esame. +4. Build with `docker compose build` +5. Run with `docker compose up` The Caddy server will listen on `localhost:5004` for the frontend and API, and on `localhost:5005` for the profile URL shortener. diff --git a/Foxnouns.Backend/Config.cs b/Foxnouns.Backend/Config.cs index 461e55e..e0a579b 100644 --- a/Foxnouns.Backend/Config.cs +++ b/Foxnouns.Backend/Config.cs @@ -26,11 +26,11 @@ public class Config public string MediaBaseUrl { get; init; } = null!; public string Address => $"http://{Host}:{Port}"; + public string MetricsAddress => $"http://{Host}:{Logging.MetricsPort}"; public LoggingConfig Logging { get; init; } = new(); public DatabaseConfig Database { get; init; } = new(); public StorageConfig Storage { get; init; } = new(); - public LimitsConfig Limits { get; init; } = new(); public EmailAuthConfig EmailAuth { get; init; } = new(); public DiscordAuthConfig DiscordAuth { get; init; } = new(); public GoogleAuthConfig GoogleAuth { get; init; } = new(); @@ -54,7 +54,6 @@ public class Config public bool? EnablePooling { get; init; } public int? Timeout { get; init; } public int? MaxPoolSize { get; init; } - public string Redis { get; init; } = string.Empty; } public class StorageConfig @@ -94,22 +93,4 @@ public class Config public string? ClientId { get; init; } public string? ClientSecret { get; init; } } - - public class LimitsConfig - { - public int MaxMemberCount { get; init; } = 1000; - - public int MaxFields { get; init; } = 25; - public int MaxFieldNameLength { get; init; } = 100; - public int MaxFieldEntryTextLength { get; init; } = 100; - public int MaxFieldEntries { get; init; } = 100; - - public int MaxUsernameLength { get; init; } = 40; - public int MaxMemberNameLength { get; init; } = 100; - public int MaxDisplayNameLength { get; init; } = 100; - public int MaxLinks { get; init; } = 25; - public int MaxLinkLength { get; init; } = 256; - public int MaxBioLength { get; init; } = 1024; - public int MaxAvatarLength { get; init; } = 1_500_000; - } } diff --git a/Foxnouns.Backend/Controllers/Authentication/AuthController.cs b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs index 39d3b11..0d95eb2 100644 --- a/Foxnouns.Backend/Controllers/Authentication/AuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/AuthController.cs @@ -46,7 +46,7 @@ public class AuthController( config.GoogleAuth.Enabled, config.TumblrAuth.Enabled ); - string state = HttpUtility.UrlEncode(await keyCacheService.GenerateAuthStateAsync()); + string state = HttpUtility.UrlEncode(await keyCacheService.GenerateAuthStateAsync(ct)); string? discord = null; string? google = null; string? tumblr = null; diff --git a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs index 8024ee6..bdf4b9a 100644 --- a/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/EmailAuthController.cs @@ -56,7 +56,7 @@ public class EmailAuthController( if (!req.Email.Contains('@')) throw new ApiError.BadRequest("Email is invalid", "email", req.Email); - string state = await keyCacheService.GenerateRegisterEmailStateAsync(req.Email, null); + string state = await keyCacheService.GenerateRegisterEmailStateAsync(req.Email, null, ct); // If there's already a user with that email address, pretend we sent an email but actually ignore it if ( diff --git a/Foxnouns.Backend/Controllers/Authentication/FediverseAuthController.cs b/Foxnouns.Backend/Controllers/Authentication/FediverseAuthController.cs index 1ae2ef9..edc7b6a 100644 --- a/Foxnouns.Backend/Controllers/Authentication/FediverseAuthController.cs +++ b/Foxnouns.Backend/Controllers/Authentication/FediverseAuthController.cs @@ -94,7 +94,8 @@ public class FediverseAuthController( public async Task RegisterAsync([FromBody] OauthRegisterRequest req) { FediverseTicketData? ticketData = await keyCacheService.GetKeyAsync( - $"fediverse:{req.Ticket}" + $"fediverse:{req.Ticket}", + true ); if (ticketData == null) throw new ApiError.BadRequest("Invalid ticket", "ticket", req.Ticket); diff --git a/Foxnouns.Backend/Controllers/DeleteUserController.cs b/Foxnouns.Backend/Controllers/DeleteUserController.cs deleted file mode 100644 index d1c8e62..0000000 --- a/Foxnouns.Backend/Controllers/DeleteUserController.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Middleware; -using Microsoft.AspNetCore.Mvc; -using NodaTime; - -namespace Foxnouns.Backend.Controllers; - -[Route("/api/internal/self-delete")] -[Authorize("*")] -[ApiExplorerSettings(IgnoreApi = true)] -public class DeleteUserController(DatabaseContext db, IClock clock, ILogger logger) - : ApiControllerBase -{ - private readonly ILogger _logger = logger.ForContext(); - - [HttpPost("delete")] - public async Task DeleteSelfAsync() - { - _logger.Information( - "User {UserId} has requested their account to be deleted", - CurrentUser!.Id - ); - - CurrentUser.Deleted = true; - CurrentUser.DeletedAt = clock.GetCurrentInstant(); - - db.Update(CurrentUser); - await db.SaveChangesAsync(); - return NoContent(); - } - - [HttpPost("force")] - [Limit(UsableByDeletedUsers = true)] - public async Task ForceDeleteAsync() - { - if (!CurrentUser!.Deleted) - throw new ApiError.BadRequest("Your account isn't deleted."); - - _logger.Information( - "User {UserId} has requested an early full delete of their account", - CurrentUser.Id - ); - - // This is the easiest way to force delete a user, don't judge me - CurrentUser.DeletedAt = clock.GetCurrentInstant() - Duration.FromDays(365); - db.Update(CurrentUser); - await db.SaveChangesAsync(); - return NoContent(); - } - - [HttpPost("undelete")] - [Limit(UsableByDeletedUsers = true)] - public async Task UndeleteSelfAsync() - { - if (!CurrentUser!.Deleted) - throw new ApiError.BadRequest("Your account isn't deleted."); - if (CurrentUser!.DeletedBy != null) - { - throw new ApiError.BadRequest( - "Your account has been suspended and can't be reactivated by yourself." - ); - } - - _logger.Information( - "User {UserId} has requested to undelete their account", - CurrentUser.Id - ); - - CurrentUser.Deleted = false; - CurrentUser.DeletedAt = null; - db.Update(CurrentUser); - await db.SaveChangesAsync(); - return NoContent(); - } -} diff --git a/Foxnouns.Backend/Controllers/ExportsController.cs b/Foxnouns.Backend/Controllers/ExportsController.cs index 0442386..315efbc 100644 --- a/Foxnouns.Backend/Controllers/ExportsController.cs +++ b/Foxnouns.Backend/Controllers/ExportsController.cs @@ -12,6 +12,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Queuing.Interfaces; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; @@ -25,10 +26,14 @@ namespace Foxnouns.Backend.Controllers; [Route("/api/internal/data-exports")] [Authorize("identify")] -[Limit(UsableByDeletedUsers = true)] [ApiExplorerSettings(IgnoreApi = true)] -public class ExportsController(ILogger logger, Config config, IClock clock, DatabaseContext db) - : ApiControllerBase +public class ExportsController( + ILogger logger, + Config config, + IClock clock, + DatabaseContext db, + IQueue queue +) : ApiControllerBase { private static readonly Duration MinimumTimeBetween = Duration.FromDays(1); private readonly ILogger _logger = logger.ForContext(); @@ -52,7 +57,7 @@ public class ExportsController(ILogger logger, Config config, IClock clock, Data } private string ExportUrl(Snowflake userId, string filename) => - $"{config.MediaBaseUrl}/data-exports/{userId}/{filename}/data-export.zip"; + $"{config.MediaBaseUrl}/data-exports/{userId}/{filename}.zip"; [HttpPost] public async Task QueueDataExportAsync() @@ -74,7 +79,10 @@ public class ExportsController(ILogger logger, Config config, IClock clock, Data throw new ApiError.BadRequest("You can't request a new data export so soon."); } - CreateDataExportJob.Enqueue(CurrentUser.Id); + queue.QueueInvocableWithPayload( + new CreateDataExportPayload(CurrentUser.Id) + ); + return NoContent(); } } diff --git a/Foxnouns.Backend/Controllers/FlagsController.cs b/Foxnouns.Backend/Controllers/FlagsController.cs index bed022a..2b145ac 100644 --- a/Foxnouns.Backend/Controllers/FlagsController.cs +++ b/Foxnouns.Backend/Controllers/FlagsController.cs @@ -12,6 +12,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Queuing.Interfaces; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; @@ -21,7 +22,6 @@ using Foxnouns.Backend.Services; using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using XidNet; namespace Foxnouns.Backend.Controllers; @@ -29,11 +29,12 @@ namespace Foxnouns.Backend.Controllers; public class FlagsController( DatabaseContext db, UserRendererService userRenderer, - ISnowflakeGenerator snowflakeGenerator + ISnowflakeGenerator snowflakeGenerator, + IQueue queue ) : ApiControllerBase { [HttpGet] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] [Authorize("user.read_flags")] [ProducesResponseType>(statusCode: StatusCodes.Status200OK)] public async Task GetFlagsAsync(CancellationToken ct = default) @@ -63,7 +64,6 @@ public class FlagsController( var flag = new PrideFlag { Id = snowflakeGenerator.GenerateSnowflake(), - LegacyId = Xid.NewXid().ToString(), UserId = CurrentUser!.Id, Name = req.Name, Description = req.Description, @@ -72,7 +72,10 @@ public class FlagsController( db.Add(flag); await db.SaveChangesAsync(); - CreateFlagJob.Enqueue(new CreateFlagPayload(flag.Id, CurrentUser!.Id, req.Image)); + queue.QueueInvocableWithPayload( + new CreateFlagPayload(flag.Id, CurrentUser!.Id, req.Image) + ); + return Accepted(userRenderer.RenderPrideFlag(flag)); } diff --git a/Foxnouns.Backend/Controllers/InternalController.cs b/Foxnouns.Backend/Controllers/InternalController.cs index 3954547..85bc774 100644 --- a/Foxnouns.Backend/Controllers/InternalController.cs +++ b/Foxnouns.Backend/Controllers/InternalController.cs @@ -38,8 +38,6 @@ public partial class InternalController(DatabaseContext db) : ControllerBase { if (template.StartsWith("api/v2")) template = template["api/v2".Length..]; - else if (template.StartsWith("api/v1")) - template = template["api/v1".Length..]; template = PathVarRegex() .Replace(template, "{id}") // Replace all path variables (almost always IDs) with `{id}` .Replace("@me", "{id}"); // Also replace hardcoded `@me` with `{id}` diff --git a/Foxnouns.Backend/Controllers/MembersController.cs b/Foxnouns.Backend/Controllers/MembersController.cs index 635dab9..9b94b30 100644 --- a/Foxnouns.Backend/Controllers/MembersController.cs +++ b/Foxnouns.Backend/Controllers/MembersController.cs @@ -12,6 +12,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Queuing.Interfaces; using EntityFramework.Exceptions.Common; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; @@ -25,7 +26,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; using NodaTime; -using XidNet; namespace Foxnouns.Backend.Controllers; @@ -36,16 +36,15 @@ public class MembersController( MemberRendererService memberRenderer, ISnowflakeGenerator snowflakeGenerator, ObjectStorageService objectStorageService, - IClock clock, - ValidationService validationService, - Config config + IQueue queue, + IClock clock ) : ApiControllerBase { private readonly ILogger _logger = logger.ForContext(); [HttpGet] [ProducesResponseType>(StatusCodes.Status200OK)] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] public async Task GetMembersAsync(string userRef, CancellationToken ct = default) { User user = await db.ResolveUserAsync(userRef, CurrentToken, ct); @@ -54,7 +53,7 @@ public class MembersController( [HttpGet("{memberRef}")] [ProducesResponseType(StatusCodes.Status200OK)] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] public async Task GetMemberAsync( string userRef, string memberRef, @@ -65,6 +64,8 @@ public class MembersController( return Ok(memberRenderer.RenderMember(member, CurrentToken)); } + public const int MaxMemberCount = 500; + [HttpPost("/api/v2/users/@me/members")] [ProducesResponseType(StatusCodes.Status200OK)] [Authorize("member.create")] @@ -75,32 +76,31 @@ public class MembersController( { ValidationUtils.Validate( [ - ("name", validationService.ValidateMemberName(req.Name)), - ("display_name", validationService.ValidateDisplayName(req.DisplayName)), - ("bio", validationService.ValidateBio(req.Bio)), - ("avatar", validationService.ValidateAvatar(req.Avatar)), - .. validationService.ValidateFields(req.Fields, CurrentUser!.CustomPreferences), - .. validationService.ValidateFieldEntries( + ("name", ValidationUtils.ValidateMemberName(req.Name)), + ("display_name", ValidationUtils.ValidateDisplayName(req.DisplayName)), + ("bio", ValidationUtils.ValidateBio(req.Bio)), + ("avatar", ValidationUtils.ValidateAvatar(req.Avatar)), + .. ValidationUtils.ValidateFields(req.Fields, CurrentUser!.CustomPreferences), + .. ValidationUtils.ValidateFieldEntries( req.Names?.ToArray(), CurrentUser!.CustomPreferences, "names" ), - .. validationService.ValidatePronouns( + .. ValidationUtils.ValidatePronouns( req.Pronouns?.ToArray(), CurrentUser!.CustomPreferences ), - .. validationService.ValidateLinks(req.Links), + .. ValidationUtils.ValidateLinks(req.Links), ] ); int memberCount = await db.Members.CountAsync(m => m.UserId == CurrentUser.Id, ct); - if (memberCount >= config.Limits.MaxMemberCount) + if (memberCount >= MaxMemberCount) throw new ApiError.BadRequest("Maximum number of members reached"); var member = new Member { Id = snowflakeGenerator.GenerateSnowflake(), - LegacyId = Xid.NewXid().ToString(), User = CurrentUser!, Name = req.Name, DisplayName = req.DisplayName, @@ -121,9 +121,6 @@ public class MembersController( CurrentUser!.Id ); - CurrentUser.LastActive = clock.GetCurrentInstant(); - db.Update(CurrentUser); - try { await db.SaveChangesAsync(ct); @@ -140,7 +137,9 @@ public class MembersController( if (req.Avatar != null) { - MemberAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(member.Id, req.Avatar)); + queue.QueueInvocableWithPayload( + new AvatarUpdatePayload(member.Id, req.Avatar) + ); } return Ok(memberRenderer.RenderMember(member, CurrentToken)); @@ -162,25 +161,25 @@ public class MembersController( // These should only take effect when a member's name is changed, not on other changes. if (req.Name != null && req.Name != member.Name) { - errors.Add(("name", validationService.ValidateMemberName(req.Name))); + errors.Add(("name", ValidationUtils.ValidateMemberName(req.Name))); member.Name = req.Name; } if (req.HasProperty(nameof(req.DisplayName))) { - errors.Add(("display_name", validationService.ValidateDisplayName(req.DisplayName))); + errors.Add(("display_name", ValidationUtils.ValidateDisplayName(req.DisplayName))); member.DisplayName = req.DisplayName; } if (req.HasProperty(nameof(req.Bio))) { - errors.Add(("bio", validationService.ValidateBio(req.Bio))); + errors.Add(("bio", ValidationUtils.ValidateBio(req.Bio))); member.Bio = req.Bio; } if (req.HasProperty(nameof(req.Links))) { - errors.AddRange(validationService.ValidateLinks(req.Links)); + errors.AddRange(ValidationUtils.ValidateLinks(req.Links)); member.Links = req.Links ?? []; } @@ -190,7 +189,7 @@ public class MembersController( if (req.Names != null) { errors.AddRange( - validationService.ValidateFieldEntries( + ValidationUtils.ValidateFieldEntries( req.Names, CurrentUser!.CustomPreferences, "names" @@ -202,7 +201,7 @@ public class MembersController( if (req.Pronouns != null) { errors.AddRange( - validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences) + ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences) ); member.Pronouns = req.Pronouns.ToList(); } @@ -210,10 +209,7 @@ public class MembersController( if (req.Fields != null) { errors.AddRange( - validationService.ValidateFields( - req.Fields.ToList(), - CurrentUser!.CustomPreferences - ) + ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences) ); member.Fields = req.Fields.ToList(); } @@ -230,7 +226,7 @@ public class MembersController( } if (req.HasProperty(nameof(req.Avatar))) - errors.Add(("avatar", validationService.ValidateAvatar(req.Avatar))); + errors.Add(("avatar", ValidationUtils.ValidateAvatar(req.Avatar))); ValidationUtils.Validate(errors); // This is fired off regardless of whether the transaction is committed @@ -238,12 +234,11 @@ public class MembersController( // so it's in a separate block to the validation above. if (req.HasProperty(nameof(req.Avatar))) { - MemberAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(member.Id, req.Avatar)); + queue.QueueInvocableWithPayload( + new AvatarUpdatePayload(member.Id, req.Avatar) + ); } - CurrentUser.LastActive = clock.GetCurrentInstant(); - db.Update(CurrentUser); - try { await db.SaveChangesAsync(); diff --git a/Foxnouns.Backend/Controllers/MetaController.cs b/Foxnouns.Backend/Controllers/MetaController.cs index 0166e86..8552164 100644 --- a/Foxnouns.Backend/Controllers/MetaController.cs +++ b/Foxnouns.Backend/Controllers/MetaController.cs @@ -12,24 +12,20 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -using System.Text.RegularExpressions; -using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; -using Foxnouns.Backend.Services.Caching; using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Mvc; namespace Foxnouns.Backend.Controllers; [Route("/api/v2/meta")] -public partial class MetaController(Config config, NoticeCacheService noticeCache) - : ApiControllerBase +public class MetaController : ApiControllerBase { private const string Repository = "https://codeberg.org/pronounscc/pronouns.cc"; [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task GetMeta(CancellationToken ct = default) => + public IActionResult GetMeta() => Ok( new MetaResponse( Repository, @@ -43,43 +39,16 @@ public partial class MetaController(Config config, NoticeCacheService noticeCach (int)FoxnounsMetrics.UsersActiveDayCount.Value ), new LimitsResponse( - config.Limits.MaxMemberCount, - config.Limits.MaxBioLength, + MembersController.MaxMemberCount, + ValidationUtils.MaxBioLength, ValidationUtils.MaxCustomPreferences, AuthUtils.MaxAuthMethodsPerType, FlagsController.MaxFlagCount - ), - Notice: NoticeResponse(await noticeCache.GetAsync(ct)) + ) ) ); - private static MetaNoticeResponse? NoticeResponse(Notice? notice) => - notice == null ? null : new MetaNoticeResponse(notice.Id, notice.Message); - - [HttpGet("page/{page}")] - public async Task GetStaticPageAsync(string page, CancellationToken ct = default) - { - if (!PageRegex().IsMatch(page)) - { - throw new ApiError.BadRequest("Invalid page name"); - } - - string path = Path.Join(Directory.GetCurrentDirectory(), "static-pages", $"{page}.md"); - try - { - string text = await System.IO.File.ReadAllTextAsync(path, ct); - return Ok(text); - } - catch (FileNotFoundException) - { - throw new ApiError.NotFound("Page not found", code: ErrorCode.PageNotFound); - } - } - [HttpGet("/api/v2/coffee")] public IActionResult BrewCoffee() => - StatusCode(StatusCodes.Status418ImATeapot, "Sorry, I'm a teapot!"); - - [GeneratedRegex(@"^[a-z\-_]+$")] - private static partial Regex PageRegex(); + Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot); } diff --git a/Foxnouns.Backend/Controllers/Moderation/AuditLogController.cs b/Foxnouns.Backend/Controllers/Moderation/AuditLogController.cs index 304cfa4..8b556de 100644 --- a/Foxnouns.Backend/Controllers/Moderation/AuditLogController.cs +++ b/Foxnouns.Backend/Controllers/Moderation/AuditLogController.cs @@ -30,9 +30,7 @@ public class AuditLogController(DatabaseContext db, ModerationRendererService mo public async Task GetAuditLogAsync( [FromQuery] AuditLogEntryType? type = null, [FromQuery] int? limit = null, - [FromQuery] Snowflake? before = null, - [FromQuery] Snowflake? after = null, - [FromQuery(Name = "by-moderator")] Snowflake? byModerator = null + [FromQuery] Snowflake? before = null ) { limit = limit switch @@ -43,36 +41,15 @@ public class AuditLogController(DatabaseContext db, ModerationRendererService mo _ => limit, }; - IQueryable query = db - .AuditLog.Include(e => e.Report) - .OrderByDescending(e => e.Id); + IQueryable query = db.AuditLog.OrderByDescending(e => e.Id); if (before != null) query = query.Where(e => e.Id < before.Value); - else if (after != null) - query = query.Where(e => e.Id > after.Value); - if (type != null) query = query.Where(e => e.Type == type); - if (byModerator != null) - query = query.Where(e => e.ModeratorId == byModerator.Value); List entries = await query.Take(limit!.Value).ToListAsync(); return Ok(entries.Select(moderationRenderer.RenderAuditLogEntry)); } - - [HttpGet("moderators")] - public async Task GetModeratorsAsync(CancellationToken ct = default) - { - var moderators = await db - .Users.Where(u => - !u.Deleted && (u.Role == UserRole.Admin || u.Role == UserRole.Moderator) - ) - .Select(u => new { u.Id, u.Username }) - .OrderBy(u => u.Id) - .ToListAsync(ct); - - return Ok(moderators); - } } diff --git a/Foxnouns.Backend/Controllers/Moderation/LookupController.cs b/Foxnouns.Backend/Controllers/Moderation/LookupController.cs deleted file mode 100644 index 9e9fa7f..0000000 --- a/Foxnouns.Backend/Controllers/Moderation/LookupController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto; -using Foxnouns.Backend.Middleware; -using Foxnouns.Backend.Services; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; - -namespace Foxnouns.Backend.Controllers.Moderation; - -[Route("/api/v2/moderation/lookup")] -[Authorize("user.moderation")] -[Limit(RequireModerator = true)] -public class LookupController( - DatabaseContext db, - UserRendererService userRenderer, - ModerationService moderationService, - ModerationRendererService moderationRenderer -) : ApiControllerBase -{ - [HttpPost] - public async Task QueryUsersAsync( - [FromBody] QueryUsersRequest req, - CancellationToken ct = default - ) - { - var query = db.Users.Select(u => new { u.Id, u.Username }); - query = req.Fuzzy - ? query.Where(u => u.Username.Contains(req.Query)) - : query.Where(u => u.Username == req.Query); - - var users = await query.OrderBy(u => u.Id).Take(100).ToListAsync(ct); - return Ok(users); - } - - [HttpGet("{id}")] - public async Task QueryUserAsync(Snowflake id, CancellationToken ct = default) - { - User user = await db.ResolveUserAsync(id, ct); - - bool showSensitiveData = await moderationService.ShowSensitiveDataAsync( - CurrentUser!, - user, - ct - ); - - List authMethods = showSensitiveData - ? await db - .AuthMethods.Where(a => a.UserId == user.Id) - .Include(a => a.FediverseApplication) - .ToListAsync(ct) - : []; - - return Ok( - new QueryUserResponse( - User: await userRenderer.RenderUserAsync( - user, - renderMembers: false, - renderAuthMethods: false, - ct: ct - ), - MemberListHidden: user.ListHidden, - LastActive: user.LastActive, - LastSidReroll: user.LastSidReroll, - Suspended: user is { Deleted: true, DeletedBy: not null }, - Deleted: user.Deleted, - ShowSensitiveData: showSensitiveData, - AuthMethods: showSensitiveData - ? authMethods.Select(UserRendererService.RenderAuthMethod) - : null - ) - ); - } - - [HttpPost("{id}/sensitive")] - public async Task QuerySensitiveUserDataAsync( - Snowflake id, - [FromBody] QuerySensitiveUserDataRequest req - ) - { - User user = await db.ResolveUserAsync(id); - - // Don't let mods accidentally spam the audit log - bool alreadyAuthorized = await moderationService.ShowSensitiveDataAsync(CurrentUser!, user); - if (alreadyAuthorized) - return NoContent(); - - AuditLogEntry entry = await moderationService.QuerySensitiveDataAsync( - CurrentUser!, - user, - req.Reason - ); - - return Ok(moderationRenderer.RenderAuditLogEntry(entry)); - } -} diff --git a/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs b/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs deleted file mode 100644 index 3d2d6bb..0000000 --- a/Foxnouns.Backend/Controllers/Moderation/NoticesController.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto; -using Foxnouns.Backend.Middleware; -using Foxnouns.Backend.Services; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using NodaTime; - -namespace Foxnouns.Backend.Controllers.Moderation; - -[Route("/api/v2/notices")] -[Authorize("user.moderation")] -[Limit(RequireModerator = true)] -public class NoticesController( - DatabaseContext db, - UserRendererService userRenderer, - ISnowflakeGenerator snowflakeGenerator, - IClock clock -) : ApiControllerBase -{ - [HttpGet] - public async Task GetNoticesAsync(CancellationToken ct = default) - { - List notices = await db - .Notices.Include(n => n.Author) - .OrderByDescending(n => n.Id) - .ToListAsync(ct); - return Ok(notices.Select(RenderNotice)); - } - - [HttpPost] - public async Task CreateNoticeAsync(CreateNoticeRequest req) - { - Instant now = clock.GetCurrentInstant(); - if (req.StartTime < now) - { - throw new ApiError.BadRequest( - "Start time cannot be in the past", - "start_time", - req.StartTime - ); - } - - if (req.EndTime < now) - { - throw new ApiError.BadRequest( - "End time cannot be in the past", - "end_time", - req.EndTime - ); - } - - var notice = new Notice - { - Id = snowflakeGenerator.GenerateSnowflake(), - Message = req.Message, - StartTime = req.StartTime ?? clock.GetCurrentInstant(), - EndTime = req.EndTime, - Author = CurrentUser!, - }; - - db.Add(notice); - await db.SaveChangesAsync(); - - return Ok(RenderNotice(notice)); - } - - private NoticeResponse RenderNotice(Notice notice) => - new( - notice.Id, - notice.Message, - notice.StartTime, - notice.EndTime, - userRenderer.RenderPartialUser(notice.Author) - ); -} diff --git a/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs b/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs index c5472b3..3e9f905 100644 --- a/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs +++ b/Foxnouns.Backend/Controllers/Moderation/ReportsController.cs @@ -18,7 +18,6 @@ using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; -using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; @@ -50,8 +49,6 @@ public class ReportsController( [FromBody] CreateReportRequest req ) { - ValidationUtils.Validate([("context", ValidationUtils.ValidateReportContext(req.Context))]); - User target = await db.ResolveUserAsync(id); if (target.Id == CurrentUser!.Id) @@ -99,7 +96,6 @@ public class ReportsController( TargetUserId = target.Id, TargetMemberId = null, Reason = req.Reason, - Context = req.Context, TargetType = ReportTargetType.User, TargetSnapshot = snapshot, }; @@ -116,8 +112,6 @@ public class ReportsController( [FromBody] CreateReportRequest req ) { - ValidationUtils.Validate([("context", ValidationUtils.ValidateReportContext(req.Context))]); - Member target = await db.ResolveMemberAsync(id); if (target.User.Id == CurrentUser!.Id) @@ -164,7 +158,6 @@ public class ReportsController( TargetUserId = target.User.Id, TargetMemberId = target.Id, Reason = req.Reason, - Context = req.Context, TargetType = ReportTargetType.Member, TargetSnapshot = snapshot, }; @@ -220,40 +213,7 @@ public class ReportsController( return Ok(reports.Select(moderationRenderer.RenderReport)); } - [HttpGet("reports/{id}")] - [Authorize("user.moderation")] - [Limit(RequireModerator = true)] - public async Task GetReportAsync(Snowflake id, CancellationToken ct = default) - { - Report? report = await db - .Reports.Include(r => r.Reporter) - .Include(r => r.TargetUser) - .Include(r => r.TargetMember) - .Include(r => r.AuditLogEntry) - .FirstOrDefaultAsync(r => r.Id == id, ct); - if (report == null) - throw new ApiError.NotFound("No report with that ID found."); - - return Ok( - new ReportDetailResponse( - Report: moderationRenderer.RenderReport(report), - User: await userRenderer.RenderUserAsync( - report.TargetUser, - renderMembers: false, - ct: ct - ), - Member: report.TargetMember != null - ? memberRenderer.RenderMember(report.TargetMember) - : null, - AuditLogEntry: report.AuditLogEntry != null - ? moderationRenderer.RenderAuditLogEntry(report.AuditLogEntry) - : null - ) - ); - } - [HttpPost("reports/{id}/ignore")] - [Authorize("user.moderation")] [Limit(RequireModerator = true)] public async Task IgnoreReportAsync( Snowflake id, diff --git a/Foxnouns.Backend/Controllers/NotificationsController.cs b/Foxnouns.Backend/Controllers/NotificationsController.cs index 873344c..8bea907 100644 --- a/Foxnouns.Backend/Controllers/NotificationsController.cs +++ b/Foxnouns.Backend/Controllers/NotificationsController.cs @@ -1,17 +1,3 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Middleware; @@ -31,7 +17,7 @@ public class NotificationsController( { [HttpGet] [Authorize("user.moderation")] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] public async Task GetNotificationsAsync([FromQuery] bool all = false) { IQueryable query = db.Notifications.Where(n => n.TargetId == CurrentUser!.Id); @@ -45,7 +31,7 @@ public class NotificationsController( [HttpPut("{id}/ack")] [Authorize("user.moderation")] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] public async Task AcknowledgeNotificationAsync(Snowflake id) { Notification? notification = await db.Notifications.FirstOrDefaultAsync(n => diff --git a/Foxnouns.Backend/Controllers/UsersController.cs b/Foxnouns.Backend/Controllers/UsersController.cs index ed9a48f..d567bdb 100644 --- a/Foxnouns.Backend/Controllers/UsersController.cs +++ b/Foxnouns.Backend/Controllers/UsersController.cs @@ -12,6 +12,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Queuing.Interfaces; using EntityFramework.Exceptions.Common; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; @@ -33,28 +34,20 @@ public class UsersController( ILogger logger, UserRendererService userRenderer, ISnowflakeGenerator snowflakeGenerator, - IClock clock, - ValidationService validationService + IQueue queue, + IClock clock ) : ApiControllerBase { private readonly ILogger _logger = logger.ForContext(); [HttpGet("{userRef}")] [ProducesResponseType(statusCode: StatusCodes.Status200OK)] - [Limit(UsableByDeletedUsers = true)] + [Limit(UsableBySuspendedUsers = true)] public async Task GetUserAsync(string userRef, CancellationToken ct = default) { User user = await db.ResolveUserAsync(userRef, CurrentToken, ct); return Ok( - await userRenderer.RenderUserAsync( - user, - CurrentUser, - CurrentToken, - renderMembers: true, - renderAuthMethods: true, - renderSettings: true, - ct: ct - ) + await userRenderer.RenderUserAsync(user, CurrentUser, CurrentToken, true, true, ct: ct) ); } @@ -72,32 +65,32 @@ public class UsersController( if (req.Username != null && req.Username != user.Username) { - errors.Add(("username", validationService.ValidateUsername(req.Username))); + errors.Add(("username", ValidationUtils.ValidateUsername(req.Username))); user.Username = req.Username; } if (req.HasProperty(nameof(req.DisplayName))) { - errors.Add(("display_name", validationService.ValidateDisplayName(req.DisplayName))); + errors.Add(("display_name", ValidationUtils.ValidateDisplayName(req.DisplayName))); user.DisplayName = req.DisplayName; } if (req.HasProperty(nameof(req.Bio))) { - errors.Add(("bio", validationService.ValidateBio(req.Bio))); + errors.Add(("bio", ValidationUtils.ValidateBio(req.Bio))); user.Bio = req.Bio; } if (req.HasProperty(nameof(req.Links))) { - errors.AddRange(validationService.ValidateLinks(req.Links)); + errors.AddRange(ValidationUtils.ValidateLinks(req.Links)); user.Links = req.Links ?? []; } if (req.Names != null) { errors.AddRange( - validationService.ValidateFieldEntries( + ValidationUtils.ValidateFieldEntries( req.Names, CurrentUser!.CustomPreferences, "names" @@ -109,7 +102,7 @@ public class UsersController( if (req.Pronouns != null) { errors.AddRange( - validationService.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences) + ValidationUtils.ValidatePronouns(req.Pronouns, CurrentUser!.CustomPreferences) ); user.Pronouns = req.Pronouns.ToList(); } @@ -117,10 +110,7 @@ public class UsersController( if (req.Fields != null) { errors.AddRange( - validationService.ValidateFields( - req.Fields.ToList(), - CurrentUser!.CustomPreferences - ) + ValidationUtils.ValidateFields(req.Fields.ToList(), CurrentUser!.CustomPreferences) ); user.Fields = req.Fields.ToList(); } @@ -133,7 +123,7 @@ public class UsersController( } if (req.HasProperty(nameof(req.Avatar))) - errors.Add(("avatar", validationService.ValidateAvatar(req.Avatar))); + errors.Add(("avatar", ValidationUtils.ValidateAvatar(req.Avatar))); if (req.HasProperty(nameof(req.MemberTitle))) { @@ -143,9 +133,7 @@ public class UsersController( } else { - errors.Add( - ("member_title", validationService.ValidateDisplayName(req.MemberTitle)) - ); + errors.Add(("member_title", ValidationUtils.ValidateDisplayName(req.MemberTitle))); user.MemberTitle = req.MemberTitle; } } @@ -183,11 +171,11 @@ public class UsersController( // so it's in a separate block to the validation above. if (req.HasProperty(nameof(req.Avatar))) { - UserAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(CurrentUser!.Id, req.Avatar)); + queue.QueueInvocableWithPayload( + new AvatarUpdatePayload(CurrentUser!.Id, req.Avatar) + ); } - user.LastActive = clock.GetCurrentInstant(); - try { await db.SaveChangesAsync(ct); @@ -234,7 +222,7 @@ public class UsersController( .CustomPreferences.Where(x => req.Any(r => r.Id == x.Key)) .ToDictionary(); - foreach (CustomPreferenceUpdateRequest r in req) + foreach (CustomPreferenceUpdateRequest? r in req) { if (r.Id != null && preferences.ContainsKey(r.Id.Value)) { @@ -245,7 +233,6 @@ public class UsersController( Muted = r.Muted, Size = r.Size, Tooltip = r.Tooltip, - LegacyId = preferences[r.Id.Value].LegacyId, }; } else @@ -257,18 +244,25 @@ public class UsersController( Muted = r.Muted, Size = r.Size, Tooltip = r.Tooltip, - LegacyId = Guid.NewGuid(), }; } } user.CustomPreferences = preferences; - user.LastActive = clock.GetCurrentInstant(); await db.SaveChangesAsync(ct); return Ok(user.CustomPreferences); } + [HttpGet("@me/settings")] + [Authorize("user.read_hidden")] + [ProducesResponseType(statusCode: StatusCodes.Status200OK)] + public async Task GetUserSettingsAsync(CancellationToken ct = default) + { + User user = await db.Users.FirstAsync(u => u.Id == CurrentUser!.Id, ct); + return Ok(user.Settings); + } + [HttpPatch("@me/settings")] [Authorize("user.read_hidden", "user.update")] [ProducesResponseType(statusCode: StatusCodes.Status200OK)] @@ -281,10 +275,7 @@ public class UsersController( if (req.HasProperty(nameof(req.DarkMode))) user.Settings.DarkMode = req.DarkMode; - if (req.HasProperty(nameof(req.LastReadNotice))) - user.Settings.LastReadNotice = req.LastReadNotice; - user.LastActive = clock.GetCurrentInstant(); db.Update(user); await db.SaveChangesAsync(ct); diff --git a/Foxnouns.Backend/Controllers/V1/V1ReadController.cs b/Foxnouns.Backend/Controllers/V1/V1ReadController.cs deleted file mode 100644 index 327f03e..0000000 --- a/Foxnouns.Backend/Controllers/V1/V1ReadController.cs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto.V1; -using Foxnouns.Backend.Middleware; -using Foxnouns.Backend.Services.V1; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; - -namespace Foxnouns.Backend.Controllers.V1; - -[Route("/api/v1")] -public class V1ReadController( - UsersV1Service usersV1Service, - MembersV1Service membersV1Service, - DatabaseContext db -) : ApiControllerBase -{ - [HttpGet("users/@me")] - [Authorize("identify")] - public async Task GetMeAsync(CancellationToken ct = default) - { - User user = await usersV1Service.ResolveUserAsync("@me", CurrentToken, ct); - return Ok(await usersV1Service.RenderCurrentUserAsync(user, ct)); - } - - [HttpGet("users/{userRef}")] - public async Task GetUserAsync(string userRef, CancellationToken ct = default) - { - User user = await usersV1Service.ResolveUserAsync(userRef, CurrentToken, ct); - return Ok( - await usersV1Service.RenderUserAsync( - user, - CurrentToken, - renderMembers: true, - renderFlags: true, - ct: ct - ) - ); - } - - [HttpGet("members/{id}")] - public async Task GetMemberAsync(string id, CancellationToken ct = default) - { - Member member = await membersV1Service.ResolveMemberAsync(id, ct); - return Ok( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - renderFlags: true, - ct: ct - ) - ); - } - - [HttpGet("users/{userRef}/members")] - public async Task GetUserMembersAsync( - string userRef, - CancellationToken ct = default - ) - { - User user = await usersV1Service.ResolveUserAsync(userRef, CurrentToken, ct); - List members = await db - .Members.Where(m => m.UserId == user.Id) - .OrderBy(m => m.Name) - .ToListAsync(ct); - - List responses = []; - foreach (Member member in members) - { - responses.Add( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - user, - renderFlags: true, - ct: ct - ) - ); - } - - return Ok(responses); - } - - [HttpGet("users/{userRef}/members/{memberRef}")] - public async Task GetUserMemberAsync( - string userRef, - string memberRef, - CancellationToken ct = default - ) - { - Member member = await membersV1Service.ResolveMemberAsync( - userRef, - memberRef, - CurrentToken, - ct - ); - return Ok( - await membersV1Service.RenderMemberAsync( - member, - CurrentToken, - renderFlags: true, - ct: ct - ) - ); - } -} diff --git a/Foxnouns.Backend/Database/DatabaseContext.cs b/Foxnouns.Backend/Database/DatabaseContext.cs index 2bbcbc7..9baa143 100644 --- a/Foxnouns.Backend/Database/DatabaseContext.cs +++ b/Foxnouns.Backend/Database/DatabaseContext.cs @@ -64,6 +64,7 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options) public DbSet FediverseApplications { get; init; } = null!; public DbSet Tokens { get; init; } = null!; public DbSet Applications { get; init; } = null!; + public DbSet TemporaryKeys { get; init; } = null!; public DbSet DataExports { get; init; } = null!; public DbSet PrideFlags { get; init; } = null!; @@ -73,7 +74,6 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options) public DbSet Reports { get; init; } = null!; public DbSet AuditLog { get; init; } = null!; public DbSet Notifications { get; init; } = null!; - public DbSet Notices { get; init; } = null!; protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { @@ -87,6 +87,7 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options) modelBuilder.Entity().HasIndex(u => u.Sid).IsUnique(); modelBuilder.Entity().HasIndex(m => new { m.UserId, m.Name }).IsUnique(); modelBuilder.Entity().HasIndex(m => m.Sid).IsUnique(); + modelBuilder.Entity().HasIndex(k => k.Key).IsUnique(); modelBuilder.Entity().HasIndex(d => d.Filename).IsUnique(); // Two indexes on auth_methods, one for fediverse auth and one for all other types. @@ -107,12 +108,6 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options) .HasFilter("fediverse_application_id IS NULL") .IsUnique(); - modelBuilder - .Entity() - .HasOne(e => e.Report) - .WithOne(e => e.AuditLogEntry) - .OnDelete(DeleteBehavior.SetNull); - modelBuilder.Entity().Property(u => u.Sid).HasDefaultValueSql("find_free_user_sid()"); modelBuilder.Entity().Property(u => u.Fields).HasColumnType("jsonb"); modelBuilder.Entity().Property(u => u.Names).HasColumnType("jsonb"); @@ -138,26 +133,6 @@ public class DatabaseContext(DbContextOptions options) : DbContext(options) modelBuilder .HasDbFunction(typeof(DatabaseContext).GetMethod(nameof(FindFreeMemberSid))!) .HasName("find_free_member_sid"); - - // Indexes for legacy IDs for APIv1 - modelBuilder.Entity().HasIndex(u => u.LegacyId).IsUnique(); - modelBuilder.Entity().HasIndex(m => m.LegacyId).IsUnique(); - modelBuilder.Entity().HasIndex(f => f.LegacyId).IsUnique(); - - // a UUID is not an xid, but this should always be set by the application anyway. - // we're just setting it here to shut EFCore up because squashing migrations is for nerds - modelBuilder - .Entity() - .Property(u => u.LegacyId) - .HasDefaultValueSql("gen_random_uuid()"); - modelBuilder - .Entity() - .Property(m => m.LegacyId) - .HasDefaultValueSql("gen_random_uuid()"); - modelBuilder - .Entity() - .Property(f => f.LegacyId) - .HasDefaultValueSql("gen_random_uuid()"); } /// diff --git a/Foxnouns.Backend/Database/Migrations/20241217195351_AddFediAppForceRefresh.cs b/Foxnouns.Backend/Database/Migrations/20241217195351_AddFediAppForceRefresh.cs deleted file mode 100644 index 8340273..0000000 --- a/Foxnouns.Backend/Database/Migrations/20241217195351_AddFediAppForceRefresh.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - [DbContext(typeof(DatabaseContext))] - [Migration("20241217195351_AddFediAppForceRefresh")] - public partial class AddFediAppForceRefresh : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn>( - name: "localization_params", - table: "notifications", - type: "hstore", - nullable: false, - oldClrType: typeof(Dictionary), - oldType: "hstore", - oldNullable: true - ); - - migrationBuilder.AddColumn( - name: "force_refresh", - table: "fediverse_applications", - type: "boolean", - nullable: false, - defaultValue: false - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn(name: "force_refresh", table: "fediverse_applications"); - - migrationBuilder.AlterColumn>( - name: "localization_params", - table: "notifications", - type: "hstore", - nullable: true, - oldClrType: typeof(Dictionary), - oldType: "hstore" - ); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20241218195457_AddContextToReports.cs b/Foxnouns.Backend/Database/Migrations/20241218195457_AddContextToReports.cs deleted file mode 100644 index 3dc6029..0000000 --- a/Foxnouns.Backend/Database/Migrations/20241218195457_AddContextToReports.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - [DbContext(typeof(DatabaseContext))] - [Migration("20241218195457_AddContextToReports")] - public partial class AddContextToReports : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "context", - table: "reports", - type: "text", - nullable: true - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn(name: "context", table: "reports"); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20241218201855_MakeAuditLogReportsNullable.cs b/Foxnouns.Backend/Database/Migrations/20241218201855_MakeAuditLogReportsNullable.cs deleted file mode 100644 index 53a1f72..0000000 --- a/Foxnouns.Backend/Database/Migrations/20241218201855_MakeAuditLogReportsNullable.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - [DbContext(typeof(DatabaseContext))] - [Migration("20241218201855_MakeAuditLogReportsNullable")] - public partial class MakeAuditLogReportsNullable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "fk_audit_log_reports_report_id", - table: "audit_log" - ); - - migrationBuilder.DropIndex(name: "ix_audit_log_report_id", table: "audit_log"); - - migrationBuilder.CreateIndex( - name: "ix_audit_log_report_id", - table: "audit_log", - column: "report_id", - unique: true - ); - - migrationBuilder.AddForeignKey( - name: "fk_audit_log_reports_report_id", - table: "audit_log", - column: "report_id", - principalTable: "reports", - principalColumn: "id", - onDelete: ReferentialAction.SetNull - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "fk_audit_log_reports_report_id", - table: "audit_log" - ); - - migrationBuilder.DropIndex(name: "ix_audit_log_report_id", table: "audit_log"); - - migrationBuilder.CreateIndex( - name: "ix_audit_log_report_id", - table: "audit_log", - column: "report_id" - ); - - migrationBuilder.AddForeignKey( - name: "fk_audit_log_reports_report_id", - table: "audit_log", - column: "report_id", - principalTable: "reports", - principalColumn: "id" - ); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20241225155818_AddLegacyIds.cs b/Foxnouns.Backend/Database/Migrations/20241225155818_AddLegacyIds.cs deleted file mode 100644 index b8330cb..0000000 --- a/Foxnouns.Backend/Database/Migrations/20241225155818_AddLegacyIds.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - [DbContext(typeof(DatabaseContext))] - [Migration("20241225155818_AddLegacyIds")] - public partial class AddLegacyIds : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "legacy_id", - table: "users", - type: "text", - nullable: false, - defaultValueSql: "gen_random_uuid()" - ); - - migrationBuilder.AddColumn( - name: "legacy_id", - table: "pride_flags", - type: "text", - nullable: false, - defaultValueSql: "gen_random_uuid()" - ); - - migrationBuilder.AddColumn( - name: "legacy_id", - table: "members", - type: "text", - nullable: false, - defaultValueSql: "gen_random_uuid()" - ); - - migrationBuilder.CreateIndex( - name: "ix_users_legacy_id", - table: "users", - column: "legacy_id", - unique: true - ); - - migrationBuilder.CreateIndex( - name: "ix_pride_flags_legacy_id", - table: "pride_flags", - column: "legacy_id", - unique: true - ); - - migrationBuilder.CreateIndex( - name: "ix_members_legacy_id", - table: "members", - column: "legacy_id", - unique: true - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex(name: "ix_users_legacy_id", table: "users"); - - migrationBuilder.DropIndex(name: "ix_pride_flags_legacy_id", table: "pride_flags"); - - migrationBuilder.DropIndex(name: "ix_members_legacy_id", table: "members"); - - migrationBuilder.DropColumn(name: "legacy_id", table: "users"); - - migrationBuilder.DropColumn(name: "legacy_id", table: "pride_flags"); - - migrationBuilder.DropColumn(name: "legacy_id", table: "members"); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs b/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs deleted file mode 100644 index 27a8ada..0000000 --- a/Foxnouns.Backend/Database/Migrations/20250304155708_RemoveTemporaryKeys.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - [DbContext(typeof(DatabaseContext))] - [Migration("20250304155708_RemoveTemporaryKeys")] - public partial class RemoveTemporaryKeys : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable(name: "temporary_keys"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "temporary_keys", - columns: table => new - { - id = table - .Column(type: "bigint", nullable: false) - .Annotation( - "Npgsql:ValueGenerationStrategy", - NpgsqlValueGenerationStrategy.IdentityByDefaultColumn - ), - expires = table.Column( - type: "timestamp with time zone", - nullable: false - ), - key = table.Column(type: "text", nullable: false), - value = table.Column(type: "text", nullable: false), - }, - constraints: table => - { - table.PrimaryKey("pk_temporary_keys", x => x.id); - } - ); - - migrationBuilder.CreateIndex( - name: "ix_temporary_keys_key", - table: "temporary_keys", - column: "key", - unique: true - ); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs b/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs deleted file mode 100644 index d2df141..0000000 --- a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.Designer.cs +++ /dev/null @@ -1,915 +0,0 @@ -// -using System.Collections.Generic; -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20250329131053_AddNotices")] - partial class AddNotices - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.2") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Application", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_secret"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.PrimitiveCollection("RedirectUris") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("redirect_uris"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("scopes"); - - b.HasKey("Id") - .HasName("pk_applications"); - - b.ToTable("applications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.PrimitiveCollection("ClearedFields") - .HasColumnType("text[]") - .HasColumnName("cleared_fields"); - - b.Property("ModeratorId") - .HasColumnType("bigint") - .HasColumnName("moderator_id"); - - b.Property("ModeratorUsername") - .IsRequired() - .HasColumnType("text") - .HasColumnName("moderator_username"); - - b.Property("Reason") - .HasColumnType("text") - .HasColumnName("reason"); - - b.Property("ReportId") - .HasColumnType("bigint") - .HasColumnName("report_id"); - - b.Property("TargetMemberId") - .HasColumnType("bigint") - .HasColumnName("target_member_id"); - - b.Property("TargetMemberName") - .HasColumnType("text") - .HasColumnName("target_member_name"); - - b.Property("TargetUserId") - .HasColumnType("bigint") - .HasColumnName("target_user_id"); - - b.Property("TargetUsername") - .HasColumnType("text") - .HasColumnName("target_username"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.HasKey("Id") - .HasName("pk_audit_log"); - - b.HasIndex("ReportId") - .IsUnique() - .HasDatabaseName("ix_audit_log_report_id"); - - b.ToTable("audit_log", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AuthType") - .HasColumnType("integer") - .HasColumnName("auth_type"); - - b.Property("FediverseApplicationId") - .HasColumnType("bigint") - .HasColumnName("fediverse_application_id"); - - b.Property("RemoteId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("remote_id"); - - b.Property("RemoteUsername") - .HasColumnType("text") - .HasColumnName("remote_username"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_auth_methods"); - - b.HasIndex("FediverseApplicationId") - .HasDatabaseName("ix_auth_methods_fediverse_application_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_auth_methods_user_id"); - - b.HasIndex("AuthType", "RemoteId") - .IsUnique() - .HasDatabaseName("ix_auth_methods_auth_type_remote_id") - .HasFilter("fediverse_application_id IS NULL"); - - b.HasIndex("AuthType", "RemoteId", "FediverseApplicationId") - .IsUnique() - .HasDatabaseName("ix_auth_methods_auth_type_remote_id_fediverse_application_id") - .HasFilter("fediverse_application_id IS NOT NULL"); - - b.ToTable("auth_methods", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Filename") - .IsRequired() - .HasColumnType("text") - .HasColumnName("filename"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_data_exports"); - - b.HasIndex("Filename") - .IsUnique() - .HasDatabaseName("ix_data_exports_filename"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_data_exports_user_id"); - - b.ToTable("data_exports", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.FediverseApplication", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_secret"); - - b.Property("Domain") - .IsRequired() - .HasColumnType("text") - .HasColumnName("domain"); - - b.Property("ForceRefresh") - .HasColumnType("boolean") - .HasColumnName("force_refresh"); - - b.Property("InstanceType") - .HasColumnType("integer") - .HasColumnName("instance_type"); - - b.HasKey("Id") - .HasName("pk_fediverse_applications"); - - b.ToTable("fediverse_applications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Avatar") - .HasColumnType("text") - .HasColumnName("avatar"); - - b.Property("Bio") - .HasColumnType("text") - .HasColumnName("bio"); - - b.Property("DisplayName") - .HasColumnType("text") - .HasColumnName("display_name"); - - b.Property>("Fields") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("fields"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.PrimitiveCollection("Links") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("links"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.Property>("Names") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("names"); - - b.Property>("Pronouns") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("pronouns"); - - b.Property("Sid") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("sid") - .HasDefaultValueSql("find_free_member_sid()"); - - b.Property("Unlisted") - .HasColumnType("boolean") - .HasColumnName("unlisted"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_members"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_members_legacy_id"); - - b.HasIndex("Sid") - .IsUnique() - .HasDatabaseName("ix_members_sid"); - - b.HasIndex("UserId", "Name") - .IsUnique() - .HasDatabaseName("ix_members_user_id_name"); - - b.ToTable("members", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("MemberId") - .HasColumnType("bigint") - .HasColumnName("member_id"); - - b.Property("PrideFlagId") - .HasColumnType("bigint") - .HasColumnName("pride_flag_id"); - - b.HasKey("Id") - .HasName("pk_member_flags"); - - b.HasIndex("MemberId") - .HasDatabaseName("ix_member_flags_member_id"); - - b.HasIndex("PrideFlagId") - .HasDatabaseName("ix_member_flags_pride_flag_id"); - - b.ToTable("member_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AuthorId") - .HasColumnType("bigint") - .HasColumnName("author_id"); - - b.Property("EndTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_time"); - - b.Property("Message") - .IsRequired() - .HasColumnType("text") - .HasColumnName("message"); - - b.Property("StartTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_time"); - - b.HasKey("Id") - .HasName("pk_notices"); - - b.HasIndex("AuthorId") - .HasDatabaseName("ix_notices_author_id"); - - b.ToTable("notices", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AcknowledgedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("acknowledged_at"); - - b.Property("LocalizationKey") - .HasColumnType("text") - .HasColumnName("localization_key"); - - b.Property>("LocalizationParams") - .IsRequired() - .HasColumnType("hstore") - .HasColumnName("localization_params"); - - b.Property("Message") - .HasColumnType("text") - .HasColumnName("message"); - - b.Property("TargetId") - .HasColumnType("bigint") - .HasColumnName("target_id"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.HasKey("Id") - .HasName("pk_notifications"); - - b.HasIndex("TargetId") - .HasDatabaseName("ix_notifications_target_id"); - - b.ToTable("notifications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Description") - .HasColumnType("text") - .HasColumnName("description"); - - b.Property("Hash") - .HasColumnType("text") - .HasColumnName("hash"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_pride_flags"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_pride_flags_legacy_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_pride_flags_user_id"); - - b.ToTable("pride_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Context") - .HasColumnType("text") - .HasColumnName("context"); - - b.Property("Reason") - .HasColumnType("integer") - .HasColumnName("reason"); - - b.Property("ReporterId") - .HasColumnType("bigint") - .HasColumnName("reporter_id"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("TargetMemberId") - .HasColumnType("bigint") - .HasColumnName("target_member_id"); - - b.Property("TargetSnapshot") - .HasColumnType("text") - .HasColumnName("target_snapshot"); - - b.Property("TargetType") - .HasColumnType("integer") - .HasColumnName("target_type"); - - b.Property("TargetUserId") - .HasColumnType("bigint") - .HasColumnName("target_user_id"); - - b.HasKey("Id") - .HasName("pk_reports"); - - b.HasIndex("ReporterId") - .HasDatabaseName("ix_reports_reporter_id"); - - b.HasIndex("TargetMemberId") - .HasDatabaseName("ix_reports_target_member_id"); - - b.HasIndex("TargetUserId") - .HasDatabaseName("ix_reports_target_user_id"); - - b.ToTable("reports", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ApplicationId") - .HasColumnType("bigint") - .HasColumnName("application_id"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expires_at"); - - b.Property("Hash") - .IsRequired() - .HasColumnType("bytea") - .HasColumnName("hash"); - - b.Property("ManuallyExpired") - .HasColumnType("boolean") - .HasColumnName("manually_expired"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("scopes"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_tokens"); - - b.HasIndex("ApplicationId") - .HasDatabaseName("ix_tokens_application_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_tokens_user_id"); - - b.ToTable("tokens", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Avatar") - .HasColumnType("text") - .HasColumnName("avatar"); - - b.Property("Bio") - .HasColumnType("text") - .HasColumnName("bio"); - - b.Property>("CustomPreferences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("custom_preferences"); - - b.Property("Deleted") - .HasColumnType("boolean") - .HasColumnName("deleted"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeletedBy") - .HasColumnType("bigint") - .HasColumnName("deleted_by"); - - b.Property("DisplayName") - .HasColumnType("text") - .HasColumnName("display_name"); - - b.Property>("Fields") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("fields"); - - b.Property("LastActive") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_active"); - - b.Property("LastSidReroll") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_sid_reroll"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.PrimitiveCollection("Links") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("links"); - - b.Property("ListHidden") - .HasColumnType("boolean") - .HasColumnName("list_hidden"); - - b.Property("MemberTitle") - .HasColumnType("text") - .HasColumnName("member_title"); - - b.Property>("Names") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("names"); - - b.Property("Password") - .HasColumnType("text") - .HasColumnName("password"); - - b.Property>("Pronouns") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("pronouns"); - - b.Property("Role") - .HasColumnType("integer") - .HasColumnName("role"); - - b.Property("Settings") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("settings"); - - b.Property("Sid") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("sid") - .HasDefaultValueSql("find_free_user_sid()"); - - b.Property("Timezone") - .HasColumnType("text") - .HasColumnName("timezone"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text") - .HasColumnName("username"); - - b.HasKey("Id") - .HasName("pk_users"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_users_legacy_id"); - - b.HasIndex("Sid") - .IsUnique() - .HasDatabaseName("ix_users_sid"); - - b.HasIndex("Username") - .IsUnique() - .HasDatabaseName("ix_users_username"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("PrideFlagId") - .HasColumnType("bigint") - .HasColumnName("pride_flag_id"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_user_flags"); - - b.HasIndex("PrideFlagId") - .HasDatabaseName("ix_user_flags_pride_flag_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_user_flags_user_id"); - - b.ToTable("user_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Report", "Report") - .WithOne("AuditLogEntry") - .HasForeignKey("Foxnouns.Backend.Database.Models.AuditLogEntry", "ReportId") - .OnDelete(DeleteBehavior.SetNull) - .HasConstraintName("fk_audit_log_reports_report_id"); - - b.Navigation("Report"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.FediverseApplication", "FediverseApplication") - .WithMany() - .HasForeignKey("FediverseApplicationId") - .HasConstraintName("fk_auth_methods_fediverse_applications_fediverse_application_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("AuthMethods") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_methods_users_user_id"); - - b.Navigation("FediverseApplication"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("DataExports") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_data_exports_users_user_id"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("Members") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_members_users_user_id"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Member", null) - .WithMany("ProfileFlags") - .HasForeignKey("MemberId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_member_flags_members_member_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag") - .WithMany() - .HasForeignKey("PrideFlagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_member_flags_pride_flags_pride_flag_id"); - - b.Navigation("PrideFlag"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Author") - .WithMany() - .HasForeignKey("AuthorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notices_users_author_id"); - - b.Navigation("Author"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Target") - .WithMany() - .HasForeignKey("TargetId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notifications_users_target_id"); - - b.Navigation("Target"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", null) - .WithMany("Flags") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_pride_flags_users_user_id"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Reporter") - .WithMany() - .HasForeignKey("ReporterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_reports_users_reporter_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.Member", "TargetMember") - .WithMany() - .HasForeignKey("TargetMemberId") - .HasConstraintName("fk_reports_members_target_member_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "TargetUser") - .WithMany() - .HasForeignKey("TargetUserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_reports_users_target_user_id"); - - b.Navigation("Reporter"); - - b.Navigation("TargetMember"); - - b.Navigation("TargetUser"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Application", "Application") - .WithMany() - .HasForeignKey("ApplicationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_tokens_applications_application_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_tokens_users_user_id"); - - b.Navigation("Application"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag") - .WithMany() - .HasForeignKey("PrideFlagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_flags_pride_flags_pride_flag_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", null) - .WithMany("ProfileFlags") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_flags_users_user_id"); - - b.Navigation("PrideFlag"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.Navigation("ProfileFlags"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.Navigation("AuditLogEntry"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b => - { - b.Navigation("AuthMethods"); - - b.Navigation("DataExports"); - - b.Navigation("Flags"); - - b.Navigation("Members"); - - b.Navigation("ProfileFlags"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs b/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs deleted file mode 100644 index 24c5166..0000000 --- a/Foxnouns.Backend/Database/Migrations/20250329131053_AddNotices.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using NodaTime; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - public partial class AddNotices : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "notices", - columns: table => new - { - id = table.Column(type: "bigint", nullable: false), - message = table.Column(type: "text", nullable: false), - start_time = table.Column( - type: "timestamp with time zone", - nullable: false - ), - end_time = table.Column( - type: "timestamp with time zone", - nullable: false - ), - author_id = table.Column(type: "bigint", nullable: false), - }, - constraints: table => - { - table.PrimaryKey("pk_notices", x => x.id); - table.ForeignKey( - name: "fk_notices_users_author_id", - column: x => x.author_id, - principalTable: "users", - principalColumn: "id", - onDelete: ReferentialAction.Cascade - ); - } - ); - - migrationBuilder.CreateIndex( - name: "ix_notices_author_id", - table: "notices", - column: "author_id" - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable(name: "notices"); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs b/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs deleted file mode 100644 index cb9377d..0000000 --- a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.Designer.cs +++ /dev/null @@ -1,923 +0,0 @@ -// -using System.Collections.Generic; -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20250410192220_AddAvatarMigrations")] - partial class AddAvatarMigrations - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.2") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Application", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_secret"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.PrimitiveCollection("RedirectUris") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("redirect_uris"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("scopes"); - - b.HasKey("Id") - .HasName("pk_applications"); - - b.ToTable("applications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.PrimitiveCollection("ClearedFields") - .HasColumnType("text[]") - .HasColumnName("cleared_fields"); - - b.Property("ModeratorId") - .HasColumnType("bigint") - .HasColumnName("moderator_id"); - - b.Property("ModeratorUsername") - .IsRequired() - .HasColumnType("text") - .HasColumnName("moderator_username"); - - b.Property("Reason") - .HasColumnType("text") - .HasColumnName("reason"); - - b.Property("ReportId") - .HasColumnType("bigint") - .HasColumnName("report_id"); - - b.Property("TargetMemberId") - .HasColumnType("bigint") - .HasColumnName("target_member_id"); - - b.Property("TargetMemberName") - .HasColumnType("text") - .HasColumnName("target_member_name"); - - b.Property("TargetUserId") - .HasColumnType("bigint") - .HasColumnName("target_user_id"); - - b.Property("TargetUsername") - .HasColumnType("text") - .HasColumnName("target_username"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.HasKey("Id") - .HasName("pk_audit_log"); - - b.HasIndex("ReportId") - .IsUnique() - .HasDatabaseName("ix_audit_log_report_id"); - - b.ToTable("audit_log", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AuthType") - .HasColumnType("integer") - .HasColumnName("auth_type"); - - b.Property("FediverseApplicationId") - .HasColumnType("bigint") - .HasColumnName("fediverse_application_id"); - - b.Property("RemoteId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("remote_id"); - - b.Property("RemoteUsername") - .HasColumnType("text") - .HasColumnName("remote_username"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_auth_methods"); - - b.HasIndex("FediverseApplicationId") - .HasDatabaseName("ix_auth_methods_fediverse_application_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_auth_methods_user_id"); - - b.HasIndex("AuthType", "RemoteId") - .IsUnique() - .HasDatabaseName("ix_auth_methods_auth_type_remote_id") - .HasFilter("fediverse_application_id IS NULL"); - - b.HasIndex("AuthType", "RemoteId", "FediverseApplicationId") - .IsUnique() - .HasDatabaseName("ix_auth_methods_auth_type_remote_id_fediverse_application_id") - .HasFilter("fediverse_application_id IS NOT NULL"); - - b.ToTable("auth_methods", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Filename") - .IsRequired() - .HasColumnType("text") - .HasColumnName("filename"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_data_exports"); - - b.HasIndex("Filename") - .IsUnique() - .HasDatabaseName("ix_data_exports_filename"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_data_exports_user_id"); - - b.ToTable("data_exports", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.FediverseApplication", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_id"); - - b.Property("ClientSecret") - .IsRequired() - .HasColumnType("text") - .HasColumnName("client_secret"); - - b.Property("Domain") - .IsRequired() - .HasColumnType("text") - .HasColumnName("domain"); - - b.Property("ForceRefresh") - .HasColumnType("boolean") - .HasColumnName("force_refresh"); - - b.Property("InstanceType") - .HasColumnType("integer") - .HasColumnName("instance_type"); - - b.HasKey("Id") - .HasName("pk_fediverse_applications"); - - b.ToTable("fediverse_applications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Avatar") - .HasColumnType("text") - .HasColumnName("avatar"); - - b.Property("AvatarMigrated") - .HasColumnType("boolean") - .HasColumnName("avatar_migrated"); - - b.Property("Bio") - .HasColumnType("text") - .HasColumnName("bio"); - - b.Property("DisplayName") - .HasColumnType("text") - .HasColumnName("display_name"); - - b.Property>("Fields") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("fields"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.PrimitiveCollection("Links") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("links"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.Property>("Names") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("names"); - - b.Property>("Pronouns") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("pronouns"); - - b.Property("Sid") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("sid") - .HasDefaultValueSql("find_free_member_sid()"); - - b.Property("Unlisted") - .HasColumnType("boolean") - .HasColumnName("unlisted"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_members"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_members_legacy_id"); - - b.HasIndex("Sid") - .IsUnique() - .HasDatabaseName("ix_members_sid"); - - b.HasIndex("UserId", "Name") - .IsUnique() - .HasDatabaseName("ix_members_user_id_name"); - - b.ToTable("members", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("MemberId") - .HasColumnType("bigint") - .HasColumnName("member_id"); - - b.Property("PrideFlagId") - .HasColumnType("bigint") - .HasColumnName("pride_flag_id"); - - b.HasKey("Id") - .HasName("pk_member_flags"); - - b.HasIndex("MemberId") - .HasDatabaseName("ix_member_flags_member_id"); - - b.HasIndex("PrideFlagId") - .HasDatabaseName("ix_member_flags_pride_flag_id"); - - b.ToTable("member_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AuthorId") - .HasColumnType("bigint") - .HasColumnName("author_id"); - - b.Property("EndTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_time"); - - b.Property("Message") - .IsRequired() - .HasColumnType("text") - .HasColumnName("message"); - - b.Property("StartTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_time"); - - b.HasKey("Id") - .HasName("pk_notices"); - - b.HasIndex("AuthorId") - .HasDatabaseName("ix_notices_author_id"); - - b.ToTable("notices", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AcknowledgedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("acknowledged_at"); - - b.Property("LocalizationKey") - .HasColumnType("text") - .HasColumnName("localization_key"); - - b.Property>("LocalizationParams") - .IsRequired() - .HasColumnType("hstore") - .HasColumnName("localization_params"); - - b.Property("Message") - .HasColumnType("text") - .HasColumnName("message"); - - b.Property("TargetId") - .HasColumnType("bigint") - .HasColumnName("target_id"); - - b.Property("Type") - .HasColumnType("integer") - .HasColumnName("type"); - - b.HasKey("Id") - .HasName("pk_notifications"); - - b.HasIndex("TargetId") - .HasDatabaseName("ix_notifications_target_id"); - - b.ToTable("notifications", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Description") - .HasColumnType("text") - .HasColumnName("description"); - - b.Property("Hash") - .HasColumnType("text") - .HasColumnName("hash"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text") - .HasColumnName("name"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_pride_flags"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_pride_flags_legacy_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_pride_flags_user_id"); - - b.ToTable("pride_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Context") - .HasColumnType("text") - .HasColumnName("context"); - - b.Property("Reason") - .HasColumnType("integer") - .HasColumnName("reason"); - - b.Property("ReporterId") - .HasColumnType("bigint") - .HasColumnName("reporter_id"); - - b.Property("Status") - .HasColumnType("integer") - .HasColumnName("status"); - - b.Property("TargetMemberId") - .HasColumnType("bigint") - .HasColumnName("target_member_id"); - - b.Property("TargetSnapshot") - .HasColumnType("text") - .HasColumnName("target_snapshot"); - - b.Property("TargetType") - .HasColumnType("integer") - .HasColumnName("target_type"); - - b.Property("TargetUserId") - .HasColumnType("bigint") - .HasColumnName("target_user_id"); - - b.HasKey("Id") - .HasName("pk_reports"); - - b.HasIndex("ReporterId") - .HasDatabaseName("ix_reports_reporter_id"); - - b.HasIndex("TargetMemberId") - .HasDatabaseName("ix_reports_target_member_id"); - - b.HasIndex("TargetUserId") - .HasDatabaseName("ix_reports_target_user_id"); - - b.ToTable("reports", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("ApplicationId") - .HasColumnType("bigint") - .HasColumnName("application_id"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expires_at"); - - b.Property("Hash") - .IsRequired() - .HasColumnType("bytea") - .HasColumnName("hash"); - - b.Property("ManuallyExpired") - .HasColumnType("boolean") - .HasColumnName("manually_expired"); - - b.PrimitiveCollection("Scopes") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("scopes"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_tokens"); - - b.HasIndex("ApplicationId") - .HasDatabaseName("ix_tokens_application_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_tokens_user_id"); - - b.ToTable("tokens", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("Avatar") - .HasColumnType("text") - .HasColumnName("avatar"); - - b.Property("AvatarMigrated") - .HasColumnType("boolean") - .HasColumnName("avatar_migrated"); - - b.Property("Bio") - .HasColumnType("text") - .HasColumnName("bio"); - - b.Property>("CustomPreferences") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("custom_preferences"); - - b.Property("Deleted") - .HasColumnType("boolean") - .HasColumnName("deleted"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("DeletedBy") - .HasColumnType("bigint") - .HasColumnName("deleted_by"); - - b.Property("DisplayName") - .HasColumnType("text") - .HasColumnName("display_name"); - - b.Property>("Fields") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("fields"); - - b.Property("LastActive") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_active"); - - b.Property("LastSidReroll") - .HasColumnType("timestamp with time zone") - .HasColumnName("last_sid_reroll"); - - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - - b.PrimitiveCollection("Links") - .IsRequired() - .HasColumnType("text[]") - .HasColumnName("links"); - - b.Property("ListHidden") - .HasColumnType("boolean") - .HasColumnName("list_hidden"); - - b.Property("MemberTitle") - .HasColumnType("text") - .HasColumnName("member_title"); - - b.Property>("Names") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("names"); - - b.Property("Password") - .HasColumnType("text") - .HasColumnName("password"); - - b.Property>("Pronouns") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("pronouns"); - - b.Property("Role") - .HasColumnType("integer") - .HasColumnName("role"); - - b.Property("Settings") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("settings"); - - b.Property("Sid") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("sid") - .HasDefaultValueSql("find_free_user_sid()"); - - b.Property("Timezone") - .HasColumnType("text") - .HasColumnName("timezone"); - - b.Property("Username") - .IsRequired() - .HasColumnType("text") - .HasColumnName("username"); - - b.HasKey("Id") - .HasName("pk_users"); - - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_users_legacy_id"); - - b.HasIndex("Sid") - .IsUnique() - .HasDatabaseName("ix_users_sid"); - - b.HasIndex("Username") - .IsUnique() - .HasDatabaseName("ix_users_username"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("PrideFlagId") - .HasColumnType("bigint") - .HasColumnName("pride_flag_id"); - - b.Property("UserId") - .HasColumnType("bigint") - .HasColumnName("user_id"); - - b.HasKey("Id") - .HasName("pk_user_flags"); - - b.HasIndex("PrideFlagId") - .HasDatabaseName("ix_user_flags_pride_flag_id"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_user_flags_user_id"); - - b.ToTable("user_flags", (string)null); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Report", "Report") - .WithOne("AuditLogEntry") - .HasForeignKey("Foxnouns.Backend.Database.Models.AuditLogEntry", "ReportId") - .OnDelete(DeleteBehavior.SetNull) - .HasConstraintName("fk_audit_log_reports_report_id"); - - b.Navigation("Report"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuthMethod", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.FediverseApplication", "FediverseApplication") - .WithMany() - .HasForeignKey("FediverseApplicationId") - .HasConstraintName("fk_auth_methods_fediverse_applications_fediverse_application_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("AuthMethods") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_auth_methods_users_user_id"); - - b.Navigation("FediverseApplication"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.DataExport", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("DataExports") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_data_exports_users_user_id"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany("Members") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_members_users_user_id"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.MemberFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Member", null) - .WithMany("ProfileFlags") - .HasForeignKey("MemberId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_member_flags_members_member_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag") - .WithMany() - .HasForeignKey("PrideFlagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_member_flags_pride_flags_pride_flag_id"); - - b.Navigation("PrideFlag"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Author") - .WithMany() - .HasForeignKey("AuthorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notices_users_author_id"); - - b.Navigation("Author"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Target") - .WithMany() - .HasForeignKey("TargetId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notifications_users_target_id"); - - b.Navigation("Target"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.PrideFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", null) - .WithMany("Flags") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_pride_flags_users_user_id"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Reporter") - .WithMany() - .HasForeignKey("ReporterId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_reports_users_reporter_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.Member", "TargetMember") - .WithMany() - .HasForeignKey("TargetMemberId") - .HasConstraintName("fk_reports_members_target_member_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "TargetUser") - .WithMany() - .HasForeignKey("TargetUserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_reports_users_target_user_id"); - - b.Navigation("Reporter"); - - b.Navigation("TargetMember"); - - b.Navigation("TargetUser"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.Application", "Application") - .WithMany() - .HasForeignKey("ApplicationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_tokens_applications_application_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_tokens_users_user_id"); - - b.Navigation("Application"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.UserFlag", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.PrideFlag", "PrideFlag") - .WithMany() - .HasForeignKey("PrideFlagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_flags_pride_flags_pride_flag_id"); - - b.HasOne("Foxnouns.Backend.Database.Models.User", null) - .WithMany("ProfileFlags") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_user_flags_users_user_id"); - - b.Navigation("PrideFlag"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Member", b => - { - b.Navigation("ProfileFlags"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.Navigation("AuditLogEntry"); - }); - - modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b => - { - b.Navigation("AuthMethods"); - - b.Navigation("DataExports"); - - b.Navigation("Flags"); - - b.Navigation("Members"); - - b.Navigation("ProfileFlags"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.cs b/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.cs deleted file mode 100644 index ca88605..0000000 --- a/Foxnouns.Backend/Database/Migrations/20250410192220_AddAvatarMigrations.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Foxnouns.Backend.Database.Migrations -{ - /// - public partial class AddAvatarMigrations : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "avatar_migrated", - table: "users", - type: "boolean", - nullable: false, - defaultValue: false - ); - - migrationBuilder.AddColumn( - name: "avatar_migrated", - table: "members", - type: "boolean", - nullable: false, - defaultValue: false - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn(name: "avatar_migrated", table: "users"); - - migrationBuilder.DropColumn(name: "avatar_migrated", table: "members"); - } - } -} diff --git a/Foxnouns.Backend/Database/Migrations/DatabaseContextModelSnapshot.cs b/Foxnouns.Backend/Database/Migrations/DatabaseContextModelSnapshot.cs index 92db9f9..83a90fd 100644 --- a/Foxnouns.Backend/Database/Migrations/DatabaseContextModelSnapshot.cs +++ b/Foxnouns.Backend/Database/Migrations/DatabaseContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace Foxnouns.Backend.Database.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.2") + .HasAnnotation("ProductVersion", "9.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "hstore"); @@ -113,7 +113,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasName("pk_audit_log"); b.HasIndex("ReportId") - .IsUnique() .HasDatabaseName("ix_audit_log_report_id"); b.ToTable("audit_log", (string)null); @@ -217,10 +216,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("text") .HasColumnName("domain"); - b.Property("ForceRefresh") - .HasColumnType("boolean") - .HasColumnName("force_refresh"); - b.Property("InstanceType") .HasColumnType("integer") .HasColumnName("instance_type"); @@ -241,10 +236,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("text") .HasColumnName("avatar"); - b.Property("AvatarMigrated") - .HasColumnType("boolean") - .HasColumnName("avatar_migrated"); - b.Property("Bio") .HasColumnType("text") .HasColumnName("bio"); @@ -258,13 +249,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("jsonb") .HasColumnName("fields"); - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - b.PrimitiveCollection("Links") .IsRequired() .HasColumnType("text[]") @@ -303,10 +287,6 @@ namespace Foxnouns.Backend.Database.Migrations b.HasKey("Id") .HasName("pk_members"); - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_members_legacy_id"); - b.HasIndex("Sid") .IsUnique() .HasDatabaseName("ix_members_sid"); @@ -347,38 +327,6 @@ namespace Foxnouns.Backend.Database.Migrations b.ToTable("member_flags", (string)null); }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.Property("Id") - .HasColumnType("bigint") - .HasColumnName("id"); - - b.Property("AuthorId") - .HasColumnType("bigint") - .HasColumnName("author_id"); - - b.Property("EndTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("end_time"); - - b.Property("Message") - .IsRequired() - .HasColumnType("text") - .HasColumnName("message"); - - b.Property("StartTime") - .HasColumnType("timestamp with time zone") - .HasColumnName("start_time"); - - b.HasKey("Id") - .HasName("pk_notices"); - - b.HasIndex("AuthorId") - .HasDatabaseName("ix_notices_author_id"); - - b.ToTable("notices", (string)null); - }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => { b.Property("Id") @@ -394,7 +342,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnName("localization_key"); b.Property>("LocalizationParams") - .IsRequired() .HasColumnType("hstore") .HasColumnName("localization_params"); @@ -433,13 +380,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("text") .HasColumnName("hash"); - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - b.Property("Name") .IsRequired() .HasColumnType("text") @@ -452,10 +392,6 @@ namespace Foxnouns.Backend.Database.Migrations b.HasKey("Id") .HasName("pk_pride_flags"); - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_pride_flags_legacy_id"); - b.HasIndex("UserId") .HasDatabaseName("ix_pride_flags_user_id"); @@ -468,10 +404,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("bigint") .HasColumnName("id"); - b.Property("Context") - .HasColumnType("text") - .HasColumnName("context"); - b.Property("Reason") .HasColumnType("integer") .HasColumnName("reason"); @@ -479,7 +411,7 @@ namespace Foxnouns.Backend.Database.Migrations b.Property("ReporterId") .HasColumnType("bigint") .HasColumnName("reporter_id"); - + b.Property("Status") .HasColumnType("integer") .HasColumnName("status"); @@ -515,6 +447,39 @@ namespace Foxnouns.Backend.Database.Migrations b.ToTable("reports", (string)null); }); + modelBuilder.Entity("Foxnouns.Backend.Database.Models.TemporaryKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Expires") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text") + .HasColumnName("key"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text") + .HasColumnName("value"); + + b.HasKey("Id") + .HasName("pk_temporary_keys"); + + b.HasIndex("Key") + .IsUnique() + .HasDatabaseName("ix_temporary_keys_key"); + + b.ToTable("temporary_keys", (string)null); + }); + modelBuilder.Entity("Foxnouns.Backend.Database.Models.Token", b => { b.Property("Id") @@ -569,10 +534,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("text") .HasColumnName("avatar"); - b.Property("AvatarMigrated") - .HasColumnType("boolean") - .HasColumnName("avatar_migrated"); - b.Property("Bio") .HasColumnType("text") .HasColumnName("bio"); @@ -611,13 +572,6 @@ namespace Foxnouns.Backend.Database.Migrations .HasColumnType("timestamp with time zone") .HasColumnName("last_sid_reroll"); - b.Property("LegacyId") - .IsRequired() - .ValueGeneratedOnAdd() - .HasColumnType("text") - .HasColumnName("legacy_id") - .HasDefaultValueSql("gen_random_uuid()"); - b.PrimitiveCollection("Links") .IsRequired() .HasColumnType("text[]") @@ -673,10 +627,6 @@ namespace Foxnouns.Backend.Database.Migrations b.HasKey("Id") .HasName("pk_users"); - b.HasIndex("LegacyId") - .IsUnique() - .HasDatabaseName("ix_users_legacy_id"); - b.HasIndex("Sid") .IsUnique() .HasDatabaseName("ix_users_sid"); @@ -720,9 +670,8 @@ namespace Foxnouns.Backend.Database.Migrations modelBuilder.Entity("Foxnouns.Backend.Database.Models.AuditLogEntry", b => { b.HasOne("Foxnouns.Backend.Database.Models.Report", "Report") - .WithOne("AuditLogEntry") - .HasForeignKey("Foxnouns.Backend.Database.Models.AuditLogEntry", "ReportId") - .OnDelete(DeleteBehavior.SetNull) + .WithMany() + .HasForeignKey("ReportId") .HasConstraintName("fk_audit_log_reports_report_id"); b.Navigation("Report"); @@ -790,18 +739,6 @@ namespace Foxnouns.Backend.Database.Migrations b.Navigation("PrideFlag"); }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notice", b => - { - b.HasOne("Foxnouns.Backend.Database.Models.User", "Author") - .WithMany() - .HasForeignKey("AuthorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_notices_users_author_id"); - - b.Navigation("Author"); - }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Notification", b => { b.HasOne("Foxnouns.Backend.Database.Models.User", "Target") @@ -897,11 +834,6 @@ namespace Foxnouns.Backend.Database.Migrations b.Navigation("ProfileFlags"); }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.Report", b => - { - b.Navigation("AuditLogEntry"); - }); - modelBuilder.Entity("Foxnouns.Backend.Database.Models.User", b => { b.Navigation("AuthMethods"); diff --git a/Foxnouns.Backend/Database/Models/AuditLogEntry.cs b/Foxnouns.Backend/Database/Models/AuditLogEntry.cs index 84e1a43..a4983ae 100644 --- a/Foxnouns.Backend/Database/Models/AuditLogEntry.cs +++ b/Foxnouns.Backend/Database/Models/AuditLogEntry.cs @@ -12,7 +12,6 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -using System.ComponentModel.DataAnnotations.Schema; using Foxnouns.Backend.Utils; using Newtonsoft.Json; @@ -41,5 +40,4 @@ public enum AuditLogEntryType WarnUser, WarnUserAndClearProfile, SuspendUser, - QuerySensitiveUserData, } diff --git a/Foxnouns.Backend/Database/Models/FediverseApplication.cs b/Foxnouns.Backend/Database/Models/FediverseApplication.cs index 9c61937..13e1318 100644 --- a/Foxnouns.Backend/Database/Models/FediverseApplication.cs +++ b/Foxnouns.Backend/Database/Models/FediverseApplication.cs @@ -20,7 +20,6 @@ public class FediverseApplication : BaseModel public required string ClientId { get; set; } public required string ClientSecret { get; set; } public required FediverseInstanceType InstanceType { get; set; } - public bool ForceRefresh { get; set; } } public enum FediverseInstanceType diff --git a/Foxnouns.Backend/Database/Models/Member.cs b/Foxnouns.Backend/Database/Models/Member.cs index 85b39f3..b9793e0 100644 --- a/Foxnouns.Backend/Database/Models/Member.cs +++ b/Foxnouns.Backend/Database/Models/Member.cs @@ -18,7 +18,6 @@ public class Member : BaseModel { public required string Name { get; set; } public string Sid { get; set; } = string.Empty; - public required string LegacyId { get; init; } public string? DisplayName { get; set; } public string? Bio { get; set; } public string? Avatar { get; set; } @@ -29,9 +28,6 @@ public class Member : BaseModel public List Pronouns { get; set; } = []; public List Fields { get; set; } = []; - // Only used by avatar-proxy and avatar-migration. - public bool AvatarMigrated { get; set; } = true; - public List ProfileFlags { get; set; } = []; public Snowflake UserId { get; init; } diff --git a/Foxnouns.Backend/Database/Models/Notice.cs b/Foxnouns.Backend/Database/Models/Notice.cs deleted file mode 100644 index c3e6f0d..0000000 --- a/Foxnouns.Backend/Database/Models/Notice.cs +++ /dev/null @@ -1,13 +0,0 @@ -using NodaTime; - -namespace Foxnouns.Backend.Database.Models; - -public class Notice : BaseModel -{ - public required string Message { get; set; } - public required Instant StartTime { get; set; } - public required Instant EndTime { get; set; } - - public Snowflake AuthorId { get; init; } - public User Author { get; init; } = null!; -} diff --git a/Foxnouns.Backend/Database/Models/PrideFlag.cs b/Foxnouns.Backend/Database/Models/PrideFlag.cs index 0c04ab5..f103610 100644 --- a/Foxnouns.Backend/Database/Models/PrideFlag.cs +++ b/Foxnouns.Backend/Database/Models/PrideFlag.cs @@ -17,7 +17,6 @@ namespace Foxnouns.Backend.Database.Models; public class PrideFlag : BaseModel { public required Snowflake UserId { get; init; } - public required string LegacyId { get; init; } // A null hash means the flag hasn't been processed yet. public string? Hash { get; set; } diff --git a/Foxnouns.Backend/Database/Models/Report.cs b/Foxnouns.Backend/Database/Models/Report.cs index 47b994f..e668f44 100644 --- a/Foxnouns.Backend/Database/Models/Report.cs +++ b/Foxnouns.Backend/Database/Models/Report.cs @@ -29,12 +29,9 @@ public class Report : BaseModel public ReportStatus Status { get; set; } public ReportReason Reason { get; init; } - public string? Context { get; init; } public ReportTargetType TargetType { get; init; } public string? TargetSnapshot { get; init; } - - public AuditLogEntry? AuditLogEntry { get; set; } } [JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] diff --git a/Foxnouns.Backend/Services/V1/V1Utils.cs b/Foxnouns.Backend/Database/Models/TemporaryKey.cs similarity index 58% rename from Foxnouns.Backend/Services/V1/V1Utils.cs rename to Foxnouns.Backend/Database/Models/TemporaryKey.cs index 2e52316..f83e515 100644 --- a/Foxnouns.Backend/Services/V1/V1Utils.cs +++ b/Foxnouns.Backend/Database/Models/TemporaryKey.cs @@ -12,23 +12,14 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; +using NodaTime; -namespace Foxnouns.Backend.Services.V1; +namespace Foxnouns.Backend.Database.Models; -public static class V1Utils +public class TemporaryKey { - public static string TranslateStatus( - string status, - Dictionary customPreferences - ) - { - if (!Snowflake.TryParse(status, out Snowflake? sf)) - return status; - - return customPreferences.TryGetValue(sf.Value, out User.CustomPreference? cf) - ? cf.LegacyId.ToString() - : "unknown"; - } + public long Id { get; init; } + public required string Key { get; init; } + public required string Value { get; set; } + public Instant Expires { get; init; } } diff --git a/Foxnouns.Backend/Database/Models/User.cs b/Foxnouns.Backend/Database/Models/User.cs index fe97b6c..12df0ae 100644 --- a/Foxnouns.Backend/Database/Models/User.cs +++ b/Foxnouns.Backend/Database/Models/User.cs @@ -25,7 +25,6 @@ public class User : BaseModel { public required string Username { get; set; } public string Sid { get; set; } = string.Empty; - public required string LegacyId { get; init; } public string? DisplayName { get; set; } public string? Bio { get; set; } public string? MemberTitle { get; set; } @@ -57,9 +56,6 @@ public class User : BaseModel public Instant? DeletedAt { get; set; } public Snowflake? DeletedBy { get; set; } - // Only used by avatar-proxy and avatar-migration. - public bool AvatarMigrated { get; set; } = true; - [NotMapped] public bool? SelfDelete => Deleted ? DeletedBy != null : null; @@ -73,8 +69,6 @@ public class User : BaseModel // This type is generally serialized directly, so the converter is applied here. [JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] public PreferenceSize Size { get; set; } - - public Guid LegacyId { get; init; } = Guid.NewGuid(); } public static readonly Duration DeleteAfter = Duration.FromDays(30); @@ -98,5 +92,4 @@ public enum PreferenceSize public class UserSettings { public bool? DarkMode { get; set; } - public Snowflake? LastReadNotice { get; set; } } diff --git a/Foxnouns.Backend/Database/Snowflake.cs b/Foxnouns.Backend/Database/Snowflake.cs index a0f127a..fc2188d 100644 --- a/Foxnouns.Backend/Database/Snowflake.cs +++ b/Foxnouns.Backend/Database/Snowflake.cs @@ -113,30 +113,24 @@ public readonly struct Snowflake(ulong value) : IEquatable ) => writer.WriteStringValue(value.Value.ToString()); } - private class JsonConverter : JsonConverter + private class JsonConverter : JsonConverter { public override void WriteJson( JsonWriter writer, - Snowflake? value, + Snowflake value, JsonSerializer serializer ) { - if (value != null) - writer.WriteValue(value.Value.ToString()); - else - writer.WriteNull(); + writer.WriteValue(value.Value.ToString()); } - public override Snowflake? ReadJson( + public override Snowflake ReadJson( JsonReader reader, Type objectType, - Snowflake? existingValue, + Snowflake existingValue, bool hasExistingValue, JsonSerializer serializer - ) => - reader.TokenType is not (JsonToken.None or JsonToken.Null) - ? ulong.Parse((string)reader.Value!) - : null; + ) => ulong.Parse((string)reader.Value!); } private class TypeConverter : System.ComponentModel.TypeConverter diff --git a/Foxnouns.Backend/Dto/Meta.cs b/Foxnouns.Backend/Dto/Meta.cs index 168327a..0ff6e80 100644 --- a/Foxnouns.Backend/Dto/Meta.cs +++ b/Foxnouns.Backend/Dto/Meta.cs @@ -14,8 +14,6 @@ // along with this program. If not, see . // ReSharper disable NotAccessedPositionalProperty.Global -using Foxnouns.Backend.Database; - namespace Foxnouns.Backend.Dto; public record MetaResponse( @@ -24,12 +22,9 @@ public record MetaResponse( string Hash, int Members, UserInfoResponse Users, - LimitsResponse Limits, - MetaNoticeResponse? Notice + LimitsResponse Limits ); -public record MetaNoticeResponse(Snowflake Id, string Message); - public record UserInfoResponse(int Total, int ActiveMonth, int ActiveWeek, int ActiveDay); public record LimitsResponse( diff --git a/Foxnouns.Backend/Dto/Moderation.cs b/Foxnouns.Backend/Dto/Moderation.cs index bcc7e8e..0de65c7 100644 --- a/Foxnouns.Backend/Dto/Moderation.cs +++ b/Foxnouns.Backend/Dto/Moderation.cs @@ -16,10 +16,8 @@ // ReSharper disable NotAccessedPositionalProperty.Global using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Utils; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using NodaTime; namespace Foxnouns.Backend.Dto; @@ -31,19 +29,10 @@ public record ReportResponse( PartialMember? TargetMember, ReportStatus Status, ReportReason Reason, - string? Context, ReportTargetType TargetType, JObject? Snapshot ); -public record ReportDetailResponse( - ReportResponse Report, - UserResponse User, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] MemberResponse? Member, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - AuditLogResponse? AuditLogEntry -); - public record AuditLogResponse( Snowflake Id, AuditLogEntity Moderator, @@ -51,23 +40,12 @@ public record AuditLogResponse( AuditLogEntity? TargetUser, [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] AuditLogEntity? TargetMember, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] PartialReport? Report, + [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] Snowflake? ReportId, AuditLogEntryType Type, string? Reason, [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string[]? ClearedFields ); -public record PartialReport( - Snowflake Id, - Snowflake ReporterId, - Snowflake TargetUserId, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - Snowflake? TargetMemberId, - ReportReason Reason, - string? Context, - ReportTargetType TargetType -); - public record NotificationResponse( Snowflake Id, NotificationType Type, @@ -79,21 +57,19 @@ public record NotificationResponse( public record AuditLogEntity(Snowflake Id, string Username); -public record CreateReportRequest(ReportReason Reason, string? Context = null); +public record CreateReportRequest(ReportReason Reason); public record IgnoreReportRequest(string? Reason = null); -public class WarnUserRequest -{ - public required string Reason { get; init; } - public FieldsToClear[]? ClearFields { get; init; } - public Snowflake? MemberId { get; init; } - public Snowflake? ReportId { get; init; } -} +public record WarnUserRequest( + string Reason, + FieldsToClear[]? ClearFields = null, + Snowflake? MemberId = null, + Snowflake? ReportId = null +); public record SuspendUserRequest(string Reason, bool ClearProfile, Snowflake? ReportId = null); -[JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] public enum FieldsToClear { DisplayName, @@ -106,29 +82,3 @@ public enum FieldsToClear Flags, CustomPreferences, } - -public record QueryUsersRequest(string Query, bool Fuzzy); - -public record QueryUserResponse( - UserResponse User, - bool MemberListHidden, - Instant LastActive, - Instant LastSidReroll, - bool Suspended, - bool Deleted, - bool ShowSensitiveData, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] - IEnumerable? AuthMethods -); - -public record QuerySensitiveUserDataRequest(string Reason); - -public record NoticeResponse( - Snowflake Id, - string Message, - Instant StartTime, - Instant EndTime, - PartialUser Author -); - -public record CreateNoticeRequest(string Message, Instant? StartTime, Instant EndTime); diff --git a/Foxnouns.Backend/Dto/User.cs b/Foxnouns.Backend/Dto/User.cs index 2ae38f1..f193811 100644 --- a/Foxnouns.Backend/Dto/User.cs +++ b/Foxnouns.Backend/Dto/User.cs @@ -36,7 +36,7 @@ public record UserResponse( IEnumerable Names, IEnumerable Pronouns, IEnumerable Fields, - Dictionary CustomPreferences, + Dictionary CustomPreferences, IEnumerable Flags, int? UtcOffset, [property: JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] UserRole Role, @@ -49,16 +49,7 @@ public record UserResponse( [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] Instant? LastSidReroll, [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] string? Timezone, [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] bool? Suspended, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] bool? Deleted, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] UserSettings? Settings -); - -public record CustomPreferenceResponse( - string Icon, - string Tooltip, - bool Muted, - bool Favourite, - [property: JsonConverter(typeof(ScreamingSnakeCaseEnumConverter))] PreferenceSize Size + [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] bool? Deleted ); public record AuthMethodResponse( @@ -80,7 +71,6 @@ public record PartialUser( public class UpdateUserSettingsRequest : PatchRequest { public bool? DarkMode { get; init; } - public Snowflake? LastReadNotice { get; init; } } public class CustomPreferenceUpdateRequest diff --git a/Foxnouns.Backend/Dto/V1/Member.cs b/Foxnouns.Backend/Dto/V1/Member.cs deleted file mode 100644 index c745187..0000000 --- a/Foxnouns.Backend/Dto/V1/Member.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// ReSharper disable NotAccessedPositionalProperty.Global -using Foxnouns.Backend.Database; -using Newtonsoft.Json; - -namespace Foxnouns.Backend.Dto.V1; - -public record PartialMember( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns -); - -public record MemberResponse( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns, - ProfileField[] Fields, - PrideFlag[] Flags, - PartialUser User, - [property: JsonProperty(NullValueHandling = NullValueHandling.Ignore)] bool? Unlisted -); - -public record PartialUser( - string Id, - Snowflake IdNew, - string Name, - string? DisplayName, - string? Avatar, - Dictionary CustomPreferences -); diff --git a/Foxnouns.Backend/Dto/V1/User.cs b/Foxnouns.Backend/Dto/V1/User.cs deleted file mode 100644 index e80a355..0000000 --- a/Foxnouns.Backend/Dto/V1/User.cs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -// ReSharper disable NotAccessedPositionalProperty.Global -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Services.V1; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; -using NodaTime; - -namespace Foxnouns.Backend.Dto.V1; - -public record UserResponse( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? MemberTitle, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns, - ProfileField[] Fields, - PrideFlag[] Flags, - PartialMember[] Members, - int? UtcOffset, - Dictionary CustomPreferences -); - -public record CurrentUserResponse( - string Id, - Snowflake IdNew, - string Sid, - string Name, - string? DisplayName, - string? Bio, - string? MemberTitle, - string? Avatar, - string[] Links, - FieldEntry[] Names, - PronounEntry[] Pronouns, - ProfileField[] Fields, - PrideFlag[] Flags, - PartialMember[] Members, - int? UtcOffset, - Dictionary CustomPreferences, - Instant CreatedAt, - string? Timezone, - bool IsAdmin, - bool ListPrivate, - Instant LastSidReroll, - string? Discord, - string? DiscordUsername, - string? Google, - string? GoogleUsername, - string? Tumblr, - string? TumblrUsername, - string? Fediverse, - string? FediverseUsername, - string? FediverseInstance -); - -public record CustomPreference( - string Icon, - string Tooltip, - [property: JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))] - PreferenceSize Size, - bool Muted, - bool Favourite -); - -public record ProfileField(string Name, FieldEntry[] Entries) -{ - public static ProfileField FromField( - Field field, - Dictionary customPreferences - ) => new(field.Name, FieldEntry.FromEntries(field.Entries, customPreferences)); - - public static ProfileField[] FromFields( - IEnumerable fields, - Dictionary customPreferences - ) => fields.Select(f => FromField(f, customPreferences)).ToArray(); -} - -public record FieldEntry(string Value, string Status) -{ - public static FieldEntry[] FromEntries( - IEnumerable entries, - Dictionary customPreferences - ) => - entries - .Select(e => new FieldEntry( - e.Value, - V1Utils.TranslateStatus(e.Status, customPreferences) - )) - .ToArray(); -} - -public record PronounEntry(string Pronouns, string? DisplayText, string Status) -{ - public static PronounEntry[] FromPronouns( - IEnumerable pronouns, - Dictionary customPreferences - ) => - pronouns - .Select(p => new PronounEntry( - p.Value, - p.DisplayText, - V1Utils.TranslateStatus(p.Status, customPreferences) - )) - .ToArray(); -} - -public record PrideFlag(string Id, Snowflake IdNew, string Hash, string Name, string? Description); diff --git a/Foxnouns.Backend/ExpectedError.cs b/Foxnouns.Backend/ExpectedError.cs index 647688b..6a704e2 100644 --- a/Foxnouns.Backend/ExpectedError.cs +++ b/Foxnouns.Backend/ExpectedError.cs @@ -164,7 +164,6 @@ public enum ErrorCode GenericApiError, UserNotFound, MemberNotFound, - PageNotFound, AccountAlreadyLinked, LastAuthMethod, InvalidReportTarget, diff --git a/Foxnouns.Backend/Extensions/ImageObjectExtensions.cs b/Foxnouns.Backend/Extensions/ImageObjectExtensions.cs index 2d3108b..db0797c 100644 --- a/Foxnouns.Backend/Extensions/ImageObjectExtensions.cs +++ b/Foxnouns.Backend/Extensions/ImageObjectExtensions.cs @@ -33,20 +33,24 @@ public static class ImageObjectExtensions Snowflake id, string hash, CancellationToken ct = default - ) => await objectStorageService.RemoveObjectAsync(MemberAvatarUpdateJob.Path(id, hash), ct); + ) => + await objectStorageService.RemoveObjectAsync( + MemberAvatarUpdateInvocable.Path(id, hash), + ct + ); public static async Task DeleteUserAvatarAsync( this ObjectStorageService objectStorageService, Snowflake id, string hash, CancellationToken ct = default - ) => await objectStorageService.RemoveObjectAsync(UserAvatarUpdateJob.Path(id, hash), ct); + ) => await objectStorageService.RemoveObjectAsync(UserAvatarUpdateInvocable.Path(id, hash), ct); public static async Task DeleteFlagAsync( this ObjectStorageService objectStorageService, string hash, CancellationToken ct = default - ) => await objectStorageService.RemoveObjectAsync(CreateFlagJob.Path(hash), ct); + ) => await objectStorageService.RemoveObjectAsync(CreateFlagInvocable.Path(hash), ct); public static async Task<(string Hash, Stream Image)> ConvertBase64UriToImage( string uri, diff --git a/Foxnouns.Backend/Extensions/KeyCacheExtensions.cs b/Foxnouns.Backend/Extensions/KeyCacheExtensions.cs index a4fb444..615cc3d 100644 --- a/Foxnouns.Backend/Extensions/KeyCacheExtensions.cs +++ b/Foxnouns.Backend/Extensions/KeyCacheExtensions.cs @@ -23,19 +23,23 @@ namespace Foxnouns.Backend.Extensions; public static class KeyCacheExtensions { - public static async Task GenerateAuthStateAsync(this KeyCacheService keyCacheService) + public static async Task GenerateAuthStateAsync( + this KeyCacheService keyCacheService, + CancellationToken ct = default + ) { string state = AuthUtils.RandomToken(); - await keyCacheService.SetKeyAsync($"oauth_state:{state}", "", Duration.FromMinutes(10)); + await keyCacheService.SetKeyAsync($"oauth_state:{state}", "", Duration.FromMinutes(10), ct); return state; } public static async Task ValidateAuthStateAsync( this KeyCacheService keyCacheService, - string state + string state, + CancellationToken ct = default ) { - string? val = await keyCacheService.GetKeyAsync($"oauth_state:{state}"); + string? val = await keyCacheService.GetKeyAsync($"oauth_state:{state}", ct: ct); if (val == null) throw new ApiError.BadRequest("Invalid OAuth state"); } @@ -43,55 +47,63 @@ public static class KeyCacheExtensions public static async Task GenerateRegisterEmailStateAsync( this KeyCacheService keyCacheService, string email, - Snowflake? userId = null + Snowflake? userId = null, + CancellationToken ct = default ) { string state = AuthUtils.RandomToken(); await keyCacheService.SetKeyAsync( $"email_state:{state}", new RegisterEmailState(email, userId), - Duration.FromDays(1) + Duration.FromDays(1), + ct ); return state; } public static async Task GetRegisterEmailStateAsync( this KeyCacheService keyCacheService, - string state - ) => await keyCacheService.GetKeyAsync($"email_state:{state}"); + string state, + CancellationToken ct = default + ) => await keyCacheService.GetKeyAsync($"email_state:{state}", ct: ct); public static async Task GenerateAddExtraAccountStateAsync( this KeyCacheService keyCacheService, AuthType authType, Snowflake userId, - string? instance = null + string? instance = null, + CancellationToken ct = default ) { string state = AuthUtils.RandomToken(); await keyCacheService.SetKeyAsync( $"add_account:{state}", new AddExtraAccountState(authType, userId, instance), - Duration.FromDays(1) + Duration.FromDays(1), + ct ); return state; } public static async Task GetAddExtraAccountStateAsync( this KeyCacheService keyCacheService, - string state - ) => await keyCacheService.GetKeyAsync($"add_account:{state}", true); + string state, + CancellationToken ct = default + ) => await keyCacheService.GetKeyAsync($"add_account:{state}", true, ct); public static async Task GenerateForgotPasswordStateAsync( this KeyCacheService keyCacheService, string email, - Snowflake userId + Snowflake userId, + CancellationToken ct = default ) { string state = AuthUtils.RandomToken(); await keyCacheService.SetKeyAsync( $"forgot_password:{state}", new ForgotPasswordState(email, userId), - Duration.FromHours(1) + Duration.FromHours(1), + ct ); return state; } @@ -99,8 +111,14 @@ public static class KeyCacheExtensions public static async Task GetForgotPasswordStateAsync( this KeyCacheService keyCacheService, string state, - bool delete = true - ) => await keyCacheService.GetKeyAsync($"forgot_password:{state}", delete); + bool delete = true, + CancellationToken ct = default + ) => + await keyCacheService.GetKeyAsync( + $"forgot_password:{state}", + delete, + ct + ); } public record RegisterEmailState( diff --git a/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs b/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs index c3efda6..64564b2 100644 --- a/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs +++ b/Foxnouns.Backend/Extensions/WebApplicationExtensions.cs @@ -15,18 +15,13 @@ using Coravel; using Coravel.Queuing.Interfaces; using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Jobs; using Foxnouns.Backend.Middleware; using Foxnouns.Backend.Services; using Foxnouns.Backend.Services.Auth; -using Foxnouns.Backend.Services.Caching; -using Foxnouns.Backend.Services.V1; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Http.Resilience; using Minio; using NodaTime; -using Polly; using Prometheus; using Serilog; using Serilog.Events; @@ -55,12 +50,9 @@ public static class WebApplicationExtensions "Microsoft.EntityFrameworkCore.Database.Command", config.Logging.LogQueries ? LogEventLevel.Information : LogEventLevel.Fatal ) - // These spam the output even on INF level .MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore.Mvc", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning) - // Hangfire's debug-level logs are extremely spammy for no reason - .MinimumLevel.Override("Hangfire", LogEventLevel.Information) .WriteTo.Console(theme: AnsiConsoleTheme.Sixteen); if (config.Logging.SeqLogUrl != null) @@ -104,40 +96,6 @@ public static class WebApplicationExtensions builder.Host.ConfigureServices( (ctx, services) => { - // create a single HTTP client for all requests. - // it's also configured with a retry mechanism, so that requests aren't immediately lost to the void if they fail - services.AddSingleton(_ => - { - // ReSharper disable once SuggestVarOrType_Elsewhere - var retryPipeline = new ResiliencePipelineBuilder() - .AddRetry( - new HttpRetryStrategyOptions - { - BackoffType = DelayBackoffType.Linear, - MaxRetryAttempts = 3, - } - ) - .Build(); - - var resilienceHandler = new ResilienceHandler(retryPipeline) - { - InnerHandler = new SocketsHttpHandler - { - PooledConnectionLifetime = TimeSpan.FromMinutes(15), - }, - }; - - var client = new HttpClient(resilienceHandler); - client.DefaultRequestHeaders.Remove("User-Agent"); - client.DefaultRequestHeaders.Remove("Accept"); - client.DefaultRequestHeaders.Add( - "User-Agent", - $"pronouns.cc/{BuildInfo.Version}" - ); - client.DefaultRequestHeaders.Add("Accept", "application/json"); - return client; - }); - services .AddQueue() .AddSmtpMailer(ctx.Configuration) @@ -153,28 +111,23 @@ public static class WebApplicationExtensions .AddSnowflakeGenerator() .AddSingleton() .AddSingleton() - .AddSingleton() .AddScoped() .AddScoped() .AddScoped() .AddScoped() .AddScoped() + .AddScoped() .AddScoped() .AddScoped() .AddScoped() .AddTransient() - .AddTransient() - .AddSingleton() // Background services .AddHostedService() // Transient jobs - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient() - // Legacy services - .AddScoped() - .AddScoped(); + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient(); if (!config.Logging.EnableMetrics) services.AddHostedService(); @@ -199,6 +152,9 @@ public static class WebApplicationExtensions public static async Task Initialize(this WebApplication app, string[] args) { + // Read version information from .version in the repository root + await BuildInfo.ReadBuildInfo(); + app.Services.ConfigureQueue() .LogQueuedTaskProgress(app.Services.GetRequiredService>()); diff --git a/Foxnouns.Backend/Foxnouns.Backend.csproj b/Foxnouns.Backend/Foxnouns.Backend.csproj index 42a3beb..8238fc8 100644 --- a/Foxnouns.Backend/Foxnouns.Backend.csproj +++ b/Foxnouns.Backend/Foxnouns.Backend.csproj @@ -8,48 +8,42 @@ - - + + - - - - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - + + + - - - - + + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - - + + + - diff --git a/Foxnouns.Backend/Jobs/CreateDataExportJob.cs b/Foxnouns.Backend/Jobs/CreateDataExportInvocable.cs similarity index 91% rename from Foxnouns.Backend/Jobs/CreateDataExportJob.cs rename to Foxnouns.Backend/Jobs/CreateDataExportInvocable.cs index 1c392f7..4d9e1b0 100644 --- a/Foxnouns.Backend/Jobs/CreateDataExportJob.cs +++ b/Foxnouns.Backend/Jobs/CreateDataExportInvocable.cs @@ -14,11 +14,11 @@ // along with this program. If not, see . using System.IO.Compression; using System.Net; +using Coravel.Invocable; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Services; using Foxnouns.Backend.Utils; -using Hangfire; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using NodaTime; @@ -26,8 +26,7 @@ using NodaTime.Text; namespace Foxnouns.Backend.Jobs; -public class CreateDataExportJob( - HttpClient client, +public class CreateDataExportInvocable( DatabaseContext db, IClock clock, UserRendererService userRenderer, @@ -35,40 +34,37 @@ public class CreateDataExportJob( ObjectStorageService objectStorageService, ISnowflakeGenerator snowflakeGenerator, ILogger logger -) +) : IInvocable, IInvocableWithPayload { - private readonly ILogger _logger = logger.ForContext(); + private static readonly HttpClient Client = new(); + private readonly ILogger _logger = logger.ForContext(); + public required CreateDataExportPayload Payload { get; set; } - public static void Enqueue(Snowflake userId) - { - BackgroundJob.Enqueue(j => j.InvokeAsync(userId)); - } - - public async Task InvokeAsync(Snowflake userId) + public async Task Invoke() { try { - await InvokeAsyncInner(userId); + await InvokeAsync(); } catch (Exception e) { - _logger.Error(e, "Error generating data export for user {UserId}", userId); + _logger.Error(e, "Error generating data export for user {UserId}", Payload.UserId); } } - private async Task InvokeAsyncInner(Snowflake userId) + private async Task InvokeAsync() { User? user = await db .Users.Include(u => u.AuthMethods) .Include(u => u.Flags) .Include(u => u.ProfileFlags) .AsSplitQuery() - .FirstOrDefaultAsync(u => u.Id == userId); + .FirstOrDefaultAsync(u => u.Id == Payload.UserId); if (user == null) { _logger.Warning( "Received create data export request for user {UserId} but no such user exists, deleted or otherwise. Ignoring request", - userId + Payload.UserId ); return; } @@ -201,7 +197,7 @@ public class CreateDataExportJob( if (s3Path == null) return; - HttpResponseMessage resp = await client.GetAsync(s3Path); + HttpResponseMessage resp = await Client.GetAsync(s3Path); if (resp.StatusCode != HttpStatusCode.OK) { _logger.Warning("S3 path {S3Path} returned a non-200 status, not saving file", s3Path); @@ -224,5 +220,5 @@ public class CreateDataExportJob( } private static string ExportPath(Snowflake userId, string b64) => - $"data-exports/{userId}/{b64}/data-export.zip"; + $"data-exports/{userId}/{b64}.zip"; } diff --git a/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs b/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs index e40bfa4..1b8905b 100644 --- a/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs +++ b/Foxnouns.Backend/Jobs/CreateFlagInvocable.cs @@ -12,53 +12,49 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Invocable; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Services; -using Hangfire; using Microsoft.EntityFrameworkCore; namespace Foxnouns.Backend.Jobs; -public class CreateFlagJob( +public class CreateFlagInvocable( DatabaseContext db, ObjectStorageService objectStorageService, ILogger logger -) +) : IInvocable, IInvocableWithPayload { - private readonly ILogger _logger = logger.ForContext(); + private readonly ILogger _logger = logger.ForContext(); + public required CreateFlagPayload Payload { get; set; } - public static void Enqueue(CreateFlagPayload payload) - { - BackgroundJob.Enqueue(j => j.InvokeAsync(payload)); - } - - public async Task InvokeAsync(CreateFlagPayload payload) + public async Task Invoke() { _logger.Information( "Creating flag {FlagId} for user {UserId} with image data length {DataLength}", - payload.Id, - payload.UserId, - payload.ImageData.Length + Payload.Id, + Payload.UserId, + Payload.ImageData.Length ); try { PrideFlag? flag = await db.PrideFlags.FirstOrDefaultAsync(f => - f.Id == payload.Id && f.UserId == payload.UserId + f.Id == Payload.Id && f.UserId == Payload.UserId ); if (flag == null) { _logger.Warning( "Got a flag create job for {FlagId} but it doesn't exist, aborting", - payload.Id + Payload.Id ); return; } (string? hash, Stream? image) = await ImageObjectExtensions.ConvertBase64UriToImage( - payload.ImageData, + Payload.ImageData, 256, false ); @@ -72,7 +68,7 @@ public class CreateFlagJob( } catch (ArgumentException ae) { - _logger.Warning("Invalid data URI for flag {FlagId}: {Reason}", payload.Id, ae.Message); + _logger.Warning("Invalid data URI for flag {FlagId}: {Reason}", Payload.Id, ae.Message); } throw new NotImplementedException(); diff --git a/Foxnouns.Backend/Jobs/MemberAvatarUpdateJob.cs b/Foxnouns.Backend/Jobs/MemberAvatarUpdateInvocable.cs similarity index 85% rename from Foxnouns.Backend/Jobs/MemberAvatarUpdateJob.cs rename to Foxnouns.Backend/Jobs/MemberAvatarUpdateInvocable.cs index c1d2df4..01ec9e3 100644 --- a/Foxnouns.Backend/Jobs/MemberAvatarUpdateJob.cs +++ b/Foxnouns.Backend/Jobs/MemberAvatarUpdateInvocable.cs @@ -12,33 +12,29 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Invocable; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Services; -using Hangfire; namespace Foxnouns.Backend.Jobs; -public class MemberAvatarUpdateJob( +public class MemberAvatarUpdateInvocable( DatabaseContext db, ObjectStorageService objectStorageService, ILogger logger -) +) : IInvocable, IInvocableWithPayload { - private readonly ILogger _logger = logger.ForContext(); + private readonly ILogger _logger = logger.ForContext(); + public required AvatarUpdatePayload Payload { get; set; } - public static void Enqueue(AvatarUpdatePayload payload) + public async Task Invoke() { - BackgroundJob.Enqueue(j => j.InvokeAsync(payload)); - } - - public async Task InvokeAsync(AvatarUpdatePayload payload) - { - if (payload.NewAvatar != null) - await UpdateMemberAvatarAsync(payload.Id, payload.NewAvatar); + if (Payload.NewAvatar != null) + await UpdateMemberAvatarAsync(Payload.Id, Payload.NewAvatar); else - await ClearMemberAvatarAsync(payload.Id); + await ClearMemberAvatarAsync(Payload.Id); } private async Task UpdateMemberAvatarAsync(Snowflake id, string newAvatar) @@ -67,7 +63,6 @@ public class MemberAvatarUpdateJob( await objectStorageService.PutObjectAsync(Path(id, hash), image, "image/webp"); member.Avatar = hash; - member.AvatarMigrated = true; await db.SaveChangesAsync(); if (prevHash != null && prevHash != hash) diff --git a/Foxnouns.Backend/Jobs/Payloads.cs b/Foxnouns.Backend/Jobs/Payloads.cs index 1f76ea2..374a5b7 100644 --- a/Foxnouns.Backend/Jobs/Payloads.cs +++ b/Foxnouns.Backend/Jobs/Payloads.cs @@ -19,3 +19,5 @@ namespace Foxnouns.Backend.Jobs; public record AvatarUpdatePayload(Snowflake Id, string? NewAvatar); public record CreateFlagPayload(Snowflake Id, Snowflake UserId, string ImageData); + +public record CreateDataExportPayload(Snowflake UserId); diff --git a/Foxnouns.Backend/Jobs/UserAvatarUpdateJob.cs b/Foxnouns.Backend/Jobs/UserAvatarUpdateInvocable.cs similarity index 87% rename from Foxnouns.Backend/Jobs/UserAvatarUpdateJob.cs rename to Foxnouns.Backend/Jobs/UserAvatarUpdateInvocable.cs index cf7bed0..862d0da 100644 --- a/Foxnouns.Backend/Jobs/UserAvatarUpdateJob.cs +++ b/Foxnouns.Backend/Jobs/UserAvatarUpdateInvocable.cs @@ -12,33 +12,29 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using Coravel.Invocable; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Services; -using Hangfire; namespace Foxnouns.Backend.Jobs; -public class UserAvatarUpdateJob( +public class UserAvatarUpdateInvocable( DatabaseContext db, ObjectStorageService objectStorageService, ILogger logger -) +) : IInvocable, IInvocableWithPayload { - private readonly ILogger _logger = logger.ForContext(); + private readonly ILogger _logger = logger.ForContext(); + public required AvatarUpdatePayload Payload { get; set; } - public static void Enqueue(AvatarUpdatePayload payload) + public async Task Invoke() { - BackgroundJob.Enqueue(j => j.InvokeAsync(payload)); - } - - public async Task InvokeAsync(AvatarUpdatePayload payload) - { - if (payload.NewAvatar != null) - await UpdateUserAvatarAsync(payload.Id, payload.NewAvatar); + if (Payload.NewAvatar != null) + await UpdateUserAvatarAsync(Payload.Id, Payload.NewAvatar); else - await ClearUserAvatarAsync(payload.Id); + await ClearUserAvatarAsync(Payload.Id); } private async Task UpdateUserAvatarAsync(Snowflake id, string newAvatar) @@ -68,7 +64,6 @@ public class UserAvatarUpdateJob( await objectStorageService.PutObjectAsync(Path(id, hash), image, "image/webp"); user.Avatar = hash; - user.AvatarMigrated = true; await db.SaveChangesAsync(); if (prevHash != null && prevHash != hash) diff --git a/Foxnouns.Backend/Middleware/LimitMiddleware.cs b/Foxnouns.Backend/Middleware/LimitMiddleware.cs index 6092041..1c5f522 100644 --- a/Foxnouns.Backend/Middleware/LimitMiddleware.cs +++ b/Foxnouns.Backend/Middleware/LimitMiddleware.cs @@ -41,7 +41,7 @@ public class LimitMiddleware : IMiddleware return; } - if (token?.User.Deleted == true && !attribute.UsableByDeletedUsers) + if (token?.User.Deleted == true && !attribute.UsableBySuspendedUsers) throw new ApiError.Forbidden("Deleted users cannot access this endpoint."); if (attribute.RequireAdmin && token?.User.Role != UserRole.Admin) @@ -62,7 +62,7 @@ public class LimitMiddleware : IMiddleware [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class LimitAttribute : Attribute { - public bool UsableByDeletedUsers { get; init; } + public bool UsableBySuspendedUsers { get; init; } public bool RequireAdmin { get; init; } public bool RequireModerator { get; init; } } diff --git a/Foxnouns.Backend/Program.cs b/Foxnouns.Backend/Program.cs index b266248..66e57a6 100644 --- a/Foxnouns.Backend/Program.cs +++ b/Foxnouns.Backend/Program.cs @@ -19,12 +19,11 @@ using Foxnouns.Backend.Extensions; using Foxnouns.Backend.Services; using Foxnouns.Backend.Utils; using Foxnouns.Backend.Utils.OpenApi; -using Hangfire; -using Hangfire.Redis.StackExchange; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Prometheus; +using Scalar.AspNetCore; using Sentry.Extensibility; using Serilog; @@ -34,9 +33,6 @@ Config config = builder.AddConfiguration(); builder.AddSerilog(); -// Read version information from .version in the repository root -await BuildInfo.ReadBuildInfo(); - builder .WebHost.UseSentry(opts => { @@ -50,8 +46,7 @@ builder // No valid request body will ever come close to this limit, // but the limit is slightly higher to prevent valid requests from being rejected. opts.Limits.MaxRequestBodySize = 2 * 1024 * 1024; - }) - .UseUrls(config.Address); + }); builder .Services.AddControllers() @@ -68,26 +63,15 @@ builder { NamingStrategy = new SnakeCaseNamingStrategy(), }; - options.SerializerSettings.DateParseHandling = DateParseHandling.None; }) .ConfigureApiBehaviorOptions(options => { - options.InvalidModelStateResponseFactory = actionContext => new BadRequestObjectResult( - new ApiError.AspBadRequest("Bad request", actionContext.ModelState).ToJson() - ); - }); - -builder - .Services.AddHangfire( - (services, c) => - { - c.UseRedisStorage( - services.GetRequiredService().Multiplexer, - new RedisStorageOptions { Prefix = "foxnouns_net:" } + // the type isn't needed but without it, rider keeps complaining for no reason (it compiles just fine) + options.InvalidModelStateResponseFactory = (ActionContext actionContext) => + new BadRequestObjectResult( + new ApiError.AspBadRequest("Bad request", actionContext.ModelState).ToJson() ); - } - ) - .AddHangfireServer(); + }); builder.Services.AddOpenApi( "v2", @@ -125,19 +109,16 @@ if (config.Logging.SentryTracing) app.UseCors(); app.UseCustomMiddleware(); app.MapControllers(); -app.UseHangfireDashboard(); +app.MapOpenApi("/api-docs/openapi/{documentName}.json"); +app.MapScalarApiReference(options => +{ + options.Title = "pronouns.cc API"; + options.OpenApiRoutePattern = "/api-docs/openapi/{documentName}.json"; + options.EndpointPathPrefix = "/api-docs/{documentName}"; +}); -// TODO: I can't figure out why this doesn't work yet -// TODO: Manually write API docs in the meantime -// app.MapOpenApi("/api-docs/openapi/{documentName}.json"); -// app.MapScalarApiReference( -// "/api-docs/", -// options => -// { -// options.Title = "pronouns.cc API"; -// options.OpenApiRoutePattern = "/api-docs/openapi/{documentName}.json"; -// } -// ); +app.Urls.Clear(); +app.Urls.Add(config.Address); // Make sure metrics are updated whenever Prometheus scrapes them Metrics.DefaultRegistry.AddBeforeCollectCallback(async ct => diff --git a/Foxnouns.Backend/Services/Auth/AuthService.cs b/Foxnouns.Backend/Services/Auth/AuthService.cs index e3e3edb..f8c2428 100644 --- a/Foxnouns.Backend/Services/Auth/AuthService.cs +++ b/Foxnouns.Backend/Services/Auth/AuthService.cs @@ -20,7 +20,6 @@ using Foxnouns.Backend.Utils; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using NodaTime; -using XidNet; namespace Foxnouns.Backend.Services.Auth; @@ -29,8 +28,7 @@ public class AuthService( ILogger logger, DatabaseContext db, ISnowflakeGenerator snowflakeGenerator, - UserRendererService userRenderer, - ValidationService validationService + UserRendererService userRenderer ) { private readonly ILogger _logger = logger.ForContext(); @@ -50,7 +48,7 @@ public class AuthService( // Validate username and whether it's not taken ValidationUtils.Validate( [ - ("username", validationService.ValidateUsername(username)), + ("username", ValidationUtils.ValidateUsername(username)), ("password", ValidationUtils.ValidatePassword(password)), ] ); @@ -72,7 +70,6 @@ public class AuthService( }, LastActive = clock.GetCurrentInstant(), Sid = null!, - LegacyId = Xid.NewXid().ToString(), }; db.Add(user); @@ -98,7 +95,7 @@ public class AuthService( AssertValidAuthType(authType, instance); // Validate username and whether it's not taken - ValidationUtils.Validate([("username", validationService.ValidateUsername(username))]); + ValidationUtils.Validate([("username", ValidationUtils.ValidateUsername(username))]); if (await db.Users.AnyAsync(u => u.Username == username, ct)) throw new ApiError.BadRequest("Username is already taken", "username", username); @@ -119,7 +116,6 @@ public class AuthService( }, LastActive = clock.GetCurrentInstant(), Sid = null!, - LegacyId = Xid.NewXid().ToString(), }; db.Add(user); @@ -253,14 +249,14 @@ public class AuthService( { AssertValidAuthType(authType, app); - // This is already checked when generating an add account state, but we check it here too just in case. + // This is already checked when int currentCount = await db .AuthMethods.Where(m => m.UserId == userId && m.AuthType == authType) .CountAsync(ct); if (currentCount >= AuthUtils.MaxAuthMethodsPerType) { throw new ApiError.BadRequest( - $"Too many linked accounts of this type, maximum of {AuthUtils.MaxAuthMethodsPerType} per account." + "Too many linked accounts of this type, maximum of 3 per account." ); } diff --git a/Foxnouns.Backend/Services/Auth/FediverseAuthService.Mastodon.cs b/Foxnouns.Backend/Services/Auth/FediverseAuthService.Mastodon.cs index 225461c..25d5327 100644 --- a/Foxnouns.Backend/Services/Auth/FediverseAuthService.Mastodon.cs +++ b/Foxnouns.Backend/Services/Auth/FediverseAuthService.Mastodon.cs @@ -25,20 +25,20 @@ namespace Foxnouns.Backend.Services.Auth; public partial class FediverseAuthService { private string MastodonRedirectUri(string instance) => - $"{config.BaseUrl}/auth/callback/mastodon/{instance}"; + $"{_config.BaseUrl}/auth/callback/mastodon/{instance}"; private async Task CreateMastodonApplicationAsync( string instance, Snowflake? existingAppId = null ) { - HttpResponseMessage resp = await client.PostAsJsonAsync( + HttpResponseMessage resp = await _client.PostAsJsonAsync( $"https://{instance}/api/v1/apps", new CreateMastodonApplicationRequest( - $"pronouns.cc (+{config.BaseUrl})", + $"pronouns.cc (+{_config.BaseUrl})", MastodonRedirectUri(instance), "read read:accounts", - config.BaseUrl + _config.BaseUrl ) ); resp.EnsureSuccessStatusCode(); @@ -58,19 +58,19 @@ public partial class FediverseAuthService { app = new FediverseApplication { - Id = existingAppId ?? snowflakeGenerator.GenerateSnowflake(), + Id = existingAppId ?? _snowflakeGenerator.GenerateSnowflake(), ClientId = mastodonApp.ClientId, ClientSecret = mastodonApp.ClientSecret, Domain = instance, InstanceType = FediverseInstanceType.MastodonApi, }; - db.Add(app); + _db.Add(app); } else { app = - await db.FediverseApplications.FindAsync(existingAppId) + await _db.FediverseApplications.FindAsync(existingAppId) ?? throw new FoxnounsError($"Existing app with ID {existingAppId} was null"); app.ClientId = mastodonApp.ClientId; @@ -78,7 +78,7 @@ public partial class FediverseAuthService app.InstanceType = FediverseInstanceType.MastodonApi; } - await db.SaveChangesAsync(); + await _db.SaveChangesAsync(); return app; } @@ -90,9 +90,9 @@ public partial class FediverseAuthService ) { if (state != null) - await keyCacheService.ValidateAuthStateAsync(state); + await _keyCacheService.ValidateAuthStateAsync(state); - HttpResponseMessage tokenResp = await client.PostAsync( + HttpResponseMessage tokenResp = await _client.PostAsync( MastodonTokenUri(app.Domain), new FormUrlEncodedContent( new Dictionary @@ -123,7 +123,7 @@ public partial class FediverseAuthService var req = new HttpRequestMessage(HttpMethod.Get, MastodonCurrentUserUri(app.Domain)); req.Headers.Add("Authorization", $"Bearer {token}"); - HttpResponseMessage currentUserResp = await client.SendAsync(req); + HttpResponseMessage currentUserResp = await _client.SendAsync(req); currentUserResp.EnsureSuccessStatusCode(); FediverseUser? user = await currentUserResp.Content.ReadFromJsonAsync(); if (user == null) @@ -151,7 +151,7 @@ public partial class FediverseAuthService app = await CreateMastodonApplicationAsync(app.Domain, app.Id); } - state ??= HttpUtility.UrlEncode(await keyCacheService.GenerateAuthStateAsync()); + state ??= HttpUtility.UrlEncode(await _keyCacheService.GenerateAuthStateAsync()); return $"https://{app.Domain}/oauth/authorize?response_type=code" + $"&client_id={app.ClientId}" diff --git a/Foxnouns.Backend/Services/Auth/FediverseAuthService.Misskey.cs b/Foxnouns.Backend/Services/Auth/FediverseAuthService.Misskey.cs index bf6c4b4..10a61e4 100644 --- a/Foxnouns.Backend/Services/Auth/FediverseAuthService.Misskey.cs +++ b/Foxnouns.Backend/Services/Auth/FediverseAuthService.Misskey.cs @@ -34,11 +34,11 @@ public partial class FediverseAuthService Snowflake? existingAppId = null ) { - HttpResponseMessage resp = await client.PostAsJsonAsync( + HttpResponseMessage resp = await _client.PostAsJsonAsync( MisskeyAppUri(instance), new CreateMisskeyApplicationRequest( - $"pronouns.cc (+{config.BaseUrl})", - $"pronouns.cc on {config.BaseUrl}", + $"pronouns.cc (+{_config.BaseUrl})", + $"pronouns.cc on {_config.BaseUrl}", ["read:account"], MastodonRedirectUri(instance) ) @@ -60,19 +60,19 @@ public partial class FediverseAuthService { app = new FediverseApplication { - Id = existingAppId ?? snowflakeGenerator.GenerateSnowflake(), + Id = existingAppId ?? _snowflakeGenerator.GenerateSnowflake(), ClientId = misskeyApp.Id, ClientSecret = misskeyApp.Secret, Domain = instance, InstanceType = FediverseInstanceType.MisskeyApi, }; - db.Add(app); + _db.Add(app); } else { app = - await db.FediverseApplications.FindAsync(existingAppId) + await _db.FediverseApplications.FindAsync(existingAppId) ?? throw new FoxnounsError($"Existing app with ID {existingAppId} was null"); app.ClientId = misskeyApp.Id; @@ -80,7 +80,7 @@ public partial class FediverseAuthService app.InstanceType = FediverseInstanceType.MisskeyApi; } - await db.SaveChangesAsync(); + await _db.SaveChangesAsync(); return app; } @@ -96,7 +96,7 @@ public partial class FediverseAuthService private async Task GetMisskeyUserAsync(FediverseApplication app, string code) { - HttpResponseMessage resp = await client.PostAsJsonAsync( + HttpResponseMessage resp = await _client.PostAsJsonAsync( MisskeyTokenUri(app.Domain), new GetMisskeySessionUserKeyRequest(app.ClientSecret, code) ); @@ -130,7 +130,7 @@ public partial class FediverseAuthService app = await CreateMisskeyApplicationAsync(app.Domain, app.Id); } - HttpResponseMessage resp = await client.PostAsJsonAsync( + HttpResponseMessage resp = await _client.PostAsJsonAsync( MisskeyGenerateSessionUri(app.Domain), new CreateMisskeySessionUriRequest(app.ClientSecret) ); diff --git a/Foxnouns.Backend/Services/Auth/FediverseAuthService.cs b/Foxnouns.Backend/Services/Auth/FediverseAuthService.cs index 3ffc28d..9ca7290 100644 --- a/Foxnouns.Backend/Services/Auth/FediverseAuthService.cs +++ b/Foxnouns.Backend/Services/Auth/FediverseAuthService.cs @@ -19,17 +19,37 @@ using J = System.Text.Json.Serialization.JsonPropertyNameAttribute; namespace Foxnouns.Backend.Services.Auth; -public partial class FediverseAuthService( - ILogger logger, - Config config, - DatabaseContext db, - HttpClient client, - KeyCacheService keyCacheService, - ISnowflakeGenerator snowflakeGenerator -) +public partial class FediverseAuthService { private const string NodeInfoRel = "http://nodeinfo.diaspora.software/ns/schema/2.0"; - private readonly ILogger _logger = logger.ForContext(); + + private readonly HttpClient _client; + private readonly ILogger _logger; + private readonly Config _config; + private readonly DatabaseContext _db; + private readonly KeyCacheService _keyCacheService; + private readonly ISnowflakeGenerator _snowflakeGenerator; + + public FediverseAuthService( + ILogger logger, + Config config, + DatabaseContext db, + KeyCacheService keyCacheService, + ISnowflakeGenerator snowflakeGenerator + ) + { + _logger = logger.ForContext(); + _config = config; + _db = db; + _keyCacheService = keyCacheService; + _snowflakeGenerator = snowflakeGenerator; + + _client = new HttpClient(); + _client.DefaultRequestHeaders.Remove("User-Agent"); + _client.DefaultRequestHeaders.Remove("Accept"); + _client.DefaultRequestHeaders.Add("User-Agent", $"pronouns.cc/{BuildInfo.Version}"); + _client.DefaultRequestHeaders.Add("Accept", "application/json"); + } public async Task GenerateAuthUrlAsync( string instance, @@ -38,7 +58,7 @@ public partial class FediverseAuthService( ) { FediverseApplication app = await GetApplicationAsync(instance); - return await GenerateAuthUrlAsync(app, forceRefresh || app.ForceRefresh, state); + return await GenerateAuthUrlAsync(app, forceRefresh, state); } // thank you, gargron and syuilo, for agreeing on a name for *once* in your lives, @@ -50,7 +70,7 @@ public partial class FediverseAuthService( public async Task GetApplicationAsync(string instance) { - FediverseApplication? app = await db.FediverseApplications.FirstOrDefaultAsync(a => + FediverseApplication? app = await _db.FediverseApplications.FirstOrDefaultAsync(a => a.Domain == instance ); if (app != null) @@ -72,7 +92,7 @@ public partial class FediverseAuthService( { _logger.Debug("Requesting software name for fediverse instance {Instance}", instance); - HttpResponseMessage wellKnownResp = await client.GetAsync( + HttpResponseMessage wellKnownResp = await _client.GetAsync( new Uri($"https://{instance}/.well-known/nodeinfo") ); wellKnownResp.EnsureSuccessStatusCode(); @@ -87,7 +107,7 @@ public partial class FediverseAuthService( ); } - HttpResponseMessage nodeInfoResp = await client.GetAsync(nodeInfoUrl); + HttpResponseMessage nodeInfoResp = await _client.GetAsync(nodeInfoUrl); nodeInfoResp.EnsureSuccessStatusCode(); PartialNodeInfo? nodeInfo = await nodeInfoResp.Content.ReadFromJsonAsync(); diff --git a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Discord.cs b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Discord.cs index d884fda..de16d2f 100644 --- a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Discord.cs +++ b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Discord.cs @@ -27,7 +27,7 @@ public partial class RemoteAuthService ) { var redirectUri = $"{config.BaseUrl}/auth/callback/discord"; - HttpResponseMessage resp = await client.PostAsync( + HttpResponseMessage resp = await _httpClient.PostAsync( _discordTokenUri, new FormUrlEncodedContent( new Dictionary @@ -59,7 +59,7 @@ public partial class RemoteAuthService var req = new HttpRequestMessage(HttpMethod.Get, _discordUserUri); req.Headers.Add("Authorization", $"{token.TokenType} {token.AccessToken}"); - HttpResponseMessage resp2 = await client.SendAsync(req, ct); + HttpResponseMessage resp2 = await _httpClient.SendAsync(req, ct); resp2.EnsureSuccessStatusCode(); DiscordUserResponse? user = await resp2.Content.ReadFromJsonAsync(ct); if (user == null) diff --git a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Google.cs b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Google.cs index 938ba32..3245858 100644 --- a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Google.cs +++ b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Google.cs @@ -28,7 +28,7 @@ public partial class RemoteAuthService ) { var redirectUri = $"{config.BaseUrl}/auth/callback/google"; - HttpResponseMessage resp = await client.PostAsync( + HttpResponseMessage resp = await _httpClient.PostAsync( _googleTokenUri, new FormUrlEncodedContent( new Dictionary diff --git a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Tumblr.cs b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Tumblr.cs index 45b9161..d63ee1a 100644 --- a/Foxnouns.Backend/Services/Auth/RemoteAuthService.Tumblr.cs +++ b/Foxnouns.Backend/Services/Auth/RemoteAuthService.Tumblr.cs @@ -29,7 +29,7 @@ public partial class RemoteAuthService ) { var redirectUri = $"{config.BaseUrl}/auth/callback/tumblr"; - HttpResponseMessage resp = await client.PostAsync( + HttpResponseMessage resp = await _httpClient.PostAsync( _tumblrTokenUri, new FormUrlEncodedContent( new Dictionary @@ -62,7 +62,7 @@ public partial class RemoteAuthService var req = new HttpRequestMessage(HttpMethod.Get, _tumblrUserUri); req.Headers.Add("Authorization", $"Bearer {token.AccessToken}"); - HttpResponseMessage resp2 = await client.SendAsync(req, ct); + HttpResponseMessage resp2 = await _httpClient.SendAsync(req, ct); if (!resp2.IsSuccessStatusCode) { string respBody = await resp2.Content.ReadAsStringAsync(ct); diff --git a/Foxnouns.Backend/Services/Auth/RemoteAuthService.cs b/Foxnouns.Backend/Services/Auth/RemoteAuthService.cs index 93b006b..6e0ba76 100644 --- a/Foxnouns.Backend/Services/Auth/RemoteAuthService.cs +++ b/Foxnouns.Backend/Services/Auth/RemoteAuthService.cs @@ -25,7 +25,6 @@ using Microsoft.EntityFrameworkCore; namespace Foxnouns.Backend.Services.Auth; public partial class RemoteAuthService( - HttpClient client, Config config, ILogger logger, DatabaseContext db, @@ -33,6 +32,7 @@ public partial class RemoteAuthService( ) { private readonly ILogger _logger = logger.ForContext(); + private readonly HttpClient _httpClient = new(); public record RemoteUser(string Id, string Username); diff --git a/Foxnouns.Backend/Services/Caching/NoticeCacheService.cs b/Foxnouns.Backend/Services/Caching/NoticeCacheService.cs deleted file mode 100644 index 2a0b1f9..0000000 --- a/Foxnouns.Backend/Services/Caching/NoticeCacheService.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Microsoft.EntityFrameworkCore; -using NodaTime; - -namespace Foxnouns.Backend.Services.Caching; - -public class NoticeCacheService(IServiceProvider serviceProvider, IClock clock, ILogger logger) - : SingletonCacheService(serviceProvider, clock, logger) -{ - public override Duration MaxAge { get; init; } = Duration.FromMinutes(5); - - public override Func< - DatabaseContext, - CancellationToken, - Task - > FetchFunc { get; init; } = - async (db, ct) => - await db - .Notices.Where(n => - n.StartTime < clock.GetCurrentInstant() && n.EndTime > clock.GetCurrentInstant() - ) - .OrderByDescending(n => n.Id) - .FirstOrDefaultAsync(ct); -} diff --git a/Foxnouns.Backend/Services/Caching/SingletonCacheService.cs b/Foxnouns.Backend/Services/Caching/SingletonCacheService.cs deleted file mode 100644 index 87b19a7..0000000 --- a/Foxnouns.Backend/Services/Caching/SingletonCacheService.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using NodaTime; - -namespace Foxnouns.Backend.Services.Caching; - -public abstract class SingletonCacheService( - IServiceProvider serviceProvider, - IClock clock, - ILogger logger -) - where T : class -{ - private T? _item; - private Instant _lastUpdated = Instant.MinValue; - private readonly SemaphoreSlim _semaphore = new(1, 1); - private readonly ILogger _logger = logger.ForContext>(); - - public virtual Duration MaxAge { get; init; } = Duration.FromMinutes(5); - - public virtual Func> FetchFunc { get; init; } = - (_, __) => Task.FromResult(null); - - public async Task GetAsync(CancellationToken ct = default) - { - await _semaphore.WaitAsync(ct); - try - { - if (_lastUpdated > clock.GetCurrentInstant() - MaxAge) - { - return _item; - } - - _logger.Debug("Cached item of type {Type} is expired, fetching it.", typeof(T)); - - await using AsyncServiceScope scope = serviceProvider.CreateAsyncScope(); - await using DatabaseContext db = - scope.ServiceProvider.GetRequiredService(); - - T? item = await FetchFunc(db, ct); - _item = item; - _lastUpdated = clock.GetCurrentInstant(); - return item; - } - finally - { - _semaphore.Release(); - } - } -} diff --git a/Foxnouns.Backend/Services/DataCleanupService.cs b/Foxnouns.Backend/Services/DataCleanupService.cs index ee60bb8..3d60462 100644 --- a/Foxnouns.Backend/Services/DataCleanupService.cs +++ b/Foxnouns.Backend/Services/DataCleanupService.cs @@ -128,5 +128,5 @@ public class DataCleanupService( } private static string ExportPath(Snowflake userId, string b64) => - $"data-exports/{userId}/{b64}/data-export.zip"; + $"data-exports/{userId}/{b64}.zip"; } diff --git a/Foxnouns.Backend/Services/EmailRateLimiter.cs b/Foxnouns.Backend/Services/EmailRateLimiter.cs index cc2dbb4..3a1a81a 100644 --- a/Foxnouns.Backend/Services/EmailRateLimiter.cs +++ b/Foxnouns.Backend/Services/EmailRateLimiter.cs @@ -23,11 +23,8 @@ public class EmailRateLimiter { private readonly ConcurrentDictionary _limiters = new(); - private readonly FixedWindowRateLimiterOptions _limiterOptions = new() - { - Window = TimeSpan.FromHours(2), - PermitLimit = 3, - }; + private readonly FixedWindowRateLimiterOptions _limiterOptions = + new() { Window = TimeSpan.FromHours(2), PermitLimit = 3 }; private RateLimiter GetLimiter(string bucket) => _limiters.GetOrAdd(bucket, _ => new FixedWindowRateLimiter(_limiterOptions)); diff --git a/Foxnouns.Backend/Services/KeyCacheService.cs b/Foxnouns.Backend/Services/KeyCacheService.cs index 5c59bce..0163516 100644 --- a/Foxnouns.Backend/Services/KeyCacheService.cs +++ b/Foxnouns.Backend/Services/KeyCacheService.cs @@ -17,39 +17,94 @@ using Foxnouns.Backend.Database.Models; using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using NodaTime; -using StackExchange.Redis; namespace Foxnouns.Backend.Services; -public class KeyCacheService(Config config) +public class KeyCacheService(DatabaseContext db, IClock clock, ILogger logger) { - public ConnectionMultiplexer Multiplexer { get; } = - ConnectionMultiplexer.Connect(config.Database.Redis); + private readonly ILogger _logger = logger.ForContext(); - public async Task SetKeyAsync(string key, string value, Duration expireAfter) => - await Multiplexer - .GetDatabase() - .StringSetAsync(key, value, expiry: expireAfter.ToTimeSpan()); + public Task SetKeyAsync( + string key, + string value, + Duration expireAfter, + CancellationToken ct = default + ) => SetKeyAsync(key, value, clock.GetCurrentInstant() + expireAfter, ct); - public async Task GetKeyAsync(string key, bool delete = false) => - delete - ? await Multiplexer.GetDatabase().StringGetDeleteAsync(key) - : await Multiplexer.GetDatabase().StringGetAsync(key); + public async Task SetKeyAsync( + string key, + string value, + Instant expires, + CancellationToken ct = default + ) + { + db.TemporaryKeys.Add( + new TemporaryKey + { + Expires = expires, + Key = key, + Value = value, + } + ); + await db.SaveChangesAsync(ct); + } - public async Task DeleteKeyAsync(string key) => - await Multiplexer.GetDatabase().KeyDeleteAsync(key); + public async Task GetKeyAsync( + string key, + bool delete = false, + CancellationToken ct = default + ) + { + TemporaryKey? value = await db.TemporaryKeys.FirstOrDefaultAsync(k => k.Key == key, ct); + if (value == null) + return null; - public async Task SetKeyAsync(string key, T obj, Duration expiresAt) + if (delete) + await db.TemporaryKeys.Where(k => k.Key == key).ExecuteDeleteAsync(ct); + + return value.Value; + } + + public async Task DeleteKeyAsync(string key, CancellationToken ct = default) => + await db.TemporaryKeys.Where(k => k.Key == key).ExecuteDeleteAsync(ct); + + public async Task DeleteExpiredKeysAsync(CancellationToken ct) + { + int count = await db + .TemporaryKeys.Where(k => k.Expires < clock.GetCurrentInstant()) + .ExecuteDeleteAsync(ct); + if (count != 0) + _logger.Information("Removed {Count} expired keys from the database", count); + } + + public Task SetKeyAsync( + string key, + T obj, + Duration expiresAt, + CancellationToken ct = default + ) + where T : class => SetKeyAsync(key, obj, clock.GetCurrentInstant() + expiresAt, ct); + + public async Task SetKeyAsync( + string key, + T obj, + Instant expires, + CancellationToken ct = default + ) where T : class { string value = JsonConvert.SerializeObject(obj); - await SetKeyAsync(key, value, expiresAt); + await SetKeyAsync(key, value, expires, ct); } - public async Task GetKeyAsync(string key, bool delete = false) + public async Task GetKeyAsync( + string key, + bool delete = false, + CancellationToken ct = default + ) where T : class { - string? value = await GetKeyAsync(key, delete); + string? value = await GetKeyAsync(key, delete, ct); return value == null ? default : JsonConvert.DeserializeObject(value); } } diff --git a/Foxnouns.Backend/Services/ModerationRendererService.cs b/Foxnouns.Backend/Services/ModerationRendererService.cs index c1d259a..deed9c5 100644 --- a/Foxnouns.Backend/Services/ModerationRendererService.cs +++ b/Foxnouns.Backend/Services/ModerationRendererService.cs @@ -36,7 +36,6 @@ public class ModerationRendererService( : null, report.Status, report.Reason, - report.Context, report.TargetType, report.TargetSnapshot != null ? JsonConvert.DeserializeObject(report.TargetSnapshot) @@ -46,26 +45,12 @@ public class ModerationRendererService( public AuditLogResponse RenderAuditLogEntry(AuditLogEntry entry) { - PartialReport? report = null; - if (entry.Report != null) - { - report = new PartialReport( - entry.Report.Id, - entry.Report.ReporterId, - entry.Report.TargetUserId, - entry.Report.TargetMemberId, - entry.Report.Reason, - entry.Report.Context, - entry.Report.TargetType - ); - } - return new AuditLogResponse( Id: entry.Id, Moderator: ToEntity(entry.ModeratorId, entry.ModeratorUsername)!, TargetUser: ToEntity(entry.TargetUserId, entry.TargetUsername), TargetMember: ToEntity(entry.TargetMemberId, entry.TargetMemberName), - Report: report, + ReportId: entry.ReportId, Type: entry.Type, Reason: entry.Reason, ClearedFields: entry.ClearedFields diff --git a/Foxnouns.Backend/Services/ModerationService.cs b/Foxnouns.Backend/Services/ModerationService.cs index 30d99ed..5444657 100644 --- a/Foxnouns.Backend/Services/ModerationService.cs +++ b/Foxnouns.Backend/Services/ModerationService.cs @@ -18,7 +18,6 @@ using Foxnouns.Backend.Database.Models; using Foxnouns.Backend.Dto; using Foxnouns.Backend.Jobs; using Humanizer; -using Microsoft.EntityFrameworkCore; using NodaTime; namespace Foxnouns.Backend.Services; @@ -27,6 +26,7 @@ public class ModerationService( ILogger logger, DatabaseContext db, ISnowflakeGenerator snowflakeGenerator, + IQueue queue, IClock clock ) { @@ -63,54 +63,6 @@ public class ModerationService( return entry; } - public async Task QuerySensitiveDataAsync( - User moderator, - User target, - string reason - ) - { - _logger.Information( - "Moderator {ModeratorId} is querying sensitive data for {TargetId}", - moderator.Id, - target.Id - ); - - var entry = new AuditLogEntry - { - Id = snowflakeGenerator.GenerateSnowflake(), - ModeratorId = moderator.Id, - ModeratorUsername = moderator.Username, - TargetUserId = target.Id, - TargetUsername = target.Username, - Type = AuditLogEntryType.QuerySensitiveUserData, - Reason = reason, - }; - db.AuditLog.Add(entry); - - await db.SaveChangesAsync(); - return entry; - } - - public async Task ShowSensitiveDataAsync( - User moderator, - User target, - CancellationToken ct = default - ) - { - Snowflake cutoff = snowflakeGenerator.GenerateSnowflake( - clock.GetCurrentInstant() - Duration.FromDays(1) - ); - - return await db.AuditLog.AnyAsync( - e => - e.ModeratorId == moderator.Id - && e.TargetUserId == target.Id - && e.Type == AuditLogEntryType.QuerySensitiveUserData - && e.Id > cutoff, - ct - ); - } - public async Task ExecuteSuspensionAsync( User moderator, User target, @@ -153,12 +105,6 @@ public class ModerationService( target.DeletedAt = clock.GetCurrentInstant(); target.DeletedBy = moderator.Id; - if (report != null) - { - report.Status = ReportStatus.Closed; - db.Update(report); - } - if (!clearProfile) { db.Update(target); @@ -180,7 +126,9 @@ public class ModerationService( target.CustomPreferences = []; target.ProfileFlags = []; - UserAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(target.Id, null)); + queue.QueueInvocableWithPayload( + new AvatarUpdatePayload(target.Id, null) + ); // TODO: also clear member profiles? @@ -261,9 +209,10 @@ public class ModerationService( targetMember.DisplayName = null; break; case FieldsToClear.Avatar: - MemberAvatarUpdateJob.Enqueue( - new AvatarUpdatePayload(targetMember.Id, null) - ); + queue.QueueInvocableWithPayload< + MemberAvatarUpdateInvocable, + AvatarUpdatePayload + >(new AvatarUpdatePayload(targetMember.Id, null)); break; case FieldsToClear.Bio: targetMember.Bio = null; @@ -302,7 +251,10 @@ public class ModerationService( targetUser.DisplayName = null; break; case FieldsToClear.Avatar: - UserAvatarUpdateJob.Enqueue(new AvatarUpdatePayload(targetUser.Id, null)); + queue.QueueInvocableWithPayload< + UserAvatarUpdateInvocable, + AvatarUpdatePayload + >(new AvatarUpdatePayload(targetUser.Id, null)); break; case FieldsToClear.Bio: targetUser.Bio = null; @@ -333,12 +285,6 @@ public class ModerationService( db.Update(targetUser); } - if (report != null) - { - report.Status = ReportStatus.Closed; - db.Update(report); - } - await db.SaveChangesAsync(); return entry; diff --git a/Foxnouns.Backend/Services/PeriodicTasksService.cs b/Foxnouns.Backend/Services/PeriodicTasksService.cs index e5efd28..bf0f4af 100644 --- a/Foxnouns.Backend/Services/PeriodicTasksService.cs +++ b/Foxnouns.Backend/Services/PeriodicTasksService.cs @@ -33,9 +33,11 @@ public class PeriodicTasksService(ILogger logger, IServiceProvider services) : B // The type is literally written on the same line, we can just use `var` // ReSharper disable SuggestVarOrType_SimpleTypes + var keyCacheService = scope.ServiceProvider.GetRequiredService(); var dataCleanupService = scope.ServiceProvider.GetRequiredService(); // ReSharper restore SuggestVarOrType_SimpleTypes + await keyCacheService.DeleteExpiredKeysAsync(ct); await dataCleanupService.InvokeAsync(ct); } } diff --git a/Foxnouns.Backend/Services/UserRendererService.cs b/Foxnouns.Backend/Services/UserRendererService.cs index 0c1fc1b..df40e1a 100644 --- a/Foxnouns.Backend/Services/UserRendererService.cs +++ b/Foxnouns.Backend/Services/UserRendererService.cs @@ -33,7 +33,6 @@ public class UserRendererService( bool renderMembers = true, bool renderAuthMethods = false, string? overrideSid = null, - bool renderSettings = false, CancellationToken ct = default ) => await RenderUserInnerAsync( @@ -43,7 +42,6 @@ public class UserRendererService( renderMembers, renderAuthMethods, overrideSid, - renderSettings, ct ); @@ -54,7 +52,6 @@ public class UserRendererService( bool renderMembers = true, bool renderAuthMethods = false, string? overrideSid = null, - bool renderSettings = false, CancellationToken ct = default ) { @@ -65,7 +62,6 @@ public class UserRendererService( renderMembers = renderMembers && (!user.ListHidden || tokenCanReadHiddenMembers); renderAuthMethods = renderAuthMethods && tokenPrivileged; - renderSettings = renderSettings && tokenHidden; IEnumerable members = renderMembers ? await db.Members.Where(m => m.UserId == user.Id).OrderBy(m => m.Name).ToListAsync(ct) @@ -107,8 +103,7 @@ public class UserRendererService( user.Names, user.Pronouns, user.Fields, - user.CustomPreferences.Select(x => (x.Key, RenderCustomPreference(x.Value))) - .ToDictionary(), + user.CustomPreferences, flags.Select(f => RenderPrideFlag(f.PrideFlag)), utcOffset, user.Role, @@ -121,8 +116,7 @@ public class UserRendererService( tokenHidden ? user.LastSidReroll : null, tokenHidden ? user.Timezone ?? "" : null, tokenHidden ? user is { Deleted: true, DeletedBy: not null } : null, - tokenHidden ? user.Deleted : null, - renderSettings ? user.Settings : null + tokenHidden ? user.Deleted : null ); } @@ -136,14 +130,6 @@ public class UserRendererService( : a.RemoteUsername ); - public static CustomPreferenceResponse RenderCustomPreference(User.CustomPreference pref) => - new(pref.Icon, pref.Tooltip, pref.Muted, pref.Favourite, pref.Size); - - public static Dictionary RenderCustomPreferences( - User user - ) => - user.CustomPreferences.Select(x => (x.Key, RenderCustomPreference(x.Value))).ToDictionary(); - public PartialUser RenderPartialUser(User user) => new( user.Id, diff --git a/Foxnouns.Backend/Services/V1/MembersV1Service.cs b/Foxnouns.Backend/Services/V1/MembersV1Service.cs deleted file mode 100644 index 632226c..0000000 --- a/Foxnouns.Backend/Services/V1/MembersV1Service.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto.V1; -using Microsoft.EntityFrameworkCore; -using FieldEntry = Foxnouns.Backend.Dto.V1.FieldEntry; -using PrideFlag = Foxnouns.Backend.Dto.V1.PrideFlag; - -namespace Foxnouns.Backend.Services.V1; - -public class MembersV1Service(DatabaseContext db, UsersV1Service usersV1Service) -{ - public async Task ResolveMemberAsync(string id, CancellationToken ct = default) - { - Member? member; - if (Snowflake.TryParse(id, out Snowflake? sf)) - { - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Id == sf && !m.User.Deleted, ct); - if (member != null) - return member; - } - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.LegacyId == id && !m.User.Deleted, ct); - if (member != null) - return member; - - throw new ApiError.NotFound("No member with that ID found.", ErrorCode.MemberNotFound); - } - - public async Task ResolveMemberAsync( - string userRef, - string memberRef, - Token? token, - CancellationToken ct = default - ) - { - User user = await usersV1Service.ResolveUserAsync(userRef, token, ct); - - Member? member; - if (Snowflake.TryParse(memberRef, out Snowflake? sf)) - { - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Id == sf && m.UserId == user.Id, ct); - if (member != null) - return member; - } - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.LegacyId == memberRef && m.UserId == user.Id, ct); - if (member != null) - return member; - - member = await db - .Members.Include(m => m.User) - .FirstOrDefaultAsync(m => m.Name == memberRef && m.UserId == user.Id, ct); - if (member != null) - return member; - - throw new ApiError.NotFound( - "No member with that ID or name found.", - ErrorCode.MemberNotFound - ); - } - - public async Task RenderMemberAsync( - Member m, - Token? token = default, - User? user = null, - bool renderFlags = true, - CancellationToken ct = default - ) - { - user ??= m.User; - bool renderUnlisted = m.UserId == token?.UserId; - - List flags = renderFlags - ? await db.MemberFlags.Where(f => f.MemberId == m.Id).OrderBy(f => f.Id).ToListAsync(ct) - : []; - - return new MemberResponse( - m.LegacyId, - m.Id, - m.Sid, - m.Name, - m.DisplayName, - m.Bio, - m.Avatar, - m.Links, - Names: FieldEntry.FromEntries(m.Names, user.CustomPreferences), - Pronouns: PronounEntry.FromPronouns(m.Pronouns, user.CustomPreferences), - Fields: ProfileField.FromFields(m.Fields, user.CustomPreferences), - Flags: flags - .Where(f => f.PrideFlag.Hash != null) - .Select(f => new PrideFlag( - f.PrideFlag.LegacyId, - f.PrideFlag.Id, - f.PrideFlag.Hash!, - f.PrideFlag.Name, - f.PrideFlag.Description - )) - .ToArray(), - User: UsersV1Service.RenderPartialUser(user), - Unlisted: renderUnlisted ? m.Unlisted : null - ); - } -} diff --git a/Foxnouns.Backend/Services/V1/UsersV1Service.cs b/Foxnouns.Backend/Services/V1/UsersV1Service.cs deleted file mode 100644 index 1f2ad79..0000000 --- a/Foxnouns.Backend/Services/V1/UsersV1Service.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using Foxnouns.Backend.Database; -using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Dto.V1; -using Microsoft.EntityFrameworkCore; -using FieldEntry = Foxnouns.Backend.Dto.V1.FieldEntry; -using PrideFlag = Foxnouns.Backend.Dto.V1.PrideFlag; - -namespace Foxnouns.Backend.Services.V1; - -public class UsersV1Service(DatabaseContext db) -{ - public async Task ResolveUserAsync( - string userRef, - Token? token, - CancellationToken ct = default - ) - { - if (userRef == "@me") - { - if (token == null) - { - throw new ApiError.Unauthorized( - "This endpoint requires an authenticated user.", - ErrorCode.AuthenticationRequired - ); - } - - return await db.Users.FirstAsync(u => u.Id == token.UserId, ct); - } - - User? user; - if (Snowflake.TryParse(userRef, out Snowflake? sf)) - { - user = await db.Users.FirstOrDefaultAsync(u => u.Id == sf && !u.Deleted, ct); - if (user != null) - return user; - } - - user = await db.Users.FirstOrDefaultAsync(u => u.LegacyId == userRef && !u.Deleted, ct); - if (user != null) - return user; - - user = await db.Users.FirstOrDefaultAsync(u => u.Username == userRef && !u.Deleted, ct); - if (user != null) - return user; - - throw new ApiError.NotFound( - "No user with that ID or username found.", - ErrorCode.UserNotFound - ); - } - - public async Task RenderUserAsync( - User user, - Token? token = null, - bool renderMembers = true, - bool renderFlags = true, - CancellationToken ct = default - ) - { - bool isSelfUser = user.Id == token?.UserId; - renderMembers = renderMembers && (isSelfUser || !user.ListHidden); - - // Only fetch members if we're rendering members (duh) - List members = renderMembers - ? await db.Members.Where(m => m.UserId == user.Id).OrderBy(m => m.Name).ToListAsync(ct) - : []; - - List flags = renderFlags - ? await db.UserFlags.Where(f => f.UserId == user.Id).OrderBy(f => f.Id).ToListAsync(ct) - : []; - - int? utcOffset = null; - if ( - user.Timezone != null - && TimeZoneInfo.TryFindSystemTimeZoneById(user.Timezone, out TimeZoneInfo? tz) - ) - { - utcOffset = (int)tz.GetUtcOffset(DateTimeOffset.UtcNow).TotalSeconds; - } - - return new UserResponse( - user.LegacyId, - user.Id, - user.Sid, - user.Username, - user.DisplayName, - user.Bio, - user.MemberTitle, - user.Avatar, - user.Links, - Names: FieldEntry.FromEntries(user.Names, user.CustomPreferences), - Pronouns: PronounEntry.FromPronouns(user.Pronouns, user.CustomPreferences), - Fields: ProfileField.FromFields(user.Fields, user.CustomPreferences), - Flags: flags - .Where(f => f.PrideFlag.Hash != null) - .Select(f => new PrideFlag( - f.PrideFlag.LegacyId, - f.PrideFlag.Id, - f.PrideFlag.Hash!, - f.PrideFlag.Name, - f.PrideFlag.Description - )) - .ToArray(), - Members: members.Select(m => RenderPartialMember(m, user.CustomPreferences)).ToArray(), - utcOffset, - CustomPreferences: RenderCustomPreferences(user.CustomPreferences) - ); - } - - public async Task RenderCurrentUserAsync( - User user, - CancellationToken ct = default - ) - { - List members = await db - .Members.Where(m => m.UserId == user.Id) - .OrderBy(m => m.Name) - .ToListAsync(ct); - - List flags = await db - .UserFlags.Where(f => f.UserId == user.Id) - .OrderBy(f => f.Id) - .ToListAsync(ct); - - int? utcOffset = null; - if ( - user.Timezone != null - && TimeZoneInfo.TryFindSystemTimeZoneById(user.Timezone, out TimeZoneInfo? tz) - ) - { - utcOffset = (int)tz.GetUtcOffset(DateTimeOffset.UtcNow).TotalSeconds; - } - - List authMethods = await db - .AuthMethods.Include(a => a.FediverseApplication) - .Where(a => a.UserId == user.Id) - .OrderBy(a => a.Id) - .ToListAsync(ct); - - AuthMethod? discord = authMethods.FirstOrDefault(a => a.AuthType is AuthType.Discord); - AuthMethod? google = authMethods.FirstOrDefault(a => a.AuthType is AuthType.Google); - AuthMethod? tumblr = authMethods.FirstOrDefault(a => a.AuthType is AuthType.Tumblr); - AuthMethod? fediverse = authMethods.FirstOrDefault(a => a.AuthType is AuthType.Fediverse); - - return new CurrentUserResponse( - user.LegacyId, - user.Id, - user.Sid, - user.Username, - user.DisplayName, - user.Bio, - user.MemberTitle, - user.Avatar, - user.Links, - Names: FieldEntry.FromEntries(user.Names, user.CustomPreferences), - Pronouns: PronounEntry.FromPronouns(user.Pronouns, user.CustomPreferences), - Fields: ProfileField.FromFields(user.Fields, user.CustomPreferences), - Flags: flags - .Where(f => f.PrideFlag.Hash != null) - .Select(f => new PrideFlag( - f.PrideFlag.LegacyId, - f.PrideFlag.Id, - f.PrideFlag.Hash!, - f.PrideFlag.Name, - f.PrideFlag.Description - )) - .ToArray(), - Members: members.Select(m => RenderPartialMember(m, user.CustomPreferences)).ToArray(), - utcOffset, - CustomPreferences: RenderCustomPreferences(user.CustomPreferences), - user.Id.Time, - user.Timezone, - user.Role is UserRole.Admin, - user.ListHidden, - user.LastSidReroll, - discord?.RemoteId, - discord?.RemoteUsername, - google?.RemoteId, - google?.RemoteUsername, - tumblr?.RemoteId, - tumblr?.RemoteUsername, - fediverse?.RemoteId, - fediverse?.RemoteUsername, - fediverse?.FediverseApplication?.Domain - ); - } - - private static Dictionary RenderCustomPreferences( - Dictionary customPreferences - ) => - customPreferences - .Select(x => - ( - x.Value.LegacyId, - new CustomPreference( - x.Value.Icon, - x.Value.Tooltip, - x.Value.Size, - x.Value.Muted, - x.Value.Favourite - ) - ) - ) - .ToDictionary(); - - private static PartialMember RenderPartialMember( - Member m, - Dictionary customPreferences - ) => - new( - m.LegacyId, - m.Id, - m.Sid, - m.Name, - m.DisplayName, - m.Bio, - m.Avatar, - m.Links, - Names: FieldEntry.FromEntries(m.Names, customPreferences), - Pronouns: PronounEntry.FromPronouns(m.Pronouns, customPreferences) - ); - - public static PartialUser RenderPartialUser(User user) => - new( - user.LegacyId, - user.Id, - user.Username, - user.DisplayName, - user.Avatar, - CustomPreferences: RenderCustomPreferences(user.CustomPreferences) - ); -} diff --git a/Foxnouns.Backend/Services/ValidationService.Strings.cs b/Foxnouns.Backend/Services/ValidationService.Strings.cs deleted file mode 100644 index 9244ed4..0000000 --- a/Foxnouns.Backend/Services/ValidationService.Strings.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -using System.Text.RegularExpressions; - -namespace Foxnouns.Backend.Services; - -public partial class ValidationService -{ - private static readonly string[] InvalidUsernames = - [ - "..", - "admin", - "administrator", - "mod", - "moderator", - "api", - "page", - "pronouns", - "settings", - "pronouns.cc", - "pronounscc", - "null", - ]; - - private static readonly string[] InvalidMemberNames = - [ - // these break routing outright - ".", - "..", - // TODO: remove this? i'm not sure if /@[username]/edit will redirect to settings - "edit", - // this breaks the frontend, somehow - "null", - ]; - - public ValidationError? ValidateUsername(string username) - { - if (!UsernameRegex().IsMatch(username)) - { - if (username.Length < 2) - { - return ValidationError.LengthError( - "Username is too short", - 2, - _limits.MaxUsernameLength, - username.Length - ); - } - - if (username.Length > _limits.MaxUsernameLength) - { - return ValidationError.LengthError( - "Username is too long", - 2, - _limits.MaxUsernameLength, - username.Length - ); - } - - return ValidationError.GenericValidationError( - "Username is invalid, can only contain alphanumeric characters, dashes, underscores, and periods", - username - ); - } - - if ( - InvalidUsernames.Any(u => - string.Equals(u, username, StringComparison.InvariantCultureIgnoreCase) - ) - ) - { - return ValidationError.GenericValidationError("Username is not allowed", username); - } - - return null; - } - - public ValidationError? ValidateMemberName(string memberName) - { - if (!MemberRegex().IsMatch(memberName)) - { - if (memberName.Length < 1) - { - return ValidationError.LengthError( - "Name is too short", - 1, - _limits.MaxMemberNameLength, - memberName.Length - ); - } - - if (memberName.Length > _limits.MaxMemberNameLength) - { - return ValidationError.LengthError( - "Name is too long", - 1, - _limits.MaxMemberNameLength, - memberName.Length - ); - } - - return ValidationError.GenericValidationError( - "Member name cannot contain any of the following: " - + " @, ?, !, #, /, \\, [, ], \", ', $, %, &, (, ), {, }, +, <, =, >, ^, |, ~, `, , " - + "and cannot be one or two periods", - memberName - ); - } - - if ( - InvalidMemberNames.Any(u => - string.Equals(u, memberName, StringComparison.InvariantCultureIgnoreCase) - ) - ) - { - return ValidationError.GenericValidationError("Name is not allowed", memberName); - } - - return null; - } - - public ValidationError? ValidateDisplayName(string? displayName) - { - if (displayName?.Length == 0) - { - return ValidationError.LengthError( - "Display name is too short", - 1, - _limits.MaxDisplayNameLength, - displayName.Length - ); - } - - if (displayName?.Length > _limits.MaxDisplayNameLength) - { - return ValidationError.LengthError( - "Display name is too long", - 1, - _limits.MaxDisplayNameLength, - displayName.Length - ); - } - - return null; - } - - public IEnumerable<(string, ValidationError?)> ValidateLinks(string[]? links) - { - if (links == null) - return []; - if (links.Length > _limits.MaxLinks) - { - return - [ - ( - "links", - ValidationError.LengthError("Too many links", 0, _limits.MaxLinks, links.Length) - ), - ]; - } - - var errors = new List<(string, ValidationError?)>(); - foreach ((string link, int idx) in links.Select((l, i) => (l, i))) - { - if (link.Length == 0) - { - errors.Add( - ( - $"links.{idx}", - ValidationError.LengthError( - "Link cannot be empty", - 1, - _limits.MaxLinkLength, - 0 - ) - ) - ); - } - else if (link.Length > _limits.MaxLinkLength) - { - errors.Add( - ( - $"links.{idx}", - ValidationError.LengthError( - "Link is too long", - 1, - _limits.MaxLinkLength, - link.Length - ) - ) - ); - } - } - - return errors; - } - - public ValidationError? ValidateBio(string? bio) - { - if (bio?.Length == 0) - { - return ValidationError.LengthError( - "Bio is too short", - 1, - _limits.MaxBioLength, - bio.Length - ); - } - - if (bio?.Length > _limits.MaxBioLength) - { - return ValidationError.LengthError( - "Bio is too long", - 1, - _limits.MaxBioLength, - bio.Length - ); - } - - return null; - } - - public ValidationError? ValidateAvatar(string? avatar) - { - if (avatar?.Length == 0) - { - return ValidationError.GenericValidationError("Avatar cannot be empty", null); - } - - if (avatar?.Length > _limits.MaxAvatarLength) - { - return ValidationError.GenericValidationError("Avatar is too large", null); - } - - return null; - } - - [GeneratedRegex(@"^[a-zA-Z_0-9\-\.]{2,40}$", RegexOptions.IgnoreCase, "en-US")] - private static partial Regex UsernameRegex(); - - [GeneratedRegex( - """^[^@'$%&()+<=>^|~`,*!#/\\\[\]""\{\}\?]{1,100}$""", - RegexOptions.IgnoreCase, - "en-US" - )] - private static partial Regex MemberRegex(); -} diff --git a/Foxnouns.Backend/Services/ValidationService.cs b/Foxnouns.Backend/Services/ValidationService.cs deleted file mode 100644 index 989f469..0000000 --- a/Foxnouns.Backend/Services/ValidationService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Foxnouns.Backend.Services; - -public partial class ValidationService(Config config) -{ - private readonly Config.LimitsConfig _limits = config.Limits; -} diff --git a/Foxnouns.Backend/Utils/AuthUtils.cs b/Foxnouns.Backend/Utils/AuthUtils.cs index d57eb73..2ce46e2 100644 --- a/Foxnouns.Backend/Utils/AuthUtils.cs +++ b/Foxnouns.Backend/Utils/AuthUtils.cs @@ -135,7 +135,7 @@ public static class AuthUtils Convert.ToBase64String(RandomNumberGenerator.GetBytes(bytes)).Trim('='); public static string RandomToken(int bytes = 48) => - RandomUrlUnsafeToken(bytes) + RandomUrlUnsafeToken() // Make the token URL-safe .Replace('+', '-') .Replace('/', '_'); diff --git a/Foxnouns.Backend/Utils/Limits.cs b/Foxnouns.Backend/Utils/Limits.cs new file mode 100644 index 0000000..3010d46 --- /dev/null +++ b/Foxnouns.Backend/Utils/Limits.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2023-present sam/u1f320 (vulpine.solutions) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +namespace Foxnouns.Backend.Utils; + +public static class Limits +{ + public const int FieldLimit = 25; + public const int FieldNameLimit = 100; + public const int FieldEntryTextLimit = 100; + public const int FieldEntriesLimit = 100; +} diff --git a/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs b/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs index 9835b50..92c1f7c 100644 --- a/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs +++ b/Foxnouns.Backend/Utils/OpenApi/PropertyKeySchemaTransformer.cs @@ -22,10 +22,8 @@ namespace Foxnouns.Backend.Utils.OpenApi; public class PropertyKeySchemaTransformer : IOpenApiSchemaTransformer { - private static readonly DefaultContractResolver SnakeCaseConverter = new() - { - NamingStrategy = new SnakeCaseNamingStrategy(), - }; + private static readonly DefaultContractResolver SnakeCaseConverter = + new() { NamingStrategy = new SnakeCaseNamingStrategy() }; public Task TransformAsync( OpenApiSchema schema, diff --git a/Foxnouns.Backend/Services/ValidationService.Fields.cs b/Foxnouns.Backend/Utils/ValidationUtils.Fields.cs similarity index 56% rename from Foxnouns.Backend/Services/ValidationService.Fields.cs rename to Foxnouns.Backend/Utils/ValidationUtils.Fields.cs index e2cbff3..0235eb6 100644 --- a/Foxnouns.Backend/Services/ValidationService.Fields.cs +++ b/Foxnouns.Backend/Utils/ValidationUtils.Fields.cs @@ -15,9 +15,9 @@ using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; -namespace Foxnouns.Backend.Services; +namespace Foxnouns.Backend.Utils; -public partial class ValidationService +public static partial class ValidationUtils { public static readonly string[] DefaultStatusOptions = [ @@ -28,7 +28,7 @@ public partial class ValidationService "avoid", ]; - public IEnumerable<(string, ValidationError?)> ValidateFields( + public static IEnumerable<(string, ValidationError?)> ValidateFields( List? fields, IReadOnlyDictionary customPreferences ) @@ -37,7 +37,7 @@ public partial class ValidationService return []; var errors = new List<(string, ValidationError?)>(); - if (fields.Count > _limits.MaxFields) + if (fields.Count > 25) { errors.Add( ( @@ -45,7 +45,7 @@ public partial class ValidationService ValidationError.LengthError( "Too many fields", 0, - _limits.MaxFields, + Limits.FieldLimit, fields.Count ) ) @@ -53,38 +53,39 @@ public partial class ValidationService } // No overwhelming this function, thank you - if (fields.Count > _limits.MaxFields + 50) + if (fields.Count > 100) return errors; foreach ((Field? field, int index) in fields.Select((field, index) => (field, index))) { - if (field.Name.Length > _limits.MaxFieldNameLength) + switch (field.Name.Length) { - errors.Add( - ( - $"fields.{index}.name", - ValidationError.LengthError( - "Field name is too long", - 1, - _limits.MaxFieldNameLength, - field.Name.Length + case > Limits.FieldNameLimit: + errors.Add( + ( + $"fields.{index}.name", + ValidationError.LengthError( + "Field name is too long", + 1, + Limits.FieldNameLimit, + field.Name.Length + ) ) - ) - ); - } - else if (field.Name.Length < 1) - { - errors.Add( - ( - $"fields.{index}.name", - ValidationError.LengthError( - "Field name is too short", - 1, - _limits.MaxFieldNameLength, - field.Name.Length + ); + break; + case < 1: + errors.Add( + ( + $"fields.{index}.name", + ValidationError.LengthError( + "Field name is too short", + 1, + Limits.FieldNameLimit, + field.Name.Length + ) ) - ) - ); + ); + break; } errors = errors @@ -101,7 +102,7 @@ public partial class ValidationService return errors; } - public IEnumerable<(string, ValidationError?)> ValidateFieldEntries( + public static IEnumerable<(string, ValidationError?)> ValidateFieldEntries( FieldEntry[]? entries, IReadOnlyDictionary customPreferences, string errorPrefix = "fields" @@ -111,7 +112,7 @@ public partial class ValidationService return []; var errors = new List<(string, ValidationError?)>(); - if (entries.Length > _limits.MaxFieldEntries) + if (entries.Length > Limits.FieldEntriesLimit) { errors.Add( ( @@ -119,7 +120,7 @@ public partial class ValidationService ValidationError.LengthError( "Field has too many entries", 0, - _limits.MaxFieldEntries, + Limits.FieldEntriesLimit, entries.Length ) ) @@ -127,7 +128,7 @@ public partial class ValidationService } // Same as above, no overwhelming this function with a ridiculous amount of entries - if (entries.Length > _limits.MaxFieldEntries + 50) + if (entries.Length > Limits.FieldEntriesLimit + 50) return errors; string[] customPreferenceIds = customPreferences.Keys.Select(id => id.ToString()).ToArray(); @@ -138,33 +139,34 @@ public partial class ValidationService ) ) { - if (entry.Value.Length > _limits.MaxFieldEntryTextLength) + switch (entry.Value.Length) { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.value", - ValidationError.LengthError( - "Field value is too long", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + case > Limits.FieldEntryTextLimit: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.value", + ValidationError.LengthError( + "Field value is too long", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); - } - else if (entry.Value.Length < 1) - { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.value", - ValidationError.LengthError( - "Field value is too short", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + ); + break; + case < 1: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.value", + ValidationError.LengthError( + "Field value is too short", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); + ); + break; } if ( @@ -184,7 +186,7 @@ public partial class ValidationService return errors; } - public IEnumerable<(string, ValidationError?)> ValidatePronouns( + public static IEnumerable<(string, ValidationError?)> ValidatePronouns( Pronoun[]? entries, IReadOnlyDictionary customPreferences, string errorPrefix = "pronouns" @@ -194,7 +196,7 @@ public partial class ValidationService return []; var errors = new List<(string, ValidationError?)>(); - if (entries.Length > _limits.MaxFieldEntries) + if (entries.Length > Limits.FieldEntriesLimit) { errors.Add( ( @@ -202,7 +204,7 @@ public partial class ValidationService ValidationError.LengthError( "Too many pronouns", 0, - _limits.MaxFieldEntries, + Limits.FieldEntriesLimit, entries.Length ) ) @@ -210,7 +212,7 @@ public partial class ValidationService } // Same as above, no overwhelming this function with a ridiculous amount of entries - if (entries.Length > _limits.MaxFieldEntries + 50) + if (entries.Length > Limits.FieldEntriesLimit + 50) return errors; string[] customPreferenceIds = customPreferences.Keys.Select(id => id.ToString()).ToArray(); @@ -219,64 +221,66 @@ public partial class ValidationService (Pronoun? entry, int entryIdx) in entries.Select((entry, entryIdx) => (entry, entryIdx)) ) { - if (entry.Value.Length > _limits.MaxFieldEntryTextLength) + switch (entry.Value.Length) { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.value", - ValidationError.LengthError( - "Pronoun value is too long", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + case > Limits.FieldEntryTextLimit: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.value", + ValidationError.LengthError( + "Pronoun value is too long", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); - } - else if (entry.Value.Length < 1) - { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.value", - ValidationError.LengthError( - "Pronoun value is too short", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + ); + break; + case < 1: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.value", + ValidationError.LengthError( + "Pronoun value is too short", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); + ); + break; } if (entry.DisplayText != null) { - if (entry.DisplayText.Length > _limits.MaxFieldEntryTextLength) + switch (entry.DisplayText.Length) { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.display_text", - ValidationError.LengthError( - "Pronoun display text is too long", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + case > Limits.FieldEntryTextLimit: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.display_text", + ValidationError.LengthError( + "Pronoun display text is too long", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); - } - else if (entry.DisplayText.Length < 1) - { - errors.Add( - ( - $"{errorPrefix}.{entryIdx}.display_text", - ValidationError.LengthError( - "Pronoun display text is too short", - 1, - _limits.MaxFieldEntryTextLength, - entry.Value.Length + ); + break; + case < 1: + errors.Add( + ( + $"{errorPrefix}.{entryIdx}.display_text", + ValidationError.LengthError( + "Pronoun display text is too short", + 1, + Limits.FieldEntryTextLimit, + entry.Value.Length + ) ) - ) - ); + ); + break; } } diff --git a/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs b/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs index 82ee485..ea12043 100644 --- a/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs +++ b/Foxnouns.Backend/Utils/ValidationUtils.Strings.cs @@ -12,16 +12,189 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +using System.Text.RegularExpressions; + namespace Foxnouns.Backend.Utils; public static partial class ValidationUtils { - public const int MaximumReportContextLength = 512; + private static readonly string[] InvalidUsernames = + [ + "..", + "admin", + "administrator", + "mod", + "moderator", + "api", + "page", + "pronouns", + "settings", + "pronouns.cc", + "pronounscc", + ]; - public static ValidationError? ValidateReportContext(string? context) => - context?.Length > MaximumReportContextLength - ? ValidationError.GenericValidationError("Report context is too long", null) - : null; + private static readonly string[] InvalidMemberNames = + [ + // these break routing outright + ".", + "..", + // the user edit page lives at `/@{username}/edit`, so a member named "edit" would be inaccessible + "edit", + ]; + + public static ValidationError? ValidateUsername(string username) + { + if (!UsernameRegex().IsMatch(username)) + { + return username.Length switch + { + < 2 => ValidationError.LengthError("Username is too short", 2, 40, username.Length), + > 40 => ValidationError.LengthError("Username is too long", 2, 40, username.Length), + _ => ValidationError.GenericValidationError( + "Username is invalid, can only contain alphanumeric characters, dashes, underscores, and periods", + username + ), + }; + } + + if ( + InvalidUsernames.Any(u => + string.Equals(u, username, StringComparison.InvariantCultureIgnoreCase) + ) + ) + { + return ValidationError.GenericValidationError("Username is not allowed", username); + } + + return null; + } + + public static ValidationError? ValidateMemberName(string memberName) + { + if (!MemberRegex().IsMatch(memberName)) + { + return memberName.Length switch + { + < 1 => ValidationError.LengthError("Name is too short", 1, 100, memberName.Length), + > 100 => ValidationError.LengthError("Name is too long", 1, 100, memberName.Length), + _ => ValidationError.GenericValidationError( + "Member name cannot contain any of the following: " + + " @, ?, !, #, /, \\, [, ], \", ', $, %, &, (, ), {, }, +, <, =, >, ^, |, ~, `, , " + + "and cannot be one or two periods", + memberName + ), + }; + } + + if ( + InvalidMemberNames.Any(u => + string.Equals(u, memberName, StringComparison.InvariantCultureIgnoreCase) + ) + ) + { + return ValidationError.GenericValidationError("Name is not allowed", memberName); + } + + return null; + } + + public static ValidationError? ValidateDisplayName(string? displayName) + { + return displayName?.Length switch + { + 0 => ValidationError.LengthError( + "Display name is too short", + 1, + 100, + displayName.Length + ), + > 100 => ValidationError.LengthError( + "Display name is too long", + 1, + 100, + displayName.Length + ), + _ => null, + }; + } + + private const int MaxLinks = 25; + private const int MaxLinkLength = 256; + + public static IEnumerable<(string, ValidationError?)> ValidateLinks(string[]? links) + { + if (links == null) + return []; + if (links.Length > MaxLinks) + { + return + [ + ("links", ValidationError.LengthError("Too many links", 0, MaxLinks, links.Length)), + ]; + } + + var errors = new List<(string, ValidationError?)>(); + foreach ((string link, int idx) in links.Select((l, i) => (l, i))) + { + switch (link.Length) + { + case 0: + errors.Add( + ( + $"links.{idx}", + ValidationError.LengthError("Link cannot be empty", 1, 256, 0) + ) + ); + break; + case > MaxLinkLength: + errors.Add( + ( + $"links.{idx}", + ValidationError.LengthError( + "Link is too long", + 1, + MaxLinkLength, + link.Length + ) + ) + ); + break; + } + } + + return errors; + } + + public const int MaxBioLength = 1024; + public const int MaxAvatarLength = 1_500_000; + + public static ValidationError? ValidateBio(string? bio) + { + return bio?.Length switch + { + 0 => ValidationError.LengthError("Bio is too short", 1, MaxBioLength, bio.Length), + > MaxBioLength => ValidationError.LengthError( + "Bio is too long", + 1, + MaxBioLength, + bio.Length + ), + _ => null, + }; + } + + public static ValidationError? ValidateAvatar(string? avatar) + { + return avatar?.Length switch + { + 0 => ValidationError.GenericValidationError("Avatar cannot be empty", null), + > MaxAvatarLength => ValidationError.GenericValidationError( + "Avatar is too large", + null + ), + _ => null, + }; + } public const int MinimumPasswordLength = 12; public const int MaximumPasswordLength = 1024; @@ -43,4 +216,14 @@ public static partial class ValidationUtils ), _ => null, }; + + [GeneratedRegex(@"^[a-zA-Z_0-9\-\.]{2,40}$", RegexOptions.IgnoreCase, "en-NL")] + private static partial Regex UsernameRegex(); + + [GeneratedRegex( + """^[^@'$%&()+<=>^|~`,*!#/\\\[\]""\{\}\?]{1,100}$""", + RegexOptions.IgnoreCase, + "en-NL" + )] + private static partial Regex MemberRegex(); } diff --git a/Foxnouns.Backend/config.example.ini b/Foxnouns.Backend/config.example.ini index 4d7c17c..7522cba 100644 --- a/Foxnouns.Backend/config.example.ini +++ b/Foxnouns.Backend/config.example.ini @@ -1,7 +1,7 @@ ; The host the server will listen on Host = localhost ; The port the server will listen on -Port = 6000 +Port = 5000 ; The base *external* URL BaseUrl = https://pronouns.localhost ; The base URL for media, without a trailing slash. This must be publicly accessible. @@ -43,9 +43,6 @@ AccessKey = SecretKey = Bucket = pronounscc -[Limits] -MaxMemberCount = 5000 - [EmailAuth] ; The address that emails will be sent from. If not set, email auth is disabled. From = noreply@accounts.pronouns.cc diff --git a/Foxnouns.Backend/packages.lock.json b/Foxnouns.Backend/packages.lock.json index 365ee8c..5f1b968 100644 --- a/Foxnouns.Backend/packages.lock.json +++ b/Foxnouns.Backend/packages.lock.json @@ -4,9 +4,9 @@ "net9.0": { "Coravel": { "type": "Direct", - "requested": "[6.0.2, )", - "resolved": "6.0.2", - "contentHash": "/XZiRId4Ilar/OqjGKdxkZWfW97ekeT0wgiWNjGdqf8pPxiK508//Zkc0xrKMDOqchFT7B/oqAoQ+Vrx1txpPQ==", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "U16V/IxGL2TcpU9sT1gUA3pqoVIlz+WthC4idn8OTPiEtLElTcmNF6sHt+gOx8DRU8TBgN5vjfL4AHetjacOWQ==", "dependencies": { "Microsoft.Extensions.Caching.Memory": "3.1.0", "Microsoft.Extensions.Configuration.Binder": "6.0.0", @@ -17,12 +17,12 @@ }, "Coravel.Mailer": { "type": "Direct", - "requested": "[7.1.0, )", - "resolved": "7.1.0", - "contentHash": "yMbUrwKl5/HbJeX8JkHa8Q3CPTJ3OmPyDSG7sULbXGEhzc2GiYIh7pmVhI1FFeL3VUtFavMDkS8PTwEeCpiwlg==", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "mxSlOOBxPjCAZruOpgXtubnZA9lD0DRgutApQmAsts7DoRfe0wTzqWrYjeZTiIzgVJZKZxJglN8duTvbPrw3jQ==", "dependencies": { - "MailKit": "4.8.0", - "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": "6.0.36" + "MailKit": "4.3.0", + "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": "6.0.27" } }, "EFCore.NamingConventions": { @@ -46,37 +46,6 @@ "Npgsql": "8.0.3" } }, - "Hangfire": { - "type": "Direct", - "requested": "[1.8.18, )", - "resolved": "1.8.18", - "contentHash": "EY+UqMHTOQAtdjeJf3jlnj8MpENyDPTpA6OHMncucVlkaongZjrx+gCN4bgma7vD3BNHqfQ7irYrfE5p1DOBEQ==", - "dependencies": { - "Hangfire.AspNetCore": "[1.8.18]", - "Hangfire.Core": "[1.8.18]", - "Hangfire.SqlServer": "[1.8.18]" - } - }, - "Hangfire.Core": { - "type": "Direct", - "requested": "[1.8.18, )", - "resolved": "1.8.18", - "contentHash": "oNAkV8QQoYg5+vM2M024NBk49EhTO2BmKDLuQaKNew23RpH9OUGtKDl1KldBdDJrD8TMFzjhWCArol3igd2i2w==", - "dependencies": { - "Newtonsoft.Json": "11.0.1" - } - }, - "Hangfire.Redis.StackExchange": { - "type": "Direct", - "requested": "[1.9.4, )", - "resolved": "1.9.4", - "contentHash": "rB4eGf4+hFhdnrN3//2O39JGuy1ThIKL3oTdVI2F3HqmSaSD9Cixl2xmMAqGJMld39Ke7eoP9sxbxnpVnYW66g==", - "dependencies": { - "Hangfire.Core": "1.8.7", - "Newtonsoft.Json": "13.0.3", - "StackExchange.Redis": "2.7.10" - } - }, "Humanizer.Core": { "type": "Direct", "requested": "[2.14.1, )", @@ -91,41 +60,41 @@ }, "Microsoft.AspNetCore.Mvc.NewtonsoftJson": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "cCnaxji6nqIHHLAEhZ6QirXCvwJNi0Q/qCPLkRW5SqMYNuOwoQdGk1KAhW65phBq1VHGt7wLbadpuGPGqfiZuA==", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "pTFDEmZi3GheCSPrBxzyE63+d5unln2vYldo/nOm1xet/4rpEk2oJYcwpclPQ13E+LZBF9XixkgwYTUwqznlWg==", "dependencies": { - "Microsoft.AspNetCore.JsonPatch": "9.0.2", + "Microsoft.AspNetCore.JsonPatch": "9.0.0", "Newtonsoft.Json": "13.0.3", "Newtonsoft.Json.Bson": "1.0.2" } }, "Microsoft.AspNetCore.OpenApi": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "JUndpjRNdG8GvzBLH/J4hen4ehWaPcshtiQ6+sUs1Bcj3a7dOsmWpDloDlpPeMOVSlhHwUJ3Xld0ClZjsFLgFQ==", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "FqUK5j1EOPNuFT7IafltZQ3cakqhSwVzH5ZW1MhZDe4pPXs9sJ2M5jom1Omsu+mwF2tNKKlRAzLRHQTZzbd+6Q==", "dependencies": { "Microsoft.OpenApi": "1.6.17" } }, "Microsoft.EntityFrameworkCore": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "P90ZuybgcpW32y985eOYxSoZ9IiL0UTYQlY0y1Pt1iHAnpZj/dQHREpSpry1RNvk8YjAeoAkWFdem5conqB9zQ==", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "wpG+nfnfDAw87R3ovAsUmjr3MZ4tYXf6bFqEPVAIKE6IfPml3DS//iX0DBnf8kWn5ZHSO5oi1m4d/Jf+1LifJQ==", "dependencies": { - "Microsoft.EntityFrameworkCore.Abstractions": "9.0.2", - "Microsoft.EntityFrameworkCore.Analyzers": "9.0.2", - "Microsoft.Extensions.Caching.Memory": "9.0.2", - "Microsoft.Extensions.Logging": "9.0.2" + "Microsoft.EntityFrameworkCore.Abstractions": "9.0.0", + "Microsoft.EntityFrameworkCore.Analyzers": "9.0.0", + "Microsoft.Extensions.Caching.Memory": "9.0.0", + "Microsoft.Extensions.Logging": "9.0.0" } }, "Microsoft.EntityFrameworkCore.Design": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "WWRmTxb/yd05cTW+k32lLvIhffxilgYvwKHDxiqe7GRLKeceyMspuf5BRpW65sFF7S2G+Be9JgjUe1ypGqt9tg==", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "Pqo8I+yHJ3VQrAoY0hiSncf+5P7gN/RkNilK5e+/K/yKh+yAWxdUAI6t0TG26a9VPlCa9FhyklzyFvRyj3YG9A==", "dependencies": { "Humanizer.Core": "2.14.1", "Microsoft.Build.Framework": "17.8.3", @@ -133,45 +102,33 @@ "Microsoft.CodeAnalysis.CSharp": "4.8.0", "Microsoft.CodeAnalysis.CSharp.Workspaces": "4.8.0", "Microsoft.CodeAnalysis.Workspaces.MSBuild": "4.8.0", - "Microsoft.EntityFrameworkCore.Relational": "9.0.2", - "Microsoft.Extensions.Caching.Memory": "9.0.2", - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.DependencyModel": "9.0.2", - "Microsoft.Extensions.Logging": "9.0.2", + "Microsoft.EntityFrameworkCore.Relational": "9.0.0", + "Microsoft.Extensions.Caching.Memory": "9.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "9.0.0", + "Microsoft.Extensions.DependencyModel": "9.0.0", + "Microsoft.Extensions.Logging": "9.0.0", "Mono.TextTemplating": "3.0.0", - "System.Text.Json": "9.0.2" + "System.Text.Json": "9.0.0" } }, "Microsoft.Extensions.Caching.Memory": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "AlEfp0DMz8E1h1Exi8LBrUCNmCYcGDfSM4F/uK1D1cYx/R3w0LVvlmjICqxqXTsy7BEZaCf5leRZY2FuPEiFaw==", + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "zbnPX/JQ0pETRSUG9fNPBvpIq42Aufvs15gGYyNIMhCun9yhmWihz0WgsI7bSDPjxWTKBf8oX/zv6v2uZ3W9OQ==", "dependencies": { - "Microsoft.Extensions.Caching.Abstractions": "9.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2", - "Microsoft.Extensions.Primitives": "9.0.2" - } - }, - "Microsoft.Extensions.Http.Resilience": { - "type": "Direct", - "requested": "[9.2.0, )", - "resolved": "9.2.0", - "contentHash": "Km+YyCuk1IaeOsAzPDygtgsUOh3Fi89hpA18si0tFJmpSBf9aKzP9ffV5j7YOoVDvRWirpumXAPQzk1inBsvKw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "9.0.2", - "Microsoft.Extensions.Http.Diagnostics": "9.2.0", - "Microsoft.Extensions.ObjectPool": "9.0.2", - "Microsoft.Extensions.Resilience": "9.2.0" + "Microsoft.Extensions.Caching.Abstractions": "9.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0", + "Microsoft.Extensions.Primitives": "9.0.0" } }, "MimeKit": { "type": "Direct", - "requested": "[4.10.0, )", - "resolved": "4.10.0", - "contentHash": "GQofI17cH55XSh109hJmHaYMtSFqTX/eUek3UcV7hTnYayAIXZ6eHlv345tfdc+bQ/BrEnYOSZVzx9I3wpvvpg==", + "requested": "[4.9.0, )", + "resolved": "4.9.0", + "contentHash": "DZXXMZzmAABDxFhOSMb6SE8KKxcRd/sk1E6aJTUE5ys2FWOQhznYV2Gl3klaaSfqKn27hQ32haqquH1J8Z6kJw==", "dependencies": { "BouncyCastle.Cryptography": "2.5.0", "System.Formats.Asn1": "8.0.1", @@ -180,11 +137,11 @@ }, "Minio": { "type": "Direct", - "requested": "[6.0.4, )", - "resolved": "6.0.4", - "contentHash": "JckRL95hQ/eDHTQZ/BB7jeR0JyF+bOctMW6uriXHY5YPjCX61hiJGsswGjuDSEViKJEPxtPi3e4IwD/1TJ7PIw==", + "requested": "[6.0.3, )", + "resolved": "6.0.3", + "contentHash": "WHlkouclHtiK/pIXPHcjVmbeELHPtElj2qRSopFVpSmsFhZXeM10sPvczrkSPePsmwuvZdFryJ/hJzKu3XeLVg==", "dependencies": { - "CommunityToolkit.HighPerformance": "8.3.0", + "CommunityToolkit.HighPerformance": "8.2.2", "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.1", "Microsoft.Extensions.Logging": "8.0.0", "System.IO.Hashing": "8.0.0", @@ -199,39 +156,39 @@ }, "NodaTime": { "type": "Direct", - "requested": "[3.2.1, )", - "resolved": "3.2.1", - "contentHash": "D1aHhUfPQUxU2nfDCVuSLahpp0xCYZTmj/KNH3mSK/tStJYcx9HO9aJ0qbOP3hzjGPV/DXOqY2AHe27Nt4xs4g==" + "requested": "[3.2.0, )", + "resolved": "3.2.0", + "contentHash": "yoRA3jEJn8NM0/rQm78zuDNPA3DonNSZdsorMUj+dltc1D+/Lc5h9YXGqbEEZozMGr37lAoYkcSM/KjTVqD0ow==" }, "Npgsql.EntityFrameworkCore.PostgreSQL": { "type": "Direct", - "requested": "[9.0.4, )", - "resolved": "9.0.4", - "contentHash": "mw5vcY2IEc7L+IeGrxpp/J5OSnCcjkjAgJYCm/eD52wpZze8zsSifdqV7zXslSMmfJG2iIUGZyo3KuDtEFKwMQ==", + "requested": "[9.0.2, )", + "resolved": "9.0.2", + "contentHash": "cYdOGplIvr9KgsG8nJ8xnzBTImeircbgetlzS1OmepS5dAQW6PuGpVrLOKBNEwEvGYZPsV8037X5vZ/Dmpwz7Q==", "dependencies": { - "Microsoft.EntityFrameworkCore": "[9.0.1, 10.0.0)", - "Microsoft.EntityFrameworkCore.Relational": "[9.0.1, 10.0.0)", - "Npgsql": "9.0.3" + "Microsoft.EntityFrameworkCore": "[9.0.0, 10.0.0)", + "Microsoft.EntityFrameworkCore.Relational": "[9.0.0, 10.0.0)", + "Npgsql": "9.0.2" } }, "Npgsql.EntityFrameworkCore.PostgreSQL.NodaTime": { "type": "Direct", - "requested": "[9.0.4, )", - "resolved": "9.0.4", - "contentHash": "QZ80CL3c9xzC83eVMWYWa1RcFZA6HJtpMAKFURlmz+1p0OyysSe8R6f/4sI9vk/nwqF6Fkw3lDgku/xH6HcJYg==", + "requested": "[9.0.2, )", + "resolved": "9.0.2", + "contentHash": "+mfwiRCK+CAKTkeBZCuQuMaOwM/yMX8B65515PS1le9TUjlG8DobuAmb48MSR/Pr/YMvU1tV8FFEFlyQviQzrg==", "dependencies": { - "Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.4", - "Npgsql.NodaTime": "9.0.3" + "Npgsql.EntityFrameworkCore.PostgreSQL": "9.0.2", + "Npgsql.NodaTime": "9.0.2" } }, "Npgsql.Json.NET": { "type": "Direct", - "requested": "[9.0.3, )", - "resolved": "9.0.3", - "contentHash": "lN8p9UKkoXaGUhX3DHg/1W6YeEfbjQiQ7XrJSGREUoDHXOLxDQHJnZ49P/9P2s/pH6HTVgTgT5dijpKoRLN0vQ==", + "requested": "[9.0.2, )", + "resolved": "9.0.2", + "contentHash": "E81dvvpNtS4WigxZu16OAFxVvPvbEkXI7vJXZzEp7GQ03MArF5V4HBb7KXDzTaE5ZQ0bhCUFoMTODC6Z8mu27g==", "dependencies": { "Newtonsoft.Json": "13.0.3", - "Npgsql": "9.0.3" + "Npgsql": "9.0.2" } }, "prometheus-net": { @@ -255,24 +212,24 @@ }, "Roslynator.Analyzers": { "type": "Direct", - "requested": "[4.13.1, )", - "resolved": "4.13.1", - "contentHash": "KZpLy6ZlCebMk+d/3I5KU2R7AOb4LNJ6tPJqPtvFXmO8bEBHQvCIAvJOnY2tu4C9/aVOROTDYUFADxFqw1gh/g==" + "requested": "[4.12.9, )", + "resolved": "4.12.9", + "contentHash": "X6lDpN/D5wuinq37KIx+l3GSUe9No+8bCjGBTI5sEEtxapLztkHg6gzNVhMXpXw8P+/5gFYxTXJ5Pf8O4iNz/w==" }, "Scalar.AspNetCore": { "type": "Direct", - "requested": "[2.0.26, )", - "resolved": "2.0.26", - "contentHash": "0tKBFM7quBq0ifgRWo7eTTVpiTbnwpf/6ygtb/aYVuo0D2gMsYknAJRqEhH8HFBqzntNiYpzHbQSf2b+VAA8sA==" + "requested": "[1.2.55, )", + "resolved": "1.2.55", + "contentHash": "zArlr6nfPQMRwyia0WFirsyczQby51GhNgWITiEIRkot+CVGZSGQ4oWGqExO11/6x26G+mcQo9Oft1mGpN0/ZQ==" }, "Sentry.AspNetCore": { "type": "Direct", - "requested": "[5.3.0, )", - "resolved": "5.3.0", - "contentHash": "zC2yhwQB0laYWGXLYDCsiKSIqleaEK3fUH9Z5t8Bgvfs2nGX0mHmh9oPqNAAbkVGvni56mhgHHCBxN/kpfkawA==", + "requested": "[4.13.0, )", + "resolved": "4.13.0", + "contentHash": "1cH9hSvjRbTkcpjUejFTrTC3jMIiOrcZ0DIvt16+AYqXhuxPEnI56npR1nhv+7WUGyhyp5cHFIZqrKnyrrGP0w==", "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "9.0.0", - "Sentry.Extensions.Logging": "5.3.0" + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Sentry.Extensions.Logging": "4.13.0" } }, "Serilog": { @@ -307,35 +264,25 @@ }, "Serilog.Sinks.Seq": { "type": "Direct", - "requested": "[9.0.0, )", - "resolved": "9.0.0", - "contentHash": "aNU8A0K322q7+voPNmp1/qNPH+9QK8xvM1p72sMmCG0wGlshFzmtDW9QnVSoSYCj0MgQKcMOlgooovtBhRlNHw==", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "z5ig56/qzjkX6Fj4U/9m1g8HQaQiYPMZS4Uevtjg1I+WWzoGSf5t/E+6JbMP/jbZYhU63bA5NJN5y0x+qqx2Bw==", "dependencies": { - "Serilog": "4.2.0", - "Serilog.Sinks.File": "6.0.0" + "Serilog": "4.0.0", + "Serilog.Sinks.File": "5.0.0" } }, "SixLabors.ImageSharp": { "type": "Direct", - "requested": "[3.1.7, )", - "resolved": "3.1.7", - "contentHash": "9fIOOAsyLFid6qKypM2Iy0Z3Q9yoanV8VoYAHtI2sYGMNKzhvRTjgFDHonIiVe+ANtxIxM6SuqUzj0r91nItpA==" - }, - "StackExchange.Redis": { - "type": "Direct", - "requested": "[2.8.31, )", - "resolved": "2.8.31", - "contentHash": "RCHVQa9Zke8k0oBgJn1Yl6BuYy8i6kv+sdMObiH60nOwD6QvWAjxdDwOm+LO78E8WsGiPqgOuItkz98fPS6haQ==", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "6.0.0", - "Pipelines.Sockets.Unofficial": "2.2.8" - } + "requested": "[3.1.6, )", + "resolved": "3.1.6", + "contentHash": "dHQ5jugF9v+5/LCVHCWVzaaIL6WOehqJy6eju/0VFYFPEj2WtqkGPoEV9EVQP83dHsdoqYaTuWpZdwAd37UwfA==" }, "System.Text.Json": { "type": "Direct", - "requested": "[9.0.2, )", - "resolved": "9.0.2", - "contentHash": "4TY2Yokh5Xp8XHFhsY9y84yokS7B0rhkaZCXuRiKppIiKwPVH4lVSFD9EEFzRpXdBM5ZeZXD43tc2vB6njEwwQ==" + "requested": "[9.0.0, )", + "resolved": "9.0.0", + "contentHash": "js7+qAu/9mQvnhA4EfGMZNEzXtJCDxgkgj8ohuxq/Qxv+R56G+ljefhiJHOxTNiw54q8vmABCWUwkMulNdlZ4A==" }, "System.Text.RegularExpressions": { "type": "Direct", @@ -346,12 +293,6 @@ "System.Runtime": "4.3.1" } }, - "Yort.Xid.Net": { - "type": "Direct", - "requested": "[2.0.1, )", - "resolved": "2.0.1", - "contentHash": "+3sNX7/RKSKheVuMz9jtWLazD+R4PXpx8va2d9SdDgvKOhETbEb0VYis8K/fD1qm/qOQT57LadToSpzReGMZlw==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.5.0", @@ -359,8 +300,8 @@ }, "CommunityToolkit.HighPerformance": { "type": "Transitive", - "resolved": "8.3.0", - "contentHash": "2zc0Wfr9OtEbLqm6J1Jycim/nKmYv+v12CytJ3tZGNzw7n3yjh1vNCMX0kIBaFBk3sw8g0pMR86QJGXGlArC+A==" + "resolved": "8.2.2", + "contentHash": "+zIp8d3sbtYaRbM6hqDs4Ui/z34j7DcUmleruZlYLE4CVxXq+MO8XJyIs42vzeTYFX+k0Iq1dEbBUnQ4z/Gnrw==" }, "EntityFrameworkCore.Exceptions.Common": { "type": "Transitive", @@ -370,46 +311,18 @@ "Microsoft.EntityFrameworkCore.Relational": "8.0.0" } }, - "Hangfire.AspNetCore": { - "type": "Transitive", - "resolved": "1.8.18", - "contentHash": "5D6Do0qgoAnakvh4KnKwhIoUzFU84Z0sCYMB+Sit+ygkpL1P6JGYDcd/9vDBcfr5K3JqBxD4Zh2IK2LOXuuiaw==", - "dependencies": { - "Hangfire.NetCore": "[1.8.18]" - } - }, - "Hangfire.NetCore": { - "type": "Transitive", - "resolved": "1.8.18", - "contentHash": "3KAV9AZ1nqQHC54qR4buNEEKRmQJfq+lODtZxUk5cdi68lV8+9K2f4H1/mIfDlPpgjPFjEfCobNoi2+TIpKySw==", - "dependencies": { - "Hangfire.Core": "[1.8.18]", - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "3.0.0", - "Microsoft.Extensions.Logging.Abstractions": "3.0.0" - } - }, - "Hangfire.SqlServer": { - "type": "Transitive", - "resolved": "1.8.18", - "contentHash": "yBfI2ygYfN/31rOrahfOFHee1mwTrG0ppsmK9awCS0mAr2GEaB9eyYqg/lURgZy8AA8UVJVs5nLHa2hc1pDAVQ==", - "dependencies": { - "Hangfire.Core": "[1.8.18]" - } - }, "MailKit": { "type": "Transitive", - "resolved": "4.8.0", - "contentHash": "zZ1UoM4FUnSFUJ9fTl5CEEaejR0DNP6+FDt1OfXnjg4igZntcir1tg/8Ufd6WY5vrpmvToAjluYqjVM24A+5lA==", + "resolved": "4.3.0", + "contentHash": "jVmB3Nr0JpqhyMiXOGWMin+QvRKpucGpSFBCav9dG6jEJPdBV+yp1RHVpKzxZPfT+0adaBuZlMFdbIciZo1EWA==", "dependencies": { - "MimeKit": "4.8.0", - "System.Formats.Asn1": "8.0.1" + "MimeKit": "4.3.0" } }, "Microsoft.AspNetCore.JsonPatch": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "bZMRhazEBgw9aZ5EBGYt0017CSd+aecsUCnppVjSa1SzWH6C1ieTSQZRAe+H0DzAVzWAoK7HLwKnQUPioopPrA==", + "resolved": "9.0.0", + "contentHash": "/4UONYoAIeexPoAmbzBPkVGA6KAY7t0BM+1sr0fKss2V1ERCdcM+Llub4X5Ma+LJ60oPp6KzM0e3j+Pp/JHCNw==", "dependencies": { "Microsoft.CSharp": "4.7.0", "Newtonsoft.Json": "13.0.3" @@ -417,27 +330,27 @@ }, "Microsoft.AspNetCore.Mvc.Razor.Extensions": { "type": "Transitive", - "resolved": "6.0.36", - "contentHash": "KFHRhrGAnd80310lpuWzI7Cf+GidS/h3JaPDFFnSmSGjCxB5vkBv5E+TXclJCJhqPtgNxg+keTC5SF1T9ieG5w==", + "resolved": "6.0.27", + "contentHash": "trwJhFrTQuJTImmixMsDnDgRE8zuTzAUAot7WqiUlmjNzlJWLOaXXBpeA/xfNJvZuOsyGjC7RIzEyNyDGhDTLg==", "dependencies": { - "Microsoft.AspNetCore.Razor.Language": "6.0.36", - "Microsoft.CodeAnalysis.Razor": "6.0.36" + "Microsoft.AspNetCore.Razor.Language": "6.0.27", + "Microsoft.CodeAnalysis.Razor": "6.0.27" } }, "Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation": { "type": "Transitive", - "resolved": "6.0.36", - "contentHash": "0OG/wNedsQ9kTMrFuvrUDoJvp6Fxj6BzWgi7AUCluOENxu/0PzbjY9AC5w6mZJ22/AFxn2gFc2m0yOBTfQbiPg==", + "resolved": "6.0.27", + "contentHash": "C6Gh/sAuUACxNtllcH4ZniWtPcGbixJuB1L5RXwoUe1a1wM6rpQ2TVMWpX2+cgeBj8U/izJyWY+nJ4Lz8mmMKA==", "dependencies": { - "Microsoft.AspNetCore.Mvc.Razor.Extensions": "6.0.36", - "Microsoft.CodeAnalysis.Razor": "6.0.36", - "Microsoft.Extensions.DependencyModel": "6.0.2" + "Microsoft.AspNetCore.Mvc.Razor.Extensions": "6.0.27", + "Microsoft.CodeAnalysis.Razor": "6.0.27", + "Microsoft.Extensions.DependencyModel": "6.0.0" } }, "Microsoft.AspNetCore.Razor.Language": { "type": "Transitive", - "resolved": "6.0.36", - "contentHash": "n5Mg5D0aRrhHJJ6bJcwKqQydIFcgUq0jTlvuynoJjwA2IvAzh8Aqf9cpYagofQbIlIXILkCP6q6FgbngyVtpYA==" + "resolved": "6.0.27", + "contentHash": "bI1kIZBgx7oJIB7utPrw4xIgcj7Pdx1jnHMTdsG54U602OcGpBzbfAuKaWs+LVdj+zZVuZsCSoRIZNJKTDP7Hw==" }, "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", @@ -491,10 +404,10 @@ }, "Microsoft.CodeAnalysis.Razor": { "type": "Transitive", - "resolved": "6.0.36", - "contentHash": "RTLNJglWezr/1IkiWdtDpPYW7X7lwa4ow8E35cHt+sWdWxOnl+ayQqMy1RfbaLp7CLmRmgXSzMMZZU3D4vZi9Q==", + "resolved": "6.0.27", + "contentHash": "NAUvSjH8QY8gPp/fXjHhi3MnQEGtSJA0iRT/dT3RKO3AdGACPJyGmKEKxLag9+Kf2On51yGHT9DEPPnK3hyezg==", "dependencies": { - "Microsoft.AspNetCore.Razor.Language": "6.0.36", + "Microsoft.AspNetCore.Razor.Language": "6.0.27", "Microsoft.CodeAnalysis.CSharp": "4.0.0", "Microsoft.CodeAnalysis.Common": "4.0.0" } @@ -530,274 +443,191 @@ }, "Microsoft.EntityFrameworkCore.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "oVSjNSIYHsk0N66eqAWgDcyo9etEFbUswbz7SmlYR6nGp05byHrJAYM5N8U2aGWJWJI6WvIC2e4TXJgH6GZ6HQ==" + "resolved": "9.0.0", + "contentHash": "fnmifFL8KaA4ZNLCVgfjCWhZUFxkrDInx5hR4qG7Q8IEaSiy/6VOSRFyx55oH7MV4y7wM3J3EE90nSpcVBI44Q==" }, "Microsoft.EntityFrameworkCore.Analyzers": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "w4jzX7XI+L3erVGzbHXpx64A3QaLXxqG3f1vPpGYYZGpxOIHkh7e4iLLD7cq4Ng1vjkwzWl5ZJp0Kj/nHsgFYg==" + "resolved": "9.0.0", + "contentHash": "Qje+DzXJOKiXF72SL0XxNlDtTkvWWvmwknuZtFahY5hIQpRKO59qnGuERIQ3qlzuq5x4bAJ8WMbgU5DLhBgeOQ==" }, "Microsoft.EntityFrameworkCore.Relational": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "r7O4N5uaM95InVSGUj7SMOQWN0f1PBF2Y30ow7Jg+pGX5GJCRVd/1fq83lQ50YMyq+EzyHac5o4CDQA2RsjKJQ==", + "resolved": "9.0.0", + "contentHash": "j+msw6fWgAE9M3Q/5B9Uhv7pdAdAQUvFPJAiBJmoy+OXvehVbfbCE8ftMAa51Uo2ZeiqVnHShhnv4Y4UJJmUzA==", "dependencies": { - "Microsoft.EntityFrameworkCore": "9.0.2", - "Microsoft.Extensions.Caching.Memory": "9.0.2", - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.Logging": "9.0.2" - } - }, - "Microsoft.Extensions.AmbientMetadata.Application": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "GMCX3zybUB22aAADjYPXrWhhd1HNMkcY5EcFAJnXy/4k5pPpJ6TS4VRl37xfrtosNyzbpO2SI7pd2Q5PvggSdg==", - "dependencies": { - "Microsoft.Extensions.Configuration": "9.0.2", - "Microsoft.Extensions.Hosting.Abstractions": "9.0.2", - "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.2" + "Microsoft.EntityFrameworkCore": "9.0.0", + "Microsoft.Extensions.Caching.Memory": "9.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "9.0.0", + "Microsoft.Extensions.Logging": "9.0.0" } }, "Microsoft.Extensions.Caching.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "a7QhA25n+BzSM5r5d7JznfyluMBGI7z3qyLlFviZ1Eiqv6DdiK27sLZdP/rpYirBM6UYAKxu5TbmfhIy13GN9A==", + "resolved": "9.0.0", + "contentHash": "FPWZAa9c0H4dvOj351iR1jkUIs4u9ykL4Bm592yhjDyO5lCoWd+TMAHx2EMbarzUvCvgjWjJIoC6//Q9kH6YhA==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.2" - } - }, - "Microsoft.Extensions.Compliance.Abstractions": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "Te+N4xphDlGIS90lKJMZyezFiMWKLAtYV2/M8gGJG4thH6xyC7LWhMzgz2+tWMehxwZlBUq2D9DvVpjKBZFTPQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.ObjectPool": "9.0.2" + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Configuration": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "EBZW+u96tApIvNtjymXEIS44tH0I/jNwABHo4c33AchWOiDWCq2rL3klpnIo+xGrxoVGJzPDISV6hZ+a9C9SzQ==", + "resolved": "8.0.0", + "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.Primitives": "9.0.2" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "I0O/270E/lUNqbBxlRVjxKOMZyYjP88dpEgQTveml+h2lTzAP4vbawLVwjS9SC7lKaU893bwyyNz0IVJYsm9EA==", + "resolved": "9.0.0", + "contentHash": "lqvd7W3FGKUO1+ZoUEMaZ5XDJeWvjpy2/M/ptCGz3tXLD4HWVaSzjufsAsjemasBEg+2SxXVtYVvGt5r2nKDlg==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.2" + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Configuration.Binder": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "krJ04xR0aPXrOf5dkNASg6aJjsdzexvsMRL6UNOUjiTzqBvRr95sJ1owoKEm89bSONQCfZNhHrAFV9ahDqIPIw==", + "resolved": "9.0.0", + "contentHash": "RiScL99DcyngY9zJA2ROrri7Br8tn5N4hP4YNvGdTN/bvg1A3dwvDOxHnNZ3Im7x2SJ5i4LkX1uPiR/MfSFBLQ==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2" + "Microsoft.Extensions.Configuration.Abstractions": "9.0.0" } }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "ZffbJrskOZ40JTzcTyKwFHS5eACSWp2bUQBBApIgGV+es8RaTD4OxUG7XxFr3RIPLXtYQ1jQzF2DjKB5fZn7Qg==", + "resolved": "9.0.0", + "contentHash": "MCPrg7v3QgNMr0vX4vzRXvkNGgLg8vKWX0nKCWUxu2uPyMsaRgiRc1tHBnbTcfJMhMKj2slE/j2M9oGkd25DNw==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "MNe7GSTBf3jQx5vYrXF0NZvn6l7hUKF6J54ENfAgCO8y6xjN1XUmKKWG464LP2ye6QqDiA1dkaWEZBYnhoZzjg==" - }, - "Microsoft.Extensions.DependencyInjection.AutoActivation": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "WcwfTpl3IcPcaahTVEaJwMUg1eWog1SkIA6jQZZFqMXiMX9/tVkhNB6yzUQmBdGWdlWDDRKpOmK7T7x1Uu05pQ==", - "dependencies": { - "Microsoft.Extensions.Hosting.Abstractions": "9.0.2" - } + "resolved": "9.0.0", + "contentHash": "+6f2qv2a3dLwd5w6JanPIPs47CxRbnk+ZocMJUhv9NxP88VlOcJYZs9jY+MYSjxvady08bUZn6qgiNh7DadGgg==" }, "Microsoft.Extensions.DependencyModel": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "3ImbcbS68jy9sKr9Z9ToRbEEX0bvIRdb8zyf5ebtL9Av2CUCGHvaO5wsSXfRfAjr60Vrq0tlmNji9IzAxW6EOw==" + "resolved": "9.0.0", + "contentHash": "saxr2XzwgDU77LaQfYFXmddEDRUKHF4DaGMZkNB3qjdVSZlax3//dGJagJkKrGMIPNZs2jVFXITyCCR6UHJNdA==" }, "Microsoft.Extensions.Diagnostics": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "kwFWk6DPaj1Roc0CExRv+TTwjsiERZA730jQIPlwCcS5tMaCAQtaGfwAK0z8CMFpVTiT+MgKXpd/P50qVCuIgg==", + "resolved": "8.0.0", + "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==", "dependencies": { - "Microsoft.Extensions.Configuration": "9.0.2", - "Microsoft.Extensions.Diagnostics.Abstractions": "9.0.2", - "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.2" + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" } }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "kFwIZEC/37cwKuEm/nXvjF7A/Myz9O7c7P9Csgz6AOiiDE62zdOG5Bu7VkROu1oMYaX0wgijPJ5LqVt6+JKjVg==", + "resolved": "9.0.0", + "contentHash": "1K8P7XzuzX8W8pmXcZjcrqS6x5eSSdvhQohmcpgiQNY/HlDAlnrhR9dvlURfFz428A+RTCJpUyB+aKTA6AgVcQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2" - } - }, - "Microsoft.Extensions.Diagnostics.ExceptionSummarization": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "et5JevHsLv1w1O1Zhb6LiUfai/nmDRzIHnbrZJdzLsIbbMCKTZpeHuANYIppAD//n12KvgOne05j4cu0GhG9gw==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0" } }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "IcOBmTlr2jySswU+3x8c3ql87FRwTVPQgVKaV5AXzPT5u0VItfNU8SMbESpdSp5STwxT/1R99WYszgHWsVkzhg==", + "resolved": "9.0.0", + "contentHash": "uK439QzYR0q2emLVtYzwyK3x+T5bTY4yWsd/k/ZUS9LR6Sflp8MIdhGXW8kQCd86dQD4tLqvcbLkku8qHY263Q==", "dependencies": { - "Microsoft.Extensions.Primitives": "9.0.2" + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Hosting.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "PvjZW6CMdZbPbOwKsQXYN5VPtIWZQqdTRuBPZiW3skhU3hymB17XSlLVC4uaBbDZU+/3eHG3p80y+MzZxZqR7Q==", + "resolved": "9.0.0", + "contentHash": "yUKJgu81ExjvqbNWqZKshBbLntZMbMVz/P7Way2SBx7bMqA08Mfdc9O7hWDKAiSp+zPUGT6LKcSCQIPeDK+CCw==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Diagnostics.Abstractions": "9.0.2", - "Microsoft.Extensions.FileProviders.Abstractions": "9.0.2", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2" + "Microsoft.Extensions.Configuration.Abstractions": "9.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Diagnostics.Abstractions": "9.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0" } }, "Microsoft.Extensions.Http": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "34+kcwxPZr3Owk9eZx268+gqGNB8G/8Y96gZHomxam0IOH08FhPBjPrLWDtKdVn4+sVUUJnJMpECSTJi4XXCcg==", + "resolved": "8.0.0", + "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Diagnostics": "9.0.2", - "Microsoft.Extensions.Logging": "9.0.2", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2" - } - }, - "Microsoft.Extensions.Http.Diagnostics": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "Eeup1LuD5hVk5SsKAuX1D7I9sF380MjrNG10IaaauRLOmrRg8rq2TA8PYTXVBXf3MLkZ6m2xpBqRbZdxf8ygkg==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.AutoActivation": "9.2.0", - "Microsoft.Extensions.Http": "9.0.2", - "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.2", - "Microsoft.Extensions.Telemetry": "9.2.0", - "System.IO.Pipelines": "9.0.2" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Diagnostics": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "Microsoft.Extensions.Logging": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "loV/0UNpt2bD+6kCDzFALVE63CDtqzPeC0LAetkdhiEr/tTNbvOlQ7CBResH7BQBd3cikrwiBfaHdyHMFUlc2g==", + "resolved": "9.0.0", + "contentHash": "crjWyORoug0kK7RSNJBTeSE6VX8IQgLf3nUpTB9m62bPXp/tzbnOsnbe8TXEG0AASNaKZddnpHKw7fET8E++Pg==", "dependencies": { - "Microsoft.Extensions.DependencyInjection": "9.0.2", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2" + "Microsoft.Extensions.DependencyInjection": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0" } }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "dV9s2Lamc8jSaqhl2BQSPn/AryDIH2sSbQUyLitLXV0ROmsb+SROnn2cH939JFbsNrnf3mIM3GNRKT7P0ldwLg==", + "resolved": "9.0.0", + "contentHash": "g0UfujELzlLbHoVG8kPKVBaW470Ewi+jnptGS9KUi6jcb+k2StujtK3m26DFSGGwQ/+bVgZfsWqNzlP6YOejvw==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0" } }, "Microsoft.Extensions.Logging.Configuration": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "pnwYZE7U6d3Y6iMVqADOAUUMMBGYAQPsT3fMwVr/V1Wdpe5DuVGFcViZavUthSJ5724NmelIl1cYy+kRfKfRPQ==", + "resolved": "8.0.0", + "contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==", "dependencies": { - "Microsoft.Extensions.Configuration": "9.0.2", - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.Configuration.Binder": "9.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Logging": "9.0.2", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2", - "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.2" + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" } }, "Microsoft.Extensions.ObjectPool": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "nWx7uY6lfkmtpyC2dGc0IxtrZZs/LnLCQHw3YYQucbqWj8a27U/dZ+eh72O3ZiolqLzzLkVzoC+w/M8dZwxRTw==" + "resolved": "7.0.0", + "contentHash": "udvKco0sAVgYGTBnHUb0tY9JQzJ/nPDiv/8PIyz69wl1AibeCDZOLVVI+6156dPfHmJH7ws5oUJRiW4ZmAvuuA==" }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "zr98z+AN8+isdmDmQRuEJ/DAKZGUTHmdv3t0ZzjHvNqvA44nAgkXE9kYtfoN6581iALChhVaSw2Owt+Z2lVbkQ==", + "resolved": "9.0.0", + "contentHash": "y2146b3jrPI3Q0lokKXdKLpmXqakYbDIPDV6r3M8SqvSf45WwOTzkyfDpxnZXJsJQEpAsAqjUq5Pu8RCJMjubg==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Primitives": "9.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Primitives": "9.0.0" } }, "Microsoft.Extensions.Options.ConfigurationExtensions": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "OPm1NXdMg4Kb4Kz+YHdbBQfekh7MqQZ7liZ5dYUd+IbJakinv9Fl7Ck6Strbgs0a6E76UGbP/jHR532K/7/feQ==", + "resolved": "8.0.0", + "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==", "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "9.0.2", - "Microsoft.Extensions.Configuration.Binder": "9.0.2", - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2", - "Microsoft.Extensions.Primitives": "9.0.2" + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "puBMtKe/wLuYa7H6docBkLlfec+h8L35DXqsDKKJgW0WY5oCwJ3cBJKcDaZchv6knAyqOMfsl6VUbaR++E5LXA==" - }, - "Microsoft.Extensions.Resilience": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "dyaM+Jeznh/i21bOrrRs3xceFfn0571EOjOq95dRXmL1rHDLC4ExhACJ2xipRBP6g1AgRNqmryi+hMrVWWgmlg==", - "dependencies": { - "Microsoft.Extensions.Diagnostics": "9.0.2", - "Microsoft.Extensions.Diagnostics.ExceptionSummarization": "9.2.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.2", - "Microsoft.Extensions.Telemetry.Abstractions": "9.2.0", - "Polly.Extensions": "8.4.2", - "Polly.RateLimiting": "8.4.2" - } - }, - "Microsoft.Extensions.Telemetry": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "4+bw7W4RrAMrND9TxonnSmzJOdXiPxljoda8OPJiReIN607mKCc0t0Mf28sHNsTujO1XQw28wsI0poxeeQxohw==", - "dependencies": { - "Microsoft.Extensions.AmbientMetadata.Application": "9.2.0", - "Microsoft.Extensions.DependencyInjection.AutoActivation": "9.2.0", - "Microsoft.Extensions.Logging.Configuration": "9.0.2", - "Microsoft.Extensions.ObjectPool": "9.0.2", - "Microsoft.Extensions.Telemetry.Abstractions": "9.2.0" - } - }, - "Microsoft.Extensions.Telemetry.Abstractions": { - "type": "Transitive", - "resolved": "9.2.0", - "contentHash": "kEl+5G3RqS20XaEhHh/nOugcjKEK+rgVtMJra1iuwNzdzQXElelf3vu8TugcT7rIZ/T4T76EKW1OX/fmlxz4hw==", - "dependencies": { - "Microsoft.Extensions.Compliance.Abstractions": "9.2.0", - "Microsoft.Extensions.Logging.Abstractions": "9.0.2", - "Microsoft.Extensions.ObjectPool": "9.0.2", - "Microsoft.Extensions.Options": "9.0.2" - } + "resolved": "9.0.0", + "contentHash": "N3qEBzmLMYiASUlKxxFIISP4AiwuPTHF5uCh+2CWSwwzAJiIYx0kBJsS30cp1nvhSySFAVi30jecD307jV+8Kg==" }, "Microsoft.NETCore.Platforms": { "type": "Transitive", @@ -832,67 +662,35 @@ }, "Npgsql": { "type": "Transitive", - "resolved": "9.0.3", - "contentHash": "tPvY61CxOAWxNsKLEBg+oR646X4Bc8UmyQ/tJszL/7mEmIXQnnBhVJZrZEEUv0Bstu0mEsHZD5At3EO8zQRAYw==", + "resolved": "9.0.2", + "contentHash": "hCbO8box7i/XXiTFqCJ3GoowyLqx3JXxyrbOJ6om7dr+eAknvBNhhUHeJVGAQo44sySZTfdVffp4BrtPeLZOAA==", "dependencies": { "Microsoft.Extensions.Logging.Abstractions": "8.0.2" } }, "Npgsql.NodaTime": { "type": "Transitive", - "resolved": "9.0.3", - "contentHash": "PMWXCft/iw+5A7eCeMcy6YZXBst6oeisbCkv2JMQVG4SAFa5vQaf6K2voXzUJCqzwOFcCWs+oT42w2uMDFpchw==", + "resolved": "9.0.2", + "contentHash": "jURb6VGmmR3pPae2N3HrUixSZ/U5ovqZgg/qo3m5Rq/q0m2fpxbZcsHZo21s5MLa/AfJAx4hcFMY98D4RtLdcg==", "dependencies": { "NodaTime": "3.2.0", - "Npgsql": "9.0.3" - } - }, - "Pipelines.Sockets.Unofficial": { - "type": "Transitive", - "resolved": "2.2.8", - "contentHash": "zG2FApP5zxSx6OcdJQLbZDk2AVlN2BNQD6MorwIfV6gVj0RRxWPEp2LXAxqDGZqeNV1Zp0BNPcNaey/GXmTdvQ==", - "dependencies": { - "System.IO.Pipelines": "5.0.1" - } - }, - "Polly.Core": { - "type": "Transitive", - "resolved": "8.4.2", - "contentHash": "BpE2I6HBYYA5tF0Vn4eoQOGYTYIK1BlF5EXVgkWGn3mqUUjbXAr13J6fZVbp7Q3epRR8yshacBMlsHMhpOiV3g==" - }, - "Polly.Extensions": { - "type": "Transitive", - "resolved": "8.4.2", - "contentHash": "GZ9vRVmR0jV2JtZavt+pGUsQ1O1cuRKG7R7VOZI6ZDy9y6RNPvRvXK1tuS4ffUrv8L0FTea59oEuQzgS0R7zSA==", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "Polly.Core": "8.4.2" - } - }, - "Polly.RateLimiting": { - "type": "Transitive", - "resolved": "8.4.2", - "contentHash": "ehTImQ/eUyO07VYW2WvwSmU9rRH200SKJ/3jku9rOkyWE0A2JxNFmAVms8dSn49QLSjmjFRRSgfNyOgr/2PSmA==", - "dependencies": { - "Polly.Core": "8.4.2", - "System.Threading.RateLimiting": "8.0.0" + "Npgsql": "9.0.2" } }, "Sentry": { "type": "Transitive", - "resolved": "5.3.0", - "contentHash": "zlBIP7YmYxySwcgapLMj1gdxPEz9rwdrOa4Yjub/TzcAaMQXusRH9hY4CE6pu0EIibZ7C7Hhjhr6xOTlyK8gFQ==" + "resolved": "4.13.0", + "contentHash": "Wfw3M1WpFcrYaGzPm7QyUTfIOYkVXQ1ry6p4WYjhbLz9fPwV23SGQZTFDpdox67NHM0V0g1aoQ4YKLm4ANtEEg==" }, "Sentry.Extensions.Logging": { "type": "Transitive", - "resolved": "5.3.0", - "contentHash": "DPN6NXvO4LTH21UM2gUFJwSwVa/fuT3B/UZmQyfSfecqViXrZO7WFuKz/h592YUoGNCumyt8x045bxbz6j9btg==", + "resolved": "4.13.0", + "contentHash": "yZ5+TtJKWcss6cG17YjnovImx4X56T8O6Qy6bsMC8tMDttYy8J7HJ2F+WdaZNyjOCo0Rfi6N2gc+Clv/5pf+TQ==", "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "9.0.0", - "Microsoft.Extensions.Http": "9.0.0", - "Microsoft.Extensions.Logging.Configuration": "9.0.0", - "Sentry": "5.3.0" + "Microsoft.Extensions.Configuration.Binder": "8.0.0", + "Microsoft.Extensions.Http": "8.0.0", + "Microsoft.Extensions.Logging.Configuration": "8.0.0", + "Sentry": "4.13.0" } }, "Serilog.Extensions.Hosting": { @@ -1020,8 +818,8 @@ }, "System.IO.Pipelines": { "type": "Transitive", - "resolved": "9.0.2", - "contentHash": "UIBaK7c/A3FyQxmX/747xw4rCUkm1BhNiVU617U5jweNJssNjLJkPUGhBsrlDG0BpKWCYKsncD+Kqpy4KmvZZQ==" + "resolved": "7.0.0", + "contentHash": "jRn6JYnNPW6xgQazROBLSfpdoczRw694vO5kKvMcNnpXuolEixUyw6IBuBs2Y2mlSX/LdLvyyWmfXhaI3ND1Yg==" }, "System.Reactive": { "type": "Transitive", @@ -1059,11 +857,6 @@ "type": "Transitive", "resolved": "7.0.0", "contentHash": "qmeeYNROMsONF6ndEZcIQ+VxR4Q/TX/7uIVLJqtwIWL7dDWeh0l1UIqgo4wYyjG//5lUNhwkLDSFl+pAWO6oiA==" - }, - "System.Threading.RateLimiting": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "7mu9v0QDv66ar3DpGSZHg9NuNcxDaaAcnMULuZlaTpP9+hwXhrxNGsF5GmLkSHxFdb5bBc1TzeujsRgTrPWi+Q==" } } } diff --git a/Foxnouns.Backend/static-pages/.gitignore b/Foxnouns.Backend/static-pages/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/Foxnouns.Backend/static-pages/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj b/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj index ead15ce..5fde110 100644 --- a/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj +++ b/Foxnouns.DataMigrator/Foxnouns.DataMigrator.csproj @@ -12,9 +12,9 @@ - - - + + + diff --git a/Foxnouns.DataMigrator/Program.cs b/Foxnouns.DataMigrator/Program.cs index e79977b..307cda5 100644 --- a/Foxnouns.DataMigrator/Program.cs +++ b/Foxnouns.DataMigrator/Program.cs @@ -6,7 +6,6 @@ using Foxnouns.Backend.Extensions; using Foxnouns.DataMigrator.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; using Npgsql; using Serilog; using Serilog.Sinks.SystemConsole.Themes; @@ -23,12 +22,6 @@ internal class Program .WriteTo.Console(theme: AnsiConsoleTheme.Sixteen) .CreateLogger(); - var minUserId = new Snowflake(0); - if (args.Length > 0) - minUserId = ulong.Parse(args[0]); - - Log.Information("Starting migration from user ID {MinUserId}", minUserId); - Config config = new ConfigurationBuilder() .AddConfiguration() @@ -42,30 +35,11 @@ internal class Program await context.Database.MigrateAsync(); - Dictionary appIds; - if (minUserId == new Snowflake(0)) - { - Log.Information("Migrating applications"); - appIds = await MigrateAppsAsync(conn, context); - - string appJson = JsonConvert.SerializeObject(appIds); - await File.WriteAllTextAsync("apps.json", appJson); - } - else - { - Log.Information( - "Not the first migration, reading application IDs from {Filename}", - "apps.json" - ); - - string appJson = await File.ReadAllTextAsync("apps.json"); - appIds = - JsonConvert.DeserializeObject>(appJson) - ?? throw new Exception("invalid apps.json file"); - } + Log.Information("Migrating applications"); + Dictionary appIds = await MigrateAppsAsync(conn, context); Log.Information("Migrating users"); - List users = await Queries.GetUsersAsync(conn, minUserId); + List users = await Queries.GetUsersAsync(conn); List userFields = await Queries.GetUserFieldsAsync(conn); List memberFields = await Queries.GetMemberFieldsAsync(conn); List prideFlags = await Queries.GetUserFlagsAsync(conn); @@ -96,12 +70,6 @@ internal class Program await context.SaveChangesAsync(); Log.Information("Migration complete!"); - Log.Information( - "Migrated {Count} users, last user was {UserId}. Complete? {Complete}", - users.Count, - users.Last().SnowflakeId, - users.Count != 1000 - ); } private static async Task> MigrateAppsAsync( @@ -124,7 +92,6 @@ internal class Program ClientId = app.ClientId, ClientSecret = app.ClientSecret, InstanceType = app.TypeToEnum(), - ForceRefresh = true, } ); } diff --git a/Foxnouns.DataMigrator/Queries.cs b/Foxnouns.DataMigrator/Queries.cs index 0bc14a2..0d6e71f 100644 --- a/Foxnouns.DataMigrator/Queries.cs +++ b/Foxnouns.DataMigrator/Queries.cs @@ -13,13 +13,8 @@ public static class Queries public static async Task> GetFediverseAppsAsync(NpgsqlConnection conn) => (await conn.QueryAsync("select * from fediverse_apps")).ToList(); - public static async Task> GetUsersAsync(NpgsqlConnection conn, Snowflake minId) => - ( - await conn.QueryAsync( - "select * from users where snowflake_id > @Id order by snowflake_id limit 1000", - new { Id = minId.Value } - ) - ).ToList(); + public static async Task> GetUsersAsync(NpgsqlConnection conn) => + (await conn.QueryAsync("select * from users order by id")).ToList(); public static async Task> GetUserFieldsAsync(NpgsqlConnection conn) => (await conn.QueryAsync("select * from user_fields order by id")).ToList(); diff --git a/Foxnouns.DataMigrator/UserMigrator.cs b/Foxnouns.DataMigrator/UserMigrator.cs index ee46878..0263c47 100644 --- a/Foxnouns.DataMigrator/UserMigrator.cs +++ b/Foxnouns.DataMigrator/UserMigrator.cs @@ -2,7 +2,7 @@ using System.Diagnostics.CodeAnalysis; using Dapper; using Foxnouns.Backend.Database; using Foxnouns.Backend.Database.Models; -using Foxnouns.Backend.Services; +using Foxnouns.Backend.Utils; using Foxnouns.DataMigrator.Models; using NodaTime.Extensions; using Npgsql; @@ -39,7 +39,6 @@ public class UserMigrator( _user = new User { Id = goUser.SnowflakeId, - LegacyId = goUser.Id, Username = goUser.Username, DisplayName = goUser.DisplayName, Bio = goUser.Bio, @@ -140,7 +139,6 @@ public class UserMigrator( new PrideFlag { Id = flag.SnowflakeId, - LegacyId = flag.Id, UserId = _user!.Id, Hash = flag.Hash, Name = flag.Name, @@ -192,7 +190,6 @@ public class UserMigrator( UserId = _user!.Id, Name = goMember.Name, Sid = goMember.Sid, - LegacyId = goMember.Id, DisplayName = goMember.DisplayName, Bio = goMember.Bio, Avatar = goMember.Avatar, @@ -238,7 +235,6 @@ public class UserMigrator( "small" => PreferenceSize.Small, _ => PreferenceSize.Normal, }, - LegacyId = new Guid(id), }; } @@ -260,6 +256,6 @@ public class UserMigrator( { if (_preferenceIds.TryGetValue(id, out Snowflake preferenceId)) return preferenceId.ToString(); - return ValidationService.DefaultStatusOptions.Contains(id) ? id : "okay"; + return ValidationUtils.DefaultStatusOptions.Contains(id) ? id : "okay"; } } diff --git a/Foxnouns.Frontend/.env.example b/Foxnouns.Frontend/.env.example index 99c47b3..d79c672 100644 --- a/Foxnouns.Frontend/.env.example +++ b/Foxnouns.Frontend/.env.example @@ -1,18 +1,7 @@ -# Example .env file--DO NOT EDIT, copy to .env or .env.local then edit - -# The language the frontend will use. Valid languages are listed in src/lib/i18n/index.ts. +# Example .env file--DO NOT EDIT PUBLIC_LANGUAGE=en -# The public base URL, i.e. the one users will see. Used for building links. PUBLIC_BASE_URL=https://pronouns.cc -# The base URL for the URL shortener service. Used for building short links. PUBLIC_SHORT_URL=https://prns.cc -# The base public URL for the API. This is (almost) always the public base URL + /api. PUBLIC_API_BASE=https://pronouns.cc/api -# The base *private* URL for the API's rate limiter proxy. The frontend will rewrite API URLs to use this. -# In development, you can set this to the same value as $PRIVATE_INTERNAL_API_HOST, but be aware that this will disable rate limiting. PRIVATE_API_HOST=http://localhost:5003/api -# The base private URL for the API, which bypasses the rate limiter. Used for /api/internal paths and unauthenticated GET requests. -PRIVATE_INTERNAL_API_HOST=http://localhost:6000/api - -# The Sentry URL to use. Optional. -PRIVATE_SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0 +PRIVATE_INTERNAL_API_HOST=http://localhost:5000/api diff --git a/Foxnouns.Frontend/.vscode/settings.json b/Foxnouns.Frontend/.vscode/settings.json index c5d12a5..5703e7f 100644 --- a/Foxnouns.Frontend/.vscode/settings.json +++ b/Foxnouns.Frontend/.vscode/settings.json @@ -4,6 +4,5 @@ "i18n-ally.localesPaths": ["src/lib/i18n", "src/lib/i18n/locales"], "i18n-ally.keystyle": "nested", "explorer.sortOrder": "filesFirst", - "explorer.compactFolders": false, - "eslint.validate": ["javascript", "javascriptreact", "svelte"] + "explorer.compactFolders": false } diff --git a/Foxnouns.Frontend/Dockerfile b/Foxnouns.Frontend/Dockerfile index 2a86593..166be23 100644 --- a/Foxnouns.Frontend/Dockerfile +++ b/Foxnouns.Frontend/Dockerfile @@ -1,4 +1,8 @@ -FROM docker.io/node:23-slim +FROM docker.io/node:22-slim + +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable COPY ./Foxnouns.Frontend /app COPY ./docker/frontend.env /app/.env.local @@ -7,7 +11,7 @@ WORKDIR /app ENV PRIVATE_API_HOST=http://rate:5003/api ENV PRIVATE_INTERNAL_API_HOST=http://backend:5000/api -RUN npm ci -RUN npm run build +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +RUN pnpm run build -CMD ["node", "build/index.js"] +CMD ["pnpm", "node", "build/index.js"] diff --git a/Foxnouns.Frontend/icons.js b/Foxnouns.Frontend/icons.js index 0c9ffc4..3efc0a4 100644 --- a/Foxnouns.Frontend/icons.js +++ b/Foxnouns.Frontend/icons.js @@ -1,6 +1,6 @@ // This script regenerates the list of icons for the frontend (Foxnouns.Frontend/src/lib/icons.ts) // and the backend (Foxnouns.Backend/Utils/BootstrapIcons.Icons.cs) from the currently installed version of Bootstrap Icons. -// Run with `node icons.js` in the frontend directory. +// Run with `pnpm node icons.js` in the frontend directory. import { writeFileSync } from "fs"; import icons from "bootstrap-icons/font/bootstrap-icons.json" with { type: "json" }; diff --git a/Foxnouns.Frontend/package-lock.json b/Foxnouns.Frontend/package-lock.json deleted file mode 100644 index ac5f6f1..0000000 --- a/Foxnouns.Frontend/package-lock.json +++ /dev/null @@ -1,6354 +0,0 @@ -{ - "name": "foxnouns.frontend", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "foxnouns.frontend", - "version": "0.0.1", - "dependencies": { - "@fontsource/firago": "^5.2.5", - "@sentry/sveltekit": "^9.11.0", - "base64-arraybuffer": "^1.0.2", - "bootstrap-icons": "^1.11.3", - "luxon": "^3.6.1", - "markdown-it": "^14.1.0", - "minidenticons": "^4.2.1", - "pretty-bytes": "^6.1.1", - "sanitize-html": "^2.15.0", - "svelte-tippy": "^1.3.2", - "tippy.js": "^6.3.7", - "tslog": "^4.9.3" - }, - "devDependencies": { - "@sveltejs/adapter-node": "^5.2.12", - "@sveltejs/kit": "^2.20.4", - "@sveltejs/vite-plugin-svelte": "^5.0.3", - "@sveltestrap/sveltestrap": "^7.1.0", - "@types/eslint": "^9.6.1", - "@types/luxon": "^3.6.2", - "@types/markdown-it": "^14.1.2", - "@types/sanitize-html": "^2.15.0", - "bootstrap": "^5.3.5", - "dotenv": "^16.4.7", - "eslint": "^9.24.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-svelte": "^2.46.1", - "globals": "^16.0.0", - "prettier": "^3.5.3", - "prettier-plugin-svelte": "^3.3.3", - "sass": "^1.86.3", - "svelte": "^5.25.7", - "svelte-bootstrap-icons": "^3.1.2", - "svelte-check": "^4.1.5", - "svelte-easy-crop": "^4.0.1", - "sveltekit-i18n": "^2.4.2", - "typescript": "^5.8.3", - "typescript-eslint": "^8.29.0", - "vite": "^6.2.5" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", - "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/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", - "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==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", - "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.9" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", - "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", - "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", - "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", - "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", - "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", - "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.13.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", - "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@fontsource/firago": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource/firago/-/firago-5.2.5.tgz", - "integrity": "sha512-11vSR9Vyh0Tp/ChtheVSsK3yP9UGUUV5xJCdSOE8xNsQH/NZIGF36p0aeFTQ6uzBBaxaVjCGm0LEIFmxAwJoRw==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", - "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.57.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.57.2.tgz", - "integrity": "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", - "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", - "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.57.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", - "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@types/shimmer": "^1.2.0", - "import-in-the-middle": "^1.8.1", - "require-in-the-middle": "^7.1.1", - "semver": "^7.5.2", - "shimmer": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.46.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.46.1.tgz", - "integrity": "sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.43.1.tgz", - "integrity": "sha512-ht7YGWQuV5BopMcw5Q2hXn3I8eG8TH0J/kc/GMcW4CuNTgiP6wCu44BOnucJWL3CmFWaRHI//vWyAhaC8BwePw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/connect": "3.4.38" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.16.1.tgz", - "integrity": "sha512-K/qU4CjnzOpNkkKO4DfCLSQshejRNAJtd4esgigo/50nxCB6XCyi1dhAblUHM9jG5dRm8eu0FB+t87nIo99LYQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.47.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.47.1.tgz", - "integrity": "sha512-QNXPTWteDclR2B4pDFpz0TNghgB33UMjUt14B+BZPmtH1MwUFAfLHBaP5If0Z5NZC+jaH8oF2glgYjrmhZWmSw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fastify": { - "version": "0.44.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.44.2.tgz", - "integrity": "sha512-arSp97Y4D2NWogoXRb8CzFK3W2ooVdvqRRtQDljFt9uC3zI6OuShgey6CVFC0JxT1iGjkAr1r4PDz23mWrFULQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.1.tgz", - "integrity": "sha512-6g0FhB3B9UobAR60BGTcXg4IHZ6aaYJzp0Ki5FhnxyAPt8Ns+9SSvgcrnsN2eGmk3RWG5vYycUGOEApycQL24A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.1.tgz", - "integrity": "sha512-M6qGYsp1cURtvVLGDrPPZemMFEbuMmCXgQYTReC/IbimV5sGrLBjB+/hANUpRZjX67nGLdKSVLZuQQAiNz+sww==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.47.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.47.1.tgz", - "integrity": "sha512-EGQRWMGqwiuVma8ZLAZnExQ7sBvbOx0N/AE/nlafISPs8S+QtXX+Viy6dcQwVWwYHQPAcuY3bFt3xgoAwb4ZNQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.45.2.tgz", - "integrity": "sha512-7Ehow/7Wp3aoyCrZwQpU7a2CnoMq0XhIcioFuKjBb0PLYfBfmTsFTUyatlHu0fRxhwcRsSQRTvEhmZu8CppBpQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.57.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.57.2.tgz", - "integrity": "sha512-1Uz5iJ9ZAlFOiPuwYg29Bf7bJJc/GeoeJIFKJYQf67nTVKFe8RHbEtxgkOmK4UGZNHKXcpW4P8cWBYzBn1USpg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/instrumentation": "0.57.2", - "@opentelemetry/semantic-conventions": "1.28.0", - "forwarded-parse": "2.1.2", - "semver": "^7.5.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.47.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.47.1.tgz", - "integrity": "sha512-OtFGSN+kgk/aoKgdkKQnBsQFDiG8WdCxu+UrHr0bXScdAmtSzLSraLo7wFIb25RVHfRWvzI5kZomqJYEg/l1iA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/redis-common": "^0.36.2", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.7.1.tgz", - "integrity": "sha512-OtjaKs8H7oysfErajdYr1yuWSjMAectT7Dwr+axIoZqT9lmEOkD/H/3rgAs8h/NIuEi2imSXD+vL4MZtOuJfqQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.44.1.tgz", - "integrity": "sha512-U4dQxkNhvPexffjEmGwCq68FuftFK15JgUF05y/HlK3M6W/G2iEaACIfXdSnwVNe9Qh0sPfw8LbOPxrWzGWGMQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.47.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.47.1.tgz", - "integrity": "sha512-l/c+Z9F86cOiPJUllUCt09v+kICKvT+Vg1vOAJHtHPsJIzurGayucfCMq2acd/A/yxeNWunl9d9eqZ0G+XiI6A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.44.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.44.1.tgz", - "integrity": "sha512-5MPkYCvG2yw7WONEjYj5lr5JFehTobW7wX+ZUFy81oF2lr9IPfZk9qO+FTaM0bGEiymwfLwKe6jE15nHn1nmHg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.52.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.52.0.tgz", - "integrity": "sha512-1xmAqOtRUQGR7QfJFfGV/M2kC7wmI2WgZdpru8hJl3S0r4hW0n3OQpEHlSGXJAaNFyvT+ilnwkT+g5L4ljHR6g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.46.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.46.1.tgz", - "integrity": "sha512-3kINtW1LUTPkiXFRSSBmva1SXzS/72we/jL22N+BnF3DFcoewkdkHPYOIdAAk9gSicJ4d5Ojtt1/HeibEc5OQg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.45.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.45.1.tgz", - "integrity": "sha512-TKp4hQ8iKQsY7vnp/j0yJJ4ZsP109Ht6l4RHTj0lNEG1TfgTrIH5vJMbgmoYXWzNHAqBH2e7fncN12p3BP8LFg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/mysql": "2.15.26" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.45.2.tgz", - "integrity": "sha512-h6Ad60FjCYdJZ5DTz1Lk2VmQsShiViKe0G7sYikb0GHI0NVvApp2XQNRHNjEMz87roFttGPLHOYVPlfy+yVIhQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@opentelemetry/sql-common": "^0.40.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.51.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.51.1.tgz", - "integrity": "sha512-QxgjSrxyWZc7Vk+qGSfsejPVFL1AgAJdSBMYZdDUbwg730D09ub3PXScB9d04vIqPriZ+0dqzjmQx0yWKiCi2Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.26.0", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@opentelemetry/sql-common": "^0.40.1", - "@types/pg": "8.6.1", - "@types/pg-pool": "2.0.6" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis-4": { - "version": "0.46.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.46.1.tgz", - "integrity": "sha512-UMqleEoabYMsWoTkqyt9WAzXwZ4BlFZHO40wr3d5ZvtjKCHlD4YXLm+6OLCeIi/HkX7EXvQaz8gtAwkwwSEvcQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/redis-common": "^0.36.2", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.18.1.tgz", - "integrity": "sha512-5Cuy/nj0HBaH+ZJ4leuD7RjgvA844aY2WW+B5uLcWtxGjRZl3MNLuxnNg5DYWZNPO+NafSSnra0q49KWAHsKBg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/tedious": "^4.0.14" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-undici": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.10.1.tgz", - "integrity": "sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.57.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.7.0" - } - }, - "node_modules/@opentelemetry/redis-common": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", - "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", - "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.30.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", - "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.30.1", - "@opentelemetry/resources": "1.30.1", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.32.0.tgz", - "integrity": "sha512-s0OpmpQFSfMrmedAn9Lhg4KWJELHCU6uU9dtIJ28N8UGhf9Y55im5X8fEzwhwDwiSqN+ZPSNrDJF7ivf/AuRPQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", - "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.1.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "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==", - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "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" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "license": "MIT" - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@prisma/instrumentation": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.5.0.tgz", - "integrity": "sha512-morJDtFRoAp5d/KENEm+K6Y3PQcn5bCvpJ5a9y3V3DNMrNy/ZSn2zulPGj+ld+Xj2UYVoaMJ8DpBX/o6iF6OiA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.8" - } - }, - "node_modules/@rollup/plugin-commonjs": { - "version": "28.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz", - "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.2.0", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-json": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", - "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.1.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", - "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", - "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", - "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", - "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", - "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", - "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", - "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", - "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", - "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", - "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", - "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", - "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", - "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", - "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", - "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", - "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", - "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", - "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", - "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", - "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", - "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@sentry-internal/browser-utils": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-9.13.0.tgz", - "integrity": "sha512-uZcbwcGI49oPC/YDEConJ+3xi2mu0TsVsDiMQKb6JoSc33KH37wq2IwXJb9nakzKJXxyMNemb44r8irAswjItw==", - "license": "MIT", - "dependencies": { - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry-internal/feedback": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-9.13.0.tgz", - "integrity": "sha512-fOhMnhEbOR5QVPtn5Gc5+UKQHjvAN/LmtYE6Qya3w2FDh3ZlnIXNFJWqwOneuICV3kCWjN4lLckwmzzwychr7A==", - "license": "MIT", - "dependencies": { - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry-internal/replay": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-9.13.0.tgz", - "integrity": "sha512-l+Atwab/bqI1N8+PSG1WWTCVmiOl7swL85Z9ntwS39QBnd66CTyzt/+j/n/UbAs8GienJK6FIfX1dvG1WmvUhA==", - "license": "MIT", - "dependencies": { - "@sentry-internal/browser-utils": "9.13.0", - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry-internal/replay-canvas": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-9.13.0.tgz", - "integrity": "sha512-5muW2BmEfWP1fpVWDNcIsph/WgqOqpHaXC1QMr4hk8/BWgt1/S2KPy85YiGVtM5lJJr0VhASKK8rBXG+9zm9IQ==", - "license": "MIT", - "dependencies": { - "@sentry-internal/replay": "9.13.0", - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/babel-plugin-component-annotate": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.2.4.tgz", - "integrity": "sha512-yBzRn3GEUSv1RPtE4xB4LnuH74ZxtdoRJ5cmQ9i6mzlmGDxlrnKuvem5++AolZTE9oJqAD3Tx2rd1PqmpWnLoA==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/@sentry/browser": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-9.13.0.tgz", - "integrity": "sha512-KiC8s9/6HvdlfCRqA420YbiBiXMBif7GYESJ8VQqOKUmlPczn8V2CRrEZjMqxhlHdIGiR0PS6jb2VSgeJBchJQ==", - "license": "MIT", - "dependencies": { - "@sentry-internal/browser-utils": "9.13.0", - "@sentry-internal/feedback": "9.13.0", - "@sentry-internal/replay": "9.13.0", - "@sentry-internal/replay-canvas": "9.13.0", - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/bundler-plugin-core": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.2.4.tgz", - "integrity": "sha512-YMj9XW5W2JA89EeweE7CPKLDz245LBsI1JhCmqpt/bjSvmsSIAAPsLYnvIJBS3LQFm0OhtG8NB54PTi96dAcMA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.18.5", - "@sentry/babel-plugin-component-annotate": "3.2.4", - "@sentry/cli": "2.42.2", - "dotenv": "^16.3.1", - "find-up": "^5.0.0", - "glob": "^9.3.2", - "magic-string": "0.30.8", - "unplugin": "1.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@sentry/bundler-plugin-core/node_modules/magic-string": { - "version": "0.30.8", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", - "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@sentry/cli": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.42.2.tgz", - "integrity": "sha512-spb7S/RUumCGyiSTg8DlrCX4bivCNmU/A1hcfkwuciTFGu8l5CDc2I6jJWWZw8/0enDGxuj5XujgXvU5tr4bxg==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.7", - "progress": "^2.0.3", - "proxy-from-env": "^1.1.0", - "which": "^2.0.2" - }, - "bin": { - "sentry-cli": "bin/sentry-cli" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@sentry/cli-darwin": "2.42.2", - "@sentry/cli-linux-arm": "2.42.2", - "@sentry/cli-linux-arm64": "2.42.2", - "@sentry/cli-linux-i686": "2.42.2", - "@sentry/cli-linux-x64": "2.42.2", - "@sentry/cli-win32-i686": "2.42.2", - "@sentry/cli-win32-x64": "2.42.2" - } - }, - "node_modules/@sentry/cli-darwin": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.42.2.tgz", - "integrity": "sha512-GtJSuxER7Vrp1IpxdUyRZzcckzMnb4N5KTW7sbTwUiwqARRo+wxS+gczYrS8tdgtmXs5XYhzhs+t4d52ITHMIg==", - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-arm": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.42.2.tgz", - "integrity": "sha512-7udCw+YL9lwq+9eL3WLspvnuG+k5Icg92YE7zsteTzWLwgPVzaxeZD2f8hwhsu+wmL+jNqbpCRmktPteh3i2mg==", - "cpu": [ - "arm" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-arm64": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.42.2.tgz", - "integrity": "sha512-BOxzI7sgEU5Dhq3o4SblFXdE9zScpz6EXc5Zwr1UDZvzgXZGosUtKVc7d1LmkrHP8Q2o18HcDWtF3WvJRb5Zpw==", - "cpu": [ - "arm64" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-i686": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.42.2.tgz", - "integrity": "sha512-Sw/dQp5ZPvKnq3/y7wIJyxTUJYPGoTX/YeMbDs8BzDlu9to2LWV3K3r7hE7W1Lpbaw4tSquUHiQjP5QHCOS7aQ==", - "cpu": [ - "x86", - "ia32" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-linux-x64": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.42.2.tgz", - "integrity": "sha512-mU4zUspAal6TIwlNLBV5oq6yYqiENnCWSxtSQVzWs0Jyq97wtqGNG9U+QrnwjJZ+ta/hvye9fvL2X25D/RxHQw==", - "cpu": [ - "x64" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux", - "freebsd" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-win32-i686": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.42.2.tgz", - "integrity": "sha512-iHvFHPGqgJMNqXJoQpqttfsv2GI3cGodeTq4aoVLU/BT3+hXzbV0x1VpvvEhncJkDgDicJpFLM8sEPHb3b8abw==", - "cpu": [ - "x86", - "ia32" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cli-win32-x64": { - "version": "2.42.2", - "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.42.2.tgz", - "integrity": "sha512-vPPGHjYoaGmfrU7xhfFxG7qlTBacroz5NdT+0FmDn6692D8IvpNXl1K+eV3Kag44ipJBBeR8g1HRJyx/F/9ACw==", - "cpu": [ - "x64" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@sentry/cloudflare": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/cloudflare/-/cloudflare-9.13.0.tgz", - "integrity": "sha512-XaG/Kl5dSUJtzYkalQjaejGhrgFoj5w3cSWoXkxd8J+LXHsq7BFg4S0uCkzGJUmDHItlzfEY8BIaPpgPTJL7MQ==", - "license": "MIT", - "dependencies": { - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cloudflare/workers-types": "^4.x" - }, - "peerDependenciesMeta": { - "@cloudflare/workers-types": { - "optional": true - } - } - }, - "node_modules/@sentry/core": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.13.0.tgz", - "integrity": "sha512-Zn1Qec5XNkNRE/M5QjL6YJLghETg6P188G/v2OzdHdHIRf0Y58/SnJilu3louF+ogos6kaSqqdMgzqKgZ8tCdg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/node/-/node-9.13.0.tgz", - "integrity": "sha512-75UVkrED5b0BaazNQKCmF8NqeqjErxildPojDyC037JN+cVFMPr/kFFGGm7E+eCvA/j2pAPUzqifHp/PjykPcw==", - "license": "MIT", - "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1", - "@opentelemetry/core": "^1.30.1", - "@opentelemetry/instrumentation": "^0.57.2", - "@opentelemetry/instrumentation-amqplib": "^0.46.1", - "@opentelemetry/instrumentation-connect": "0.43.1", - "@opentelemetry/instrumentation-dataloader": "0.16.1", - "@opentelemetry/instrumentation-express": "0.47.1", - "@opentelemetry/instrumentation-fastify": "0.44.2", - "@opentelemetry/instrumentation-fs": "0.19.1", - "@opentelemetry/instrumentation-generic-pool": "0.43.1", - "@opentelemetry/instrumentation-graphql": "0.47.1", - "@opentelemetry/instrumentation-hapi": "0.45.2", - "@opentelemetry/instrumentation-http": "0.57.2", - "@opentelemetry/instrumentation-ioredis": "0.47.1", - "@opentelemetry/instrumentation-kafkajs": "0.7.1", - "@opentelemetry/instrumentation-knex": "0.44.1", - "@opentelemetry/instrumentation-koa": "0.47.1", - "@opentelemetry/instrumentation-lru-memoizer": "0.44.1", - "@opentelemetry/instrumentation-mongodb": "0.52.0", - "@opentelemetry/instrumentation-mongoose": "0.46.1", - "@opentelemetry/instrumentation-mysql": "0.45.1", - "@opentelemetry/instrumentation-mysql2": "0.45.2", - "@opentelemetry/instrumentation-pg": "0.51.1", - "@opentelemetry/instrumentation-redis-4": "0.46.1", - "@opentelemetry/instrumentation-tedious": "0.18.1", - "@opentelemetry/instrumentation-undici": "0.10.1", - "@opentelemetry/resources": "^1.30.1", - "@opentelemetry/sdk-trace-base": "^1.30.1", - "@opentelemetry/semantic-conventions": "^1.30.0", - "@prisma/instrumentation": "6.5.0", - "@sentry/core": "9.13.0", - "@sentry/opentelemetry": "9.13.0", - "import-in-the-middle": "^1.13.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/opentelemetry": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.13.0.tgz", - "integrity": "sha512-TLSP0n+sXKVcVkAM2ttVmXcAT2K3e9D5gdPfr6aCnW+KIGJuD7wzla/TIcTWFaVwUejbvXAB6IFpZ/qA8HFwyA==", - "license": "MIT", - "dependencies": { - "@sentry/core": "9.13.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1", - "@opentelemetry/core": "^1.30.1", - "@opentelemetry/instrumentation": "^0.57.1", - "@opentelemetry/sdk-trace-base": "^1.30.1", - "@opentelemetry/semantic-conventions": "^1.28.0" - } - }, - "node_modules/@sentry/svelte": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/svelte/-/svelte-9.13.0.tgz", - "integrity": "sha512-Sy8YOlIA0x4yhW4WM5ra2aarzKKrLgFTqkY6gAG3XrJ3DNFURrTDiaHUwQCICkLf2+zJKpuw6sfovBWqo1Z+DQ==", - "license": "MIT", - "dependencies": { - "@sentry/browser": "9.13.0", - "@sentry/core": "9.13.0", - "magic-string": "^0.30.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "svelte": "3.x || 4.x || 5.x" - } - }, - "node_modules/@sentry/sveltekit": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@sentry/sveltekit/-/sveltekit-9.13.0.tgz", - "integrity": "sha512-U+uDKxAB+bI7nIiz/SfqPpoQMnenARXj0E3+z916bkgfdEyZUODkaQvHmmEKEOX7VRcRUT53mD/c1LwbxhSWxw==", - "license": "MIT", - "dependencies": { - "@babel/parser": "7.26.9", - "@sentry/cloudflare": "9.13.0", - "@sentry/core": "9.13.0", - "@sentry/node": "9.13.0", - "@sentry/opentelemetry": "9.13.0", - "@sentry/svelte": "9.13.0", - "@sentry/vite-plugin": "3.2.4", - "magic-string": "0.30.7", - "recast": "0.23.11", - "sorcery": "1.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@sveltejs/kit": "2.x", - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/@sentry/vite-plugin": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@sentry/vite-plugin/-/vite-plugin-3.2.4.tgz", - "integrity": "sha512-ZRn5TLlq5xtwKOqaWP+XqS1PYVfbBCgsbMk7wW2Ly6EgF9wYePvtLqKgYnE3hwPg2LpBnRPR2ti1ohlUkR+wXA==", - "license": "MIT", - "dependencies": { - "@sentry/bundler-plugin-core": "3.2.4", - "unplugin": "1.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", - "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", - "license": "MIT", - "peerDependencies": { - "acorn": "^8.9.0" - } - }, - "node_modules/@sveltejs/adapter-node": { - "version": "5.2.12", - "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.12.tgz", - "integrity": "sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/plugin-commonjs": "^28.0.1", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.0", - "rollup": "^4.9.5" - }, - "peerDependencies": { - "@sveltejs/kit": "^2.4.0" - } - }, - "node_modules/@sveltejs/kit": { - "version": "2.20.7", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.7.tgz", - "integrity": "sha512-dVbLMubpJJSLI4OYB+yWYNHGAhgc2bVevWuBjDj8jFUXIJOAnLwYP3vsmtcgoxNGUXoq0rHS5f7MFCsryb6nzg==", - "license": "MIT", - "dependencies": { - "@types/cookie": "^0.6.0", - "cookie": "^0.6.0", - "devalue": "^5.1.0", - "esm-env": "^1.2.2", - "import-meta-resolve": "^4.1.0", - "kleur": "^4.1.5", - "magic-string": "^0.30.5", - "mrmime": "^2.0.0", - "sade": "^1.8.1", - "set-cookie-parser": "^2.6.0", - "sirv": "^3.0.0" - }, - "bin": { - "svelte-kit": "svelte-kit.js" - }, - "engines": { - "node": ">=18.13" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3 || ^6.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", - "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", - "license": "MIT", - "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", - "debug": "^4.4.0", - "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.15", - "vitefu": "^1.0.4" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" - }, - "peerDependencies": { - "svelte": "^5.0.0", - "vite": "^6.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", - "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.7" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.0", - "svelte": "^5.0.0", - "vite": "^6.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte/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==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, - "node_modules/@sveltekit-i18n/base": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/@sveltekit-i18n/base/-/base-1.3.7.tgz", - "integrity": "sha512-kg1kql1/ro/lIudwFiWrv949Q07gmweln87tflUZR51MNdXXzK4fiJQv5Mw50K/CdQ5BOk/dJ0WOH2vOtBI6yw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "svelte": ">=3.49.0" - } - }, - "node_modules/@sveltekit-i18n/parser-default": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@sveltekit-i18n/parser-default/-/parser-default-1.1.1.tgz", - "integrity": "sha512-/gtzLlqm/sox7EoPKD56BxGZktK/syGc79EbJAPWY5KVitQD9SM0TP8yJCqDxTVPk7Lk0WJhrBGUE2Nn0f5M1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sveltestrap/sveltestrap": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@sveltestrap/sveltestrap/-/sveltestrap-7.1.0.tgz", - "integrity": "sha512-TpIx25kqLV+z+VD3yfqYayOI1IaCeWFbT0uqM6NfA4vQgDs9PjFwmjkU4YEAlV/ngs9e7xPmaRWE7lkrg4Miow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@popperjs/core": "^2.11.8" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0 || ^5.0.0-next.0" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "license": "MIT" - }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/luxon": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz", - "integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mysql": { - "version": "2.15.26", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", - "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "22.14.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", - "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/pg": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", - "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/pg-pool": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", - "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", - "license": "MIT", - "dependencies": { - "@types/pg": "*" - } - }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/sanitize-html": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.15.0.tgz", - "integrity": "sha512-71Z6PbYsVKfp4i6Jvr37s5ql6if1Q/iJQT80NbaSi7uGaG8CqBMXP0pk/EsURAOuGdk5IJCd/vnzKrR7S3Txsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "htmlparser2": "^8.0.0" - } - }, - "node_modules/@types/shimmer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", - "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", - "license": "MIT" - }, - "node_modules/@types/tedious": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", - "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", - "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/type-utils": "8.30.1", - "@typescript-eslint/utils": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", - "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/typescript-estree": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", - "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", - "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "8.30.1", - "@typescript-eslint/utils": "8.30.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", - "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", - "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.0.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", - "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/typescript-estree": "8.30.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", - "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.30.1", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "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/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/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "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==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ast-types": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", - "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6.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==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bootstrap": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.5.tgz", - "integrity": "sha512-ct1CHKtiobRimyGzmsSldEtM03E8fcEX4Tb3dGXz1V8faRwM50+vfHwTzOxB3IlKO7m+9vTH3s/3C6T2EAPeTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "license": "MIT", - "peerDependencies": { - "@popperjs/core": "^2.11.8" - } - }, - "node_modules/bootstrap-icons": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz", - "integrity": "sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "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.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001714", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001714.tgz", - "integrity": "sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==", - "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": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "license": "MIT" - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "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/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==", - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "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/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/devalue": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", - "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", - "license": "MIT" - }, - "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==", - "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==", - "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==", - "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==", - "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/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.137.tgz", - "integrity": "sha512-/QSJaU2JyIuTbbABAo/crOs+SuAZLS+fVVS10PVrIT9hrRkmZl8Hb0xPSkKRUUWHQtYzXHpQUW3Dy5hwMzGZkA==", - "license": "ISC" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", - "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.0", - "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.24.0", - "@eslint/plugin-kit": "^0.2.7", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-compat-utils": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", - "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-svelte": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz", - "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@jridgewell/sourcemap-codec": "^1.4.15", - "eslint-compat-utils": "^0.5.1", - "esutils": "^2.0.3", - "known-css-properties": "^0.35.0", - "postcss": "^8.4.38", - "postcss-load-config": "^3.1.4", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.1.0", - "semver": "^7.6.2", - "svelte-eslint-parser": "^0.43.0" - }, - "engines": { - "node": "^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0", - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", - "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esm-env": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "license": "MIT" - }, - "node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrap": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", - "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "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-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/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/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-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "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/forwarded-parse": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", - "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", - "license": "MIT" - }, - "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==", - "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==", - "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==", - "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==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", - "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", - "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", - "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalyzer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "license": "MIT" - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "license": "MIT" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "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/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "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.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immutable": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz", - "integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-in-the-middle": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.13.1.tgz", - "integrity": "sha512-k2V9wNm9B+ysuelDTHjI9d5KPc4l8zAZTGqj+pcynvWkypZd857ryzN8jNC7Pg2YZXNMJcHRPpaDyCBbNyVRpA==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.14.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" - } - }, - "node_modules/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "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/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==", - "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==", - "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==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "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==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "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/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "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==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/known-css-properties": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", - "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", - "dev": true, - "license": "MIT" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/locate-character": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "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==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/luxon": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz", - "integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/magic-string": { - "version": "0.30.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", - "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "devOptional": true, - "license": "MIT", - "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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/minidenticons": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minidenticons/-/minidenticons-4.2.1.tgz", - "integrity": "sha512-oWfFivA0lOx/V/bO/YIJbthB26lV8JXYvhnv9zM2hNd3fzsHTXQ6c6bWZPcvhD3nnOB+lQk/D9lF43BXixrN8g==", - "license": "MIT", - "engines": { - "node": ">=15.14.0" - } - }, - "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==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", - "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/module-details-from-path": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", - "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==", - "license": "MIT" - }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "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==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "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/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "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==", - "license": "MIT", - "optional": true - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "license": "MIT" - }, - "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==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-srcset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", - "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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==", - "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==", - "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==", - "license": "ISC" - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.8.0.tgz", - "integrity": "sha512-jvuYlEkL03NRvOoyoRktBK7+qU5kOvlAwvmrH8sr3wbLrOdVWsRxQfz8mMy9sZFsqJ1hEWNfdWKI4SAmoL+j7g==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "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.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", - "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-scss": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", - "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-scss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.4.29" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-svelte": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz", - "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "prettier": "^3.0.0", - "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" - } - }, - "node_modules/pretty-bytes": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", - "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", - "license": "MIT", - "engines": { - "node": "^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "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/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/recast": { - "version": "0.23.11", - "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", - "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", - "license": "MIT", - "dependencies": { - "ast-types": "^0.16.1", - "esprima": "~4.0.0", - "source-map": "~0.6.1", - "tiny-invariant": "^1.3.3", - "tslib": "^2.0.1" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/require-in-the-middle": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", - "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3", - "resolve": "^1.22.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "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==", - "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/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", - "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.7" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.40.0", - "@rollup/rollup-android-arm64": "4.40.0", - "@rollup/rollup-darwin-arm64": "4.40.0", - "@rollup/rollup-darwin-x64": "4.40.0", - "@rollup/rollup-freebsd-arm64": "4.40.0", - "@rollup/rollup-freebsd-x64": "4.40.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", - "@rollup/rollup-linux-arm-musleabihf": "4.40.0", - "@rollup/rollup-linux-arm64-gnu": "4.40.0", - "@rollup/rollup-linux-arm64-musl": "4.40.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-gnu": "4.40.0", - "@rollup/rollup-linux-riscv64-musl": "4.40.0", - "@rollup/rollup-linux-s390x-gnu": "4.40.0", - "@rollup/rollup-linux-x64-gnu": "4.40.0", - "@rollup/rollup-linux-x64-musl": "4.40.0", - "@rollup/rollup-win32-arm64-msvc": "4.40.0", - "@rollup/rollup-win32-ia32-msvc": "4.40.0", - "@rollup/rollup-win32-x64-msvc": "4.40.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "license": "MIT", - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sanitize-html": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.16.0.tgz", - "integrity": "sha512-0s4caLuHHaZFVxFTG74oW91+j6vW7gKbGD6CD2+miP73CE6z6YtOBN0ArtLd2UGyi4IC7K47v3ENUbQX4jV3Mg==", - "license": "MIT", - "dependencies": { - "deepmerge": "^4.2.2", - "escape-string-regexp": "^4.0.0", - "htmlparser2": "^8.0.0", - "is-plain-object": "^5.0.0", - "parse-srcset": "^1.0.2", - "postcss": "^8.3.11" - } - }, - "node_modules/sass": { - "version": "1.86.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.3.tgz", - "integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==", - "devOptional": 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.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" - }, - "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/shimmer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", - "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", - "license": "BSD-2-Clause" - }, - "node_modules/sirv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/sorcery": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-1.0.0.tgz", - "integrity": "sha512-5ay9oJE+7sNmhzl3YNG18jEEEf4AOQCM/FAqR5wMmzqd1FtRorFbJXn3w3SKOhbiQaVgHM+Q1lszZspjri7bpA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.14", - "minimist": "^1.2.0", - "tiny-glob": "^0.2.9" - }, - "bin": { - "sorcery": "bin/sorcery" - } - }, - "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==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svelte": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.27.0.tgz", - "integrity": "sha512-Uai13Ydt1ZE+bUHme6b9U38PCYVNCqBRoBMkUKbFbKiD7kHWjdUUrklYAQZJxyKK81qII4mrBwe/YmvEMSlC9w==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@jridgewell/sourcemap-codec": "^1.5.0", - "@sveltejs/acorn-typescript": "^1.0.5", - "@types/estree": "^1.0.5", - "acorn": "^8.12.1", - "aria-query": "^5.3.1", - "axobject-query": "^4.1.0", - "clsx": "^2.1.1", - "esm-env": "^1.2.1", - "esrap": "^1.4.6", - "is-reference": "^3.0.3", - "locate-character": "^3.0.0", - "magic-string": "^0.30.11", - "zimmerframe": "^1.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/svelte-bootstrap-icons": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/svelte-bootstrap-icons/-/svelte-bootstrap-icons-3.1.2.tgz", - "integrity": "sha512-vy+qmWFfLJZxu5BaDlmaUG4uzki1rodX5ERZAP6KQdyO/2WNeGBDU4Yke3Z0NRq+VSepK86iAy+iUJvlUdsbBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/svelte-check": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.6.tgz", - "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "chokidar": "^4.0.1", - "fdir": "^6.2.0", - "picocolors": "^1.0.0", - "sade": "^1.7.4" - }, - "bin": { - "svelte-check": "bin/svelte-check" - }, - "engines": { - "node": ">= 18.0.0" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "typescript": ">=5.0.0" - } - }, - "node_modules/svelte-easy-crop": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/svelte-easy-crop/-/svelte-easy-crop-4.0.1.tgz", - "integrity": "sha512-0k7vVpHVLrPyobSXqey5IJUmFVxOoCaQrobFEsFXpSCyK8N5jTkRj1VX6NuCOZK8XXcMAqUvV0MktB8D5x1oCw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "svelte": "^5.0.0" - } - }, - "node_modules/svelte-eslint-parser": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz", - "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "postcss": "^8.4.39", - "postcss-scss": "^4.0.9" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "svelte": { - "optional": true - } - } - }, - "node_modules/svelte-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/svelte-eslint-parser/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/svelte-tippy": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svelte-tippy/-/svelte-tippy-1.3.2.tgz", - "integrity": "sha512-41f+85hwhKBRqX0UNYrgFsi34Kk/KDvUkIZXYANxkWoA2NTVTCZbUC2J8hRNZ4TRVxObTshoZRjK2co5+i6LMw==", - "dependencies": { - "tippy.js": "6.3.7" - } - }, - "node_modules/svelte/node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.6" - } - }, - "node_modules/svelte/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==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, - "node_modules/sveltekit-i18n": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/sveltekit-i18n/-/sveltekit-i18n-2.4.2.tgz", - "integrity": "sha512-hjRWn4V4DBL8JQKJoJa3MRvn6d32Zo+rWkoSP5bsQ/XIAguPdQUZJ8LMe6Nc1rST8WEVdu9+vZI3aFdKYGR3+Q==", - "dev": true, - "license": "MIT", - "workspaces": [ - "./examples/*/" - ], - "dependencies": { - "@sveltekit-i18n/base": "~1.3.0", - "@sveltekit-i18n/parser-default": "~1.1.0" - }, - "peerDependencies": { - "svelte": ">=3.49.0" - } - }, - "node_modules/tiny-glob": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", - "license": "MIT", - "dependencies": { - "globalyzer": "0.1.0", - "globrex": "^0.1.2" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", - "license": "MIT", - "dependencies": { - "fdir": "^6.4.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tippy.js": { - "version": "6.3.7", - "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", - "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", - "license": "MIT", - "dependencies": { - "@popperjs/core": "^2.9.0" - } - }, - "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==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "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/tslog": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.9.3.tgz", - "integrity": "sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/fullstack-build/tslog?sponsor=1" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.30.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.30.1.tgz", - "integrity": "sha512-D7lC0kcehVH7Mb26MRQi64LMyRJsj3dToJxM1+JVTl53DQSV5/7oUGWQLcKl1C1KnoVHxMMU2FNQMffr7F3Row==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.30.1", - "@typescript-eslint/parser": "8.30.1", - "@typescript-eslint/utils": "8.30.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/unplugin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz", - "integrity": "sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==", - "license": "MIT", - "dependencies": { - "acorn": "^8.8.1", - "chokidar": "^3.5.3", - "webpack-sources": "^3.2.3", - "webpack-virtual-modules": "^0.5.0" - } - }, - "node_modules/unplugin/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "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/unplugin/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==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/unplugin/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/unplugin/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "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==", - "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/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.1.tgz", - "integrity": "sha512-kkzzkqtMESYklo96HKKPE5KKLkC1amlsqt+RjFMlX2AvbRB/0wghap19NdBxxwGZ+h/C6DLCrcEphPIItlGrRQ==", - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.3", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.12" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "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/vitefu": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", - "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", - "license": "MIT", - "workspaces": [ - "tests/deps/*", - "tests/projects/*" - ], - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-virtual-modules": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz", - "integrity": "sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==", - "license": "MIT" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zimmerframe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", - "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", - "license": "MIT" - } - } -} diff --git a/Foxnouns.Frontend/package.json b/Foxnouns.Frontend/package.json index 507e11f..b9e35fc 100644 --- a/Foxnouns.Frontend/package.json +++ b/Foxnouns.Frontend/package.json @@ -12,42 +12,40 @@ "lint": "prettier --check . && eslint ." }, "devDependencies": { - "@sveltejs/adapter-node": "^5.2.12", - "@sveltejs/kit": "^2.20.4", - "@sveltejs/vite-plugin-svelte": "^5.0.3", - "@sveltestrap/sveltestrap": "^7.1.0", + "@sveltejs/adapter-node": "^5.2.10", + "@sveltejs/kit": "^2.11.1", + "@sveltejs/vite-plugin-svelte": "^4.0.3", + "@sveltestrap/sveltestrap": "^6.2.7", "@types/eslint": "^9.6.1", - "@types/luxon": "^3.6.2", + "@types/luxon": "^3.4.2", "@types/markdown-it": "^14.1.2", - "@types/sanitize-html": "^2.15.0", - "bootstrap": "^5.3.5", - "dotenv": "^16.4.7", - "eslint": "^9.24.0", + "@types/sanitize-html": "^2.13.0", + "bootstrap": "^5.3.3", + "eslint": "^9.17.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.46.1", - "globals": "^16.0.0", - "prettier": "^3.5.3", - "prettier-plugin-svelte": "^3.3.3", - "sass": "^1.86.3", - "svelte": "^5.25.7", - "svelte-bootstrap-icons": "^3.1.2", - "svelte-check": "^4.1.5", - "svelte-easy-crop": "^4.0.1", + "globals": "^15.13.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.2", + "sass": "^1.83.0", + "svelte": "^5.13.0", + "svelte-bootstrap-icons": "^3.1.1", + "svelte-check": "^4.1.1", "sveltekit-i18n": "^2.4.2", - "typescript": "^5.8.3", - "typescript-eslint": "^8.29.0", - "vite": "^6.2.5" + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.0", + "vite": "^5.4.11" }, + "packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c", "dependencies": { - "@fontsource/firago": "^5.2.5", - "@sentry/sveltekit": "^9.11.0", + "@fontsource/firago": "^5.1.0", "base64-arraybuffer": "^1.0.2", "bootstrap-icons": "^1.11.3", - "luxon": "^3.6.1", + "luxon": "^3.5.0", "markdown-it": "^14.1.0", "minidenticons": "^4.2.1", "pretty-bytes": "^6.1.1", - "sanitize-html": "^2.15.0", + "sanitize-html": "^2.13.1", "svelte-tippy": "^1.3.2", "tippy.js": "^6.3.7", "tslog": "^4.9.3" diff --git a/Foxnouns.Frontend/pnpm-lock.yaml b/Foxnouns.Frontend/pnpm-lock.yaml new file mode 100644 index 0000000..2ebd886 --- /dev/null +++ b/Foxnouns.Frontend/pnpm-lock.yaml @@ -0,0 +1,2686 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@fontsource/firago': + specifier: ^5.1.0 + version: 5.1.0 + base64-arraybuffer: + specifier: ^1.0.2 + version: 1.0.2 + bootstrap-icons: + specifier: ^1.11.3 + version: 1.11.3 + luxon: + specifier: ^3.5.0 + version: 3.5.0 + markdown-it: + specifier: ^14.1.0 + version: 14.1.0 + minidenticons: + specifier: ^4.2.1 + version: 4.2.1 + pretty-bytes: + specifier: ^6.1.1 + version: 6.1.1 + sanitize-html: + specifier: ^2.13.1 + version: 2.13.1 + svelte-tippy: + specifier: ^1.3.2 + version: 1.3.2 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 + tslog: + specifier: ^4.9.3 + version: 4.9.3 + devDependencies: + '@sveltejs/adapter-node': + specifier: ^5.2.10 + version: 5.2.10(@sveltejs/kit@2.11.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0))) + '@sveltejs/kit': + specifier: ^2.11.1 + version: 2.11.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + '@sveltejs/vite-plugin-svelte': + specifier: ^4.0.3 + version: 4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + '@sveltestrap/sveltestrap': + specifier: ^6.2.7 + version: 6.2.7(svelte@5.13.0) + '@types/eslint': + specifier: ^9.6.1 + version: 9.6.1 + '@types/luxon': + specifier: ^3.4.2 + version: 3.4.2 + '@types/markdown-it': + specifier: ^14.1.2 + version: 14.1.2 + '@types/sanitize-html': + specifier: ^2.13.0 + version: 2.13.0 + bootstrap: + specifier: ^5.3.3 + version: 5.3.3(@popperjs/core@2.11.8) + eslint: + specifier: ^9.17.0 + version: 9.17.0 + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@9.17.0) + eslint-plugin-svelte: + specifier: ^2.46.1 + version: 2.46.1(eslint@9.17.0)(svelte@5.13.0) + globals: + specifier: ^15.13.0 + version: 15.13.0 + prettier: + specifier: ^3.4.2 + version: 3.4.2 + prettier-plugin-svelte: + specifier: ^3.3.2 + version: 3.3.2(prettier@3.4.2)(svelte@5.13.0) + sass: + specifier: ^1.83.0 + version: 1.83.0 + svelte: + specifier: ^5.13.0 + version: 5.13.0 + svelte-bootstrap-icons: + specifier: ^3.1.1 + version: 3.1.1 + svelte-check: + specifier: ^4.1.1 + version: 4.1.1(picomatch@4.0.2)(svelte@5.13.0)(typescript@5.7.2) + sveltekit-i18n: + specifier: ^2.4.2 + version: 2.4.2(svelte@5.13.0) + typescript: + specifier: ^5.7.2 + version: 5.7.2 + typescript-eslint: + specifier: ^8.18.0 + version: 8.18.0(eslint@9.17.0)(typescript@5.7.2) + vite: + specifier: ^5.4.11 + version: 5.4.11(sass@1.83.0) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.1': + resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.19.1': + resolution: {integrity: sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.9.1': + resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.17.0': + resolution: {integrity: sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.5': + resolution: {integrity: sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.4': + resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@fontsource/firago@5.1.0': + resolution: {integrity: sha512-ym1zCs5Zmp7J6vJ2AzU74H008bxebz53OBY2yPe+qD7+UXwu1S4bHpHYBbznu+HMxccW+JkEZg6UTyqc90V2ug==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@parcel/watcher-android-arm64@2.5.0': + resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.0': + resolution: {integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.0': + resolution: {integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.0': + resolution: {integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.0': + resolution: {integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm-musl@2.5.0': + resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-arm64-musl@2.5.0': + resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + + '@parcel/watcher-linux-x64-glibc@2.5.0': + resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-linux-x64-musl@2.5.0': + resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + + '@parcel/watcher-win32-arm64@2.5.0': + resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.0': + resolution: {integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.0': + resolution: {integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.0': + resolution: {integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==} + engines: {node: '>= 10.0.0'} + + '@polka/url@1.0.0-next.28': + resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@rollup/plugin-commonjs@28.0.1': + resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@15.3.0': + resolution: {integrity: sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.1.3': + resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.28.1': + resolution: {integrity: sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.28.1': + resolution: {integrity: sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.28.1': + resolution: {integrity: sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.28.1': + resolution: {integrity: sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.28.1': + resolution: {integrity: sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.28.1': + resolution: {integrity: sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.28.1': + resolution: {integrity: sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.28.1': + resolution: {integrity: sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.28.1': + resolution: {integrity: sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.28.1': + resolution: {integrity: sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.28.1': + resolution: {integrity: sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.28.1': + resolution: {integrity: sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.28.1': + resolution: {integrity: sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.28.1': + resolution: {integrity: sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.28.1': + resolution: {integrity: sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.28.1': + resolution: {integrity: sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.28.1': + resolution: {integrity: sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.28.1': + resolution: {integrity: sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.28.1': + resolution: {integrity: sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==} + cpu: [x64] + os: [win32] + + '@sveltejs/adapter-node@5.2.10': + resolution: {integrity: sha512-U0SCdULhHbSYCDgvvrHRtKUykl9GZkM/b3NyeIUtaxM39upQFd5059pWmXgTNaNTU1HMdj4xx0xvNAvQcIzmXQ==} + peerDependencies: + '@sveltejs/kit': ^2.4.0 + + '@sveltejs/kit@2.11.1': + resolution: {integrity: sha512-dAiHDEd+AOm20eYdMPV1a2eKBOc0s/7XsSs7PCoNv2kKS7BAoVRC9uzR+FQmxLtp8xuEo9z8CtrMQoszkThltQ==} + engines: {node: '>=18.13'} + hasBin: true + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.3 || ^6.0.0 + + '@sveltejs/vite-plugin-svelte-inspector@3.0.1': + resolution: {integrity: sha512-2CKypmj1sM4GE7HjllT7UKmo4Q6L5xFRd7VMGEWhYnZ+wc6AUVU01IBd7yUi6WnFndEwWoMNOd6e8UjoN0nbvQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + '@sveltejs/vite-plugin-svelte': ^4.0.0-next.0||^4.0.0 + svelte: ^5.0.0-next.96 || ^5.0.0 + vite: ^5.0.0 + + '@sveltejs/vite-plugin-svelte@4.0.3': + resolution: {integrity: sha512-J7nC5gT5qpmvyD2pmzPUntLUgoinyEaNy9sTpGGE6N7pblggO0A1NyneJJvR2ELlzK6ti28aF2SLXG1yJdnJeA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22} + peerDependencies: + svelte: ^5.0.0-next.96 || ^5.0.0 + vite: ^5.0.0 + + '@sveltekit-i18n/base@1.3.7': + resolution: {integrity: sha512-kg1kql1/ro/lIudwFiWrv949Q07gmweln87tflUZR51MNdXXzK4fiJQv5Mw50K/CdQ5BOk/dJ0WOH2vOtBI6yw==} + peerDependencies: + svelte: '>=3.49.0' + + '@sveltekit-i18n/parser-default@1.1.1': + resolution: {integrity: sha512-/gtzLlqm/sox7EoPKD56BxGZktK/syGc79EbJAPWY5KVitQD9SM0TP8yJCqDxTVPk7Lk0WJhrBGUE2Nn0f5M1w==} + + '@sveltestrap/sveltestrap@6.2.7': + resolution: {integrity: sha512-WwLLfAFUb42BGuRrf3Vbct30bQMzlEMMipN/MfxhjuLTmLQeW9muVJfPyvjtWS+mY+RjkSCoHvAp/ZobP1NLlQ==} + peerDependencies: + svelte: ^4.0.0 || ^5.0.0 || ^5.0.0-next.0 + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/luxon@3.4.2': + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/sanitize-html@2.13.0': + resolution: {integrity: sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==} + + '@typescript-eslint/eslint-plugin@8.18.0': + resolution: {integrity: sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/parser@8.18.0': + resolution: {integrity: sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/scope-manager@8.18.0': + resolution: {integrity: sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.18.0': + resolution: {integrity: sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/types@8.18.0': + resolution: {integrity: sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.18.0': + resolution: {integrity: sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/utils@8.18.0': + resolution: {integrity: sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + '@typescript-eslint/visitor-keys@8.18.0': + resolution: {integrity: sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-typescript@1.4.13: + resolution: {integrity: sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==} + peerDependencies: + acorn: '>=8.9.0' + + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-arraybuffer@1.0.2: + resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} + engines: {node: '>= 0.6.0'} + + bootstrap-icons@1.11.3: + resolution: {integrity: sha512-+3lpHrCw/it2/7lBL15VR0HEumaBss0+f/Lb6ZvHISn1mlK83jjFpooTLsMWbIjJMDjDjOExMsTxnXSIT4k4ww==} + + bootstrap@5.3.3: + resolution: {integrity: sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==} + peerDependencies: + '@popperjs/core': ^2.11.8 + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + devalue@5.1.1: + resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-config-prettier@9.1.0: + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-svelte@2.46.1: + resolution: {integrity: sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0-0 || ^9.0.0-0 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.17.0: + resolution: {integrity: sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esm-env@1.2.1: + resolution: {integrity: sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==} + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrap@1.2.3: + resolution: {integrity: sha512-ZlQmCCK+n7SGoqo7DnfKaP1sJZa49P01/dXzmjCASSo04p72w8EksT2NMK8CEX8DhKsfJXANioIw8VyHNsBfvQ==} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fdir@6.4.2: + resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.2: + resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.13.0: + resolution: {integrity: sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==} + engines: {node: '>=18'} + + globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + immutable@5.0.3: + resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-core-module@2.16.0: + resolution: {integrity: sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + known-css-properties@0.35.0: + resolution: {integrity: sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + luxon@3.5.0: + resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==} + engines: {node: '>=12'} + + magic-string@0.30.15: + resolution: {integrity: sha512-zXeaYRgZ6ldS1RJJUrMrYgNJ4fdwnyI6tVqoiIhyCyv5IVTK9BU8Ic2l253GGETQHxI4HNUwhJ3fjDhKqEoaAw==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minidenticons@4.2.1: + resolution: {integrity: sha512-oWfFivA0lOx/V/bO/YIJbthB26lV8JXYvhnv9zM2hNd3fzsHTXQ6c6bWZPcvhD3nnOB+lQk/D9lF43BXixrN8g==} + engines: {node: '>=15.14.0'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-srcset@1.0.2: + resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + postcss-load-config@3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + postcss-safe-parser@6.0.0: + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-plugin-svelte@3.3.2: + resolution: {integrity: sha512-kRPjH8wSj2iu+dO+XaUv4vD8qr5mdDmlak3IT/7AOgGIMRG86z/EHOLauFcClKEnOUf4A4nOA7sre5KrJD4Raw==} + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + + prettier@3.4.2: + resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve@1.22.9: + resolution: {integrity: sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.28.1: + resolution: {integrity: sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + sanitize-html@2.13.1: + resolution: {integrity: sha512-ZXtKq89oue4RP7abL9wp/9URJcqQNABB5GGJ2acW1sdO8JTVl92f4ygD7Yc9Ze09VAZhnt2zegeU0tbNsdcLYg==} + + sass@1.83.0: + resolution: {integrity: sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==} + engines: {node: '>=14.0.0'} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sirv@3.0.0: + resolution: {integrity: sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svelte-bootstrap-icons@3.1.1: + resolution: {integrity: sha512-ghJlt6TX3IX35M7wSvGyrmVgXeT5GMRF+7+q6L4OUT2RJWF09mQIvZTZ04Ii3FBfg10KdzFdvVuoB8M0cVHfzw==} + + svelte-check@4.1.1: + resolution: {integrity: sha512-NfaX+6Qtc8W/CyVGS/F7/XdiSSyXz+WGYA9ZWV3z8tso14V2vzjfXviKaTFEzB7g8TqfgO2FOzP6XT4ApSTUTw==} + engines: {node: '>= 18.0.0'} + hasBin: true + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: '>=5.0.0' + + svelte-eslint-parser@0.43.0: + resolution: {integrity: sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + svelte: + optional: true + + svelte-tippy@1.3.2: + resolution: {integrity: sha512-41f+85hwhKBRqX0UNYrgFsi34Kk/KDvUkIZXYANxkWoA2NTVTCZbUC2J8hRNZ4TRVxObTshoZRjK2co5+i6LMw==} + + svelte@5.13.0: + resolution: {integrity: sha512-ZG4VmBNze/j2KxT2GEeUm8Jr3RLYQ3P5Y9/flUDCgaAxgzx4ZRTdiyh+PCr7qRlOr5M8uidIqr+3DwUFVrdL+A==} + engines: {node: '>=18'} + + sveltekit-i18n@2.4.2: + resolution: {integrity: sha512-hjRWn4V4DBL8JQKJoJa3MRvn6d32Zo+rWkoSP5bsQ/XIAguPdQUZJ8LMe6Nc1rST8WEVdu9+vZI3aFdKYGR3+Q==} + peerDependencies: + svelte: '>=3.49.0' + + tiny-glob@0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + tslog@4.9.3: + resolution: {integrity: sha512-oDWuGVONxhVEBtschLf2cs/Jy8i7h1T+CpdkTNWQgdAF7DhRo2G8vMCgILKe7ojdEkLhICWgI1LYSSKaJsRgcw==} + engines: {node: '>=16'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.18.0: + resolution: {integrity: sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite@5.4.11: + resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitefu@1.0.4: + resolution: {integrity: sha512-y6zEE3PQf6uu/Mt6DTJ9ih+kyJLr4XcSgHR2zUkM8SWDhuixEJxfJ6CZGMHh1Ec3vPLoEA0IHU5oWzVqw8ulow==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + vite: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0)': + dependencies: + eslint: 9.17.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.19.1': + dependencies: + '@eslint/object-schema': 2.1.5 + debug: 4.4.0 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.9.1': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.2.0': + dependencies: + ajv: 6.12.6 + debug: 4.4.0 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.17.0': {} + + '@eslint/object-schema@2.1.5': {} + + '@eslint/plugin-kit@0.2.4': + dependencies: + levn: 0.4.1 + + '@fontsource/firago@5.1.0': {} + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.1': {} + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + '@parcel/watcher-android-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-x64@2.5.0': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.0': + optional: true + + '@parcel/watcher-win32-arm64@2.5.0': + optional: true + + '@parcel/watcher-win32-ia32@2.5.0': + optional: true + + '@parcel/watcher-win32-x64@2.5.0': + optional: true + + '@parcel/watcher@2.5.0': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 + optional: true + + '@polka/url@1.0.0-next.28': {} + + '@popperjs/core@2.11.8': {} + + '@rollup/plugin-commonjs@28.0.1(rollup@4.28.1)': + dependencies: + '@rollup/pluginutils': 5.1.3(rollup@4.28.1) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.4.2(picomatch@4.0.2) + is-reference: 1.2.1 + magic-string: 0.30.15 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.28.1 + + '@rollup/plugin-json@6.1.0(rollup@4.28.1)': + dependencies: + '@rollup/pluginutils': 5.1.3(rollup@4.28.1) + optionalDependencies: + rollup: 4.28.1 + + '@rollup/plugin-node-resolve@15.3.0(rollup@4.28.1)': + dependencies: + '@rollup/pluginutils': 5.1.3(rollup@4.28.1) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.9 + optionalDependencies: + rollup: 4.28.1 + + '@rollup/pluginutils@5.1.3(rollup@4.28.1)': + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + optionalDependencies: + rollup: 4.28.1 + + '@rollup/rollup-android-arm-eabi@4.28.1': + optional: true + + '@rollup/rollup-android-arm64@4.28.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.28.1': + optional: true + + '@rollup/rollup-darwin-x64@4.28.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.28.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.28.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.28.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.28.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.28.1': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.28.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.28.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.28.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.28.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.28.1': + optional: true + + '@sveltejs/adapter-node@5.2.10(@sveltejs/kit@2.11.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))': + dependencies: + '@rollup/plugin-commonjs': 28.0.1(rollup@4.28.1) + '@rollup/plugin-json': 6.1.0(rollup@4.28.1) + '@rollup/plugin-node-resolve': 15.3.0(rollup@4.28.1) + '@sveltejs/kit': 2.11.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + rollup: 4.28.1 + + '@sveltejs/kit@2.11.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + '@types/cookie': 0.6.0 + cookie: 0.6.0 + devalue: 5.1.1 + esm-env: 1.2.1 + import-meta-resolve: 4.1.0 + kleur: 4.1.5 + magic-string: 0.30.15 + mrmime: 2.0.0 + sade: 1.8.1 + set-cookie-parser: 2.7.1 + sirv: 3.0.0 + svelte: 5.13.0 + tiny-glob: 0.2.9 + vite: 5.4.11(sass@1.83.0) + + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0))': + dependencies: + '@sveltejs/vite-plugin-svelte': 4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + debug: 4.4.0 + svelte: 5.13.0 + vite: 5.4.11(sass@1.83.0) + transitivePeerDependencies: + - supports-color + + '@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0))': + dependencies: + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.3(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)))(svelte@5.13.0)(vite@5.4.11(sass@1.83.0)) + debug: 4.4.0 + deepmerge: 4.3.1 + kleur: 4.1.5 + magic-string: 0.30.15 + svelte: 5.13.0 + vite: 5.4.11(sass@1.83.0) + vitefu: 1.0.4(vite@5.4.11(sass@1.83.0)) + transitivePeerDependencies: + - supports-color + + '@sveltekit-i18n/base@1.3.7(svelte@5.13.0)': + dependencies: + svelte: 5.13.0 + + '@sveltekit-i18n/parser-default@1.1.1': {} + + '@sveltestrap/sveltestrap@6.2.7(svelte@5.13.0)': + dependencies: + '@popperjs/core': 2.11.8 + svelte: 5.13.0 + + '@types/cookie@0.6.0': {} + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.6': {} + + '@types/json-schema@7.0.15': {} + + '@types/linkify-it@5.0.0': {} + + '@types/luxon@3.4.2': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@2.0.0': {} + + '@types/resolve@1.20.2': {} + + '@types/sanitize-html@2.13.0': + dependencies: + htmlparser2: 8.0.2 + + '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.17.0)(typescript@5.7.2))(eslint@9.17.0)(typescript@5.7.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/type-utils': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.0 + eslint: 9.17.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.4.3(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.18.0(eslint@9.17.0)(typescript@5.7.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.18.0 + debug: 4.4.0 + eslint: 9.17.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.18.0': + dependencies: + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/visitor-keys': 8.18.0 + + '@typescript-eslint/type-utils@8.18.0(eslint@9.17.0)(typescript@5.7.2)': + dependencies: + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + debug: 4.4.0 + eslint: 9.17.0 + ts-api-utils: 1.4.3(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.18.0': {} + + '@typescript-eslint/typescript-estree@8.18.0(typescript@5.7.2)': + dependencies: + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/visitor-keys': 8.18.0 + debug: 4.4.0 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.4.3(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.18.0(eslint@9.17.0)(typescript@5.7.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@typescript-eslint/scope-manager': 8.18.0 + '@typescript-eslint/types': 8.18.0 + '@typescript-eslint/typescript-estree': 8.18.0(typescript@5.7.2) + eslint: 9.17.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.18.0': + dependencies: + '@typescript-eslint/types': 8.18.0 + eslint-visitor-keys: 4.2.0 + + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn-typescript@1.4.13(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + + acorn@8.14.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + base64-arraybuffer@1.0.2: {} + + bootstrap-icons@1.11.3: {} + + bootstrap@5.3.3(@popperjs/core@2.11.8): + dependencies: + '@popperjs/core': 2.11.8 + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + commondir@1.0.1: {} + + concat-map@0.0.1: {} + + cookie@0.6.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + detect-libc@1.0.3: + optional: true + + devalue@5.1.1: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.1.0: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + entities@4.5.0: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + escape-string-regexp@4.0.0: {} + + eslint-compat-utils@0.5.1(eslint@9.17.0): + dependencies: + eslint: 9.17.0 + semver: 7.6.3 + + eslint-config-prettier@9.1.0(eslint@9.17.0): + dependencies: + eslint: 9.17.0 + + eslint-plugin-svelte@2.46.1(eslint@9.17.0)(svelte@5.13.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@jridgewell/sourcemap-codec': 1.5.0 + eslint: 9.17.0 + eslint-compat-utils: 0.5.1(eslint@9.17.0) + esutils: 2.0.3 + known-css-properties: 0.35.0 + postcss: 8.4.49 + postcss-load-config: 3.1.4(postcss@8.4.49) + postcss-safe-parser: 6.0.0(postcss@8.4.49) + postcss-selector-parser: 6.1.2 + semver: 7.6.3 + svelte-eslint-parser: 0.43.0(svelte@5.13.0) + optionalDependencies: + svelte: 5.13.0 + transitivePeerDependencies: + - ts-node + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@8.2.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.17.0: + dependencies: + '@eslint-community/eslint-utils': 4.4.1(eslint@9.17.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.1 + '@eslint/core': 0.9.1 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.17.0 + '@eslint/plugin-kit': 0.2.4 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.0 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + esm-env@1.2.1: {} + + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + + espree@9.6.1: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrap@1.2.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.6 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fdir@6.4.2(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.2 + keyv: 4.5.4 + + flatted@3.3.2: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@15.13.0: {} + + globalyzer@0.1.0: {} + + globrex@0.1.2: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + + ignore@5.3.2: {} + + immutable@5.0.3: {} + + import-fresh@3.3.0: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-meta-resolve@4.1.0: {} + + imurmurhash@0.1.4: {} + + is-core-module@2.16.0: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-module@1.0.0: {} + + is-number@7.0.0: {} + + is-plain-object@5.0.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.6 + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.6 + + isexe@2.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@4.1.5: {} + + known-css-properties@0.35.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@2.1.0: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + locate-character@3.0.0: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + luxon@3.5.0: {} + + magic-string@0.30.15: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + mdurl@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + minidenticons@4.2.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + mri@1.2.0: {} + + mrmime@2.0.0: {} + + ms@2.1.3: {} + + nanoid@3.3.8: {} + + natural-compare@1.4.0: {} + + node-addon-api@7.1.1: + optional: true + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-srcset@1.0.2: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + postcss-load-config@3.1.4(postcss@8.4.49): + dependencies: + lilconfig: 2.1.0 + yaml: 1.10.2 + optionalDependencies: + postcss: 8.4.49 + + postcss-safe-parser@6.0.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + postcss-scss@4.0.9(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.4.49: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-plugin-svelte@3.3.2(prettier@3.4.2)(svelte@5.13.0): + dependencies: + prettier: 3.4.2 + svelte: 5.13.0 + + prettier@3.4.2: {} + + pretty-bytes@6.1.1: {} + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + readdirp@4.0.2: {} + + resolve-from@4.0.0: {} + + resolve@1.22.9: + dependencies: + is-core-module: 2.16.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} + + rollup@4.28.1: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.28.1 + '@rollup/rollup-android-arm64': 4.28.1 + '@rollup/rollup-darwin-arm64': 4.28.1 + '@rollup/rollup-darwin-x64': 4.28.1 + '@rollup/rollup-freebsd-arm64': 4.28.1 + '@rollup/rollup-freebsd-x64': 4.28.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.28.1 + '@rollup/rollup-linux-arm-musleabihf': 4.28.1 + '@rollup/rollup-linux-arm64-gnu': 4.28.1 + '@rollup/rollup-linux-arm64-musl': 4.28.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.28.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.28.1 + '@rollup/rollup-linux-riscv64-gnu': 4.28.1 + '@rollup/rollup-linux-s390x-gnu': 4.28.1 + '@rollup/rollup-linux-x64-gnu': 4.28.1 + '@rollup/rollup-linux-x64-musl': 4.28.1 + '@rollup/rollup-win32-arm64-msvc': 4.28.1 + '@rollup/rollup-win32-ia32-msvc': 4.28.1 + '@rollup/rollup-win32-x64-msvc': 4.28.1 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + sanitize-html@2.13.1: + dependencies: + deepmerge: 4.3.1 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.2 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.4.49 + + sass@1.83.0: + dependencies: + chokidar: 4.0.1 + immutable: 5.0.3 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.0 + + semver@7.6.3: {} + + set-cookie-parser@2.7.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + sirv@3.0.0: + dependencies: + '@polka/url': 1.0.0-next.28 + mrmime: 2.0.0 + totalist: 3.0.1 + + source-map-js@1.2.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svelte-bootstrap-icons@3.1.1: {} + + svelte-check@4.1.1(picomatch@4.0.2)(svelte@5.13.0)(typescript@5.7.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + chokidar: 4.0.1 + fdir: 6.4.2(picomatch@4.0.2) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.13.0 + typescript: 5.7.2 + transitivePeerDependencies: + - picomatch + + svelte-eslint-parser@0.43.0(svelte@5.13.0): + dependencies: + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + postcss: 8.4.49 + postcss-scss: 4.0.9(postcss@8.4.49) + optionalDependencies: + svelte: 5.13.0 + + svelte-tippy@1.3.2: + dependencies: + tippy.js: 6.3.7 + + svelte@5.13.0: + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.6 + acorn: 8.14.0 + acorn-typescript: 1.4.13(acorn@8.14.0) + aria-query: 5.3.2 + axobject-query: 4.1.0 + esm-env: 1.2.1 + esrap: 1.2.3 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.15 + zimmerframe: 1.1.2 + + sveltekit-i18n@2.4.2(svelte@5.13.0): + dependencies: + '@sveltekit-i18n/base': 1.3.7(svelte@5.13.0) + '@sveltekit-i18n/parser-default': 1.1.1 + svelte: 5.13.0 + + tiny-glob@0.2.9: + dependencies: + globalyzer: 0.1.0 + globrex: 0.1.2 + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.8 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + totalist@3.0.1: {} + + ts-api-utils@1.4.3(typescript@5.7.2): + dependencies: + typescript: 5.7.2 + + tslog@4.9.3: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.18.0(eslint@9.17.0)(typescript@5.7.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.17.0)(typescript@5.7.2))(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/parser': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + '@typescript-eslint/utils': 8.18.0(eslint@9.17.0)(typescript@5.7.2) + eslint: 9.17.0 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + typescript@5.7.2: {} + + uc.micro@2.1.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vite@5.4.11(sass@1.83.0): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.28.1 + optionalDependencies: + fsevents: 2.3.3 + sass: 1.83.0 + + vitefu@1.0.4(vite@5.4.11(sass@1.83.0)): + optionalDependencies: + vite: 5.4.11(sass@1.83.0) + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + yaml@1.10.2: {} + + yocto-queue@0.1.0: {} + + zimmerframe@1.1.2: {} diff --git a/Foxnouns.Frontend/src/app.d.ts b/Foxnouns.Frontend/src/app.d.ts index 243d72d..da08e6d 100644 --- a/Foxnouns.Frontend/src/app.d.ts +++ b/Foxnouns.Frontend/src/app.d.ts @@ -1,17 +1,7 @@ // See https://svelte.dev/docs/kit/types#app.d.ts - -import type { ErrorCode } from "$api/error"; - // for information about these interfaces declare global { namespace App { - interface Error { - message: string; - status: number; - code: ErrorCode; - errors?: Array<{ key: string; errors: ValidationError[] }>; - error_id?: string; - } // interface Error {} // interface Locals {} // interface PageData {} diff --git a/Foxnouns.Frontend/src/app.scss b/Foxnouns.Frontend/src/app.scss index c678355..e1d59ab 100644 --- a/Foxnouns.Frontend/src/app.scss +++ b/Foxnouns.Frontend/src/app.scss @@ -64,11 +64,3 @@ max-width: 200px; border-radius: 3px; } - -.big-footer { - @media (prefers-color-scheme: dark) { - background-color: bootstrap.shade-color(bootstrap.$dark, 20%); - } - - background-color: bootstrap.shade-color(bootstrap.$light, 5%); -} diff --git a/Foxnouns.Frontend/src/hooks.server.ts b/Foxnouns.Frontend/src/hooks.server.ts index 35a0048..e8ec723 100644 --- a/Foxnouns.Frontend/src/hooks.server.ts +++ b/Foxnouns.Frontend/src/hooks.server.ts @@ -1,10 +1,6 @@ -import ApiError, { ErrorCode } from "$api/error"; import { PRIVATE_API_HOST, PRIVATE_INTERNAL_API_HOST } from "$env/static/private"; -import { env } from "$env/dynamic/private"; import { PUBLIC_API_BASE } from "$env/static/public"; -import log from "$lib/log"; -import type { HandleFetch, HandleServerError } from "@sveltejs/kit"; -import * as Sentry from "@sentry/sveltekit"; +import type { HandleFetch } from "@sveltejs/kit"; export const handleFetch: HandleFetch = async ({ request, fetch }) => { if (request.url.startsWith(`${PUBLIC_API_BASE}/internal`)) { @@ -15,33 +11,3 @@ export const handleFetch: HandleFetch = async ({ request, fetch }) => { return await fetch(request); }; - -Sentry.init({ - dsn: env.PRIVATE_SENTRY_DSN, -}); - -export const handleError: HandleServerError = async ({ error, status, message }) => { - if (error instanceof ApiError) { - return { - status: error.raw?.status || status, - message: error.raw?.message || "Unknown error", - code: error.code, - }; - } - - if (status >= 400 && status <= 499) { - return { status, message, code: ErrorCode.GenericApiError }; - } - - // client errors and backend API errors just clog up sentry, so we don't send those. - const id = Sentry.captureException(error, { - mechanism: { - type: "sveltekit", - handled: false, - }, - }); - - log.error("[%s] error in handler:", id, error); - - return { error_id: id, status, message, code: ErrorCode.InternalServerError }; -}; diff --git a/Foxnouns.Frontend/src/lib/actions/callback.ts b/Foxnouns.Frontend/src/lib/actions/callback.ts index 5c525ab..3df1070 100644 --- a/Foxnouns.Frontend/src/lib/actions/callback.ts +++ b/Foxnouns.Frontend/src/lib/actions/callback.ts @@ -4,12 +4,10 @@ import type { AddAccountResponse, CallbackResponse } from "$api/models"; import { setToken } from "$lib"; import log from "$lib/log"; import { isRedirect, redirect, type ServerLoadEvent } from "@sveltejs/kit"; -import type { TicketData } from "../../routes/auth/callback/register/[ticket]/+page.server"; export default function createCallbackLoader( callbackType: string, bodyFn?: (event: ServerLoadEvent) => Promise, - returnData?: boolean, ) { return async (event: ServerLoadEvent) => { const { parent, fetch, cookies } = event; @@ -55,23 +53,12 @@ export default function createCallbackLoader( redirect(303, `/@${resp.user!.username}`); } - if (returnData) - return { - ticket: resp.ticket!, - remoteUser: resp.remote_username!, - }; - - const ticket = btoa( - JSON.stringify({ - type: callbackType, - ticket: resp.ticket!, - remoteUsername: resp.remote_username!, - } satisfies TicketData), - ) - .replaceAll("+", "-") - .replaceAll("/", "_"); - - redirect(303, "/auth/callback/register/" + ticket); + return { + hasAccount: false, + isLinkRequest: false, + ticket: resp.ticket!, + remoteUser: resp.remote_username!, + }; } catch (e) { if (isRedirect(e)) throw e; if (e instanceof ApiError) return { isLinkRequest: false, error: e.obj }; diff --git a/Foxnouns.Frontend/src/lib/actions/modaction.ts b/Foxnouns.Frontend/src/lib/actions/modaction.ts deleted file mode 100644 index 15fd16f..0000000 --- a/Foxnouns.Frontend/src/lib/actions/modaction.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { apiRequest } from "$api"; -import ApiError, { ErrorCode, type RawApiError } from "$api/error"; -import type { AuditLogEntry, ClearableField } from "$api/models/moderation"; -import log from "$lib/log"; -import { type RequestEvent } from "@sveltejs/kit"; - -type ModactionResponse = { ok: boolean; resp: AuditLogEntry | null; error: RawApiError | null }; -type ModactionFunction = (evt: RequestEvent) => Promise; - -export default function createModactionAction( - type: "ignore" | "warn" | "suspend", - requireReason: boolean, -): ModactionFunction { - return async function ({ request, fetch, cookies }) { - const body = await request.formData(); - const userId = body.get("user") as string; - const memberId = body.get("member") as string | null; - const reportId = body.get("report") as string | null; - const reason = body.get("reason") as string | null; - - if (!reportId && type === "ignore") { - return { - ok: false, - resp: null, - error: { - status: 400, - message: "Bad request", - code: ErrorCode.BadRequest, - errors: [ - { key: "report", errors: [{ message: "Ignoring a report requires a report ID" }] }, - ], - } satisfies RawApiError, - }; - } - - if (!reason && requireReason) { - return { - ok: false, - resp: null, - error: { - status: 400, - message: "Bad request", - code: ErrorCode.BadRequest, - errors: [{ key: "reason", errors: [{ message: "You must give a reason" }] }], - } satisfies RawApiError, - }; - } - - let clearFields: ClearableField[] | undefined = undefined; - if (type === "warn") { - clearFields = body.getAll("clear-fields") as ClearableField[]; - } - - let path: string; - if (type === "warn") path = `/moderation/warnings/${userId}`; - else if (type === "suspend") path = `/moderation/suspensions/${userId}`; - else path = `/moderation/reports/${reportId}/ignore`; - - try { - const resp = await apiRequest("POST", path, { - fetch, - cookies, - body: { - reason: reason, - // These are ignored by POST /reports/{id}/ignore - member_id: memberId, - report_id: reportId, - // This is ignored by everything but POST /warnings/{id} - clear_fields: clearFields, - // This is ignored by everything but POST /suspensions/{id} - clear_profile: !!body.get("clear-profile"), - }, - }); - - return { ok: true, resp, error: null }; - } catch (e) { - if (e instanceof ApiError) return { ok: false, error: e.obj, resp: null }; - log.error("could not take action on %s:", path, e); - throw e; - } - }; -} - -export function createModactions() { - return { - ignore: createModactionAction("ignore", false), - warn: createModactionAction("warn", true), - suspend: createModactionAction("suspend", true), - }; -} diff --git a/Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.server.ts b/Foxnouns.Frontend/src/lib/actions/register.ts similarity index 62% rename from Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.server.ts rename to Foxnouns.Frontend/src/lib/actions/register.ts index b14c1a2..d3c126d 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.server.ts +++ b/Foxnouns.Frontend/src/lib/actions/register.ts @@ -3,23 +3,10 @@ import ApiError, { ErrorCode, type RawApiError } from "$api/error"; import type { AuthResponse } from "$api/models/auth"; import { setToken } from "$lib"; import log from "$lib/log"; -import { isRedirect, redirect } from "@sveltejs/kit"; - -export type TicketData = { - type: string; - ticket: string; - remoteUsername: string; -}; - -export const load = async ({ params }) => { - const data = JSON.parse(atob(params.ticket)) as TicketData; - return data; -}; - -export const actions = { - default: async ({ request, fetch, cookies, params }) => { - const type = (JSON.parse(atob(params.ticket)) as TicketData).type; +import { isRedirect, redirect, type RequestEvent } from "@sveltejs/kit"; +export default function createRegisterAction(callbackUrl: string) { + return async function ({ request, fetch, cookies }: RequestEvent) { const data = await request.formData(); const username = data.get("username") as string | null; const ticket = data.get("ticket") as string | null; @@ -30,7 +17,7 @@ export const actions = { }; try { - const resp = await apiRequest("POST", `/auth/${type}/register`, { + const resp = await apiRequest("POST", callbackUrl, { body: { username, ticket }, isInternal: true, fetch, @@ -44,5 +31,5 @@ export const actions = { if (e instanceof ApiError) return { error: e.obj }; throw e; } - }, -}; + }; +} diff --git a/Foxnouns.Frontend/src/lib/api/error.ts b/Foxnouns.Frontend/src/lib/api/error.ts index e893a86..1fd2041 100644 --- a/Foxnouns.Frontend/src/lib/api/error.ts +++ b/Foxnouns.Frontend/src/lib/api/error.ts @@ -14,7 +14,6 @@ export default class ApiError { toObject(): RawApiError { return { - error_id: this.raw?.error_id, status: this.raw?.status || 500, code: this.code, message: this.raw?.message || "Internal server error", @@ -24,7 +23,6 @@ export default class ApiError { } export type RawApiError = { - error_id?: string; status: number; message: string; code: ErrorCode; @@ -43,7 +41,6 @@ export enum ErrorCode { MemberNotFound = "MEMBER_NOT_FOUND", AccountAlreadyLinked = "ACCOUNT_ALREADY_LINKED", LastAuthMethod = "LAST_AUTH_METHOD", - PageNotFound = "PAGE_NOT_FOUND", // This code isn't actually returned by the API Non204Response = "(non 204 response)", } diff --git a/Foxnouns.Frontend/src/lib/api/index.ts b/Foxnouns.Frontend/src/lib/api/index.ts index e52918a..0a4047d 100644 --- a/Foxnouns.Frontend/src/lib/api/index.ts +++ b/Foxnouns.Frontend/src/lib/api/index.ts @@ -9,7 +9,7 @@ export type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE"; /** * Optional arguments for a request. `load` and `action` functions should always pass `fetch` and `cookies`. */ -export type RequestArgs = { +export type RequestArgs = { /** * The token for this request. Where possible, `cookies` should be passed instead. * Will override `cookies` if both are passed. @@ -23,7 +23,7 @@ export type RequestArgs = { /** * The body for this request, which will be serialized to JSON. Should be a plain JS object. */ - body?: T; + body?: unknown; /** * The fetch function to use. Should be passed in loader and action functions, but can be safely ignored for client-side requests. */ @@ -41,10 +41,10 @@ export type RequestArgs = { * @param args Optional arguments to the request function. * @returns A Response object. */ -export async function baseRequest( +export async function baseRequest( method: Method, path: string, - args: RequestArgs = {}, + args: RequestArgs = {}, ): Promise { const token = args.token ?? args.cookies?.get(TOKEN_COOKIE_NAME); @@ -72,20 +72,19 @@ export async function baseRequest( * @param args Optional arguments to the request function. * @returns The response deserialized as `T`. */ -export async function apiRequest( +export async function apiRequest( method: Method, path: string, - args: RequestArgs = {}, -): Promise { + args: RequestArgs = {}, +): Promise { const resp = await baseRequest(method, path, args); if (resp.status < 200 || resp.status > 299) { const err = await resp.json(); - log.error("Received error for request to %s %s:", method, path, err); if ("code" in err) throw new ApiError(err); else throw new ApiError(); } - return (await resp.json()) as TResponse; + return (await resp.json()) as T; } /** @@ -95,10 +94,10 @@ export async function apiRequest( * @param args Optional arguments to the request function. * @param enforce204 Whether to throw an error on a non-204 status code. */ -export async function fastRequest( +export async function fastRequest( method: Method, path: string, - args: RequestArgs = {}, + args: RequestArgs = {}, enforce204: boolean = false, ): Promise { const resp = await baseRequest(method, path, args); diff --git a/Foxnouns.Frontend/src/lib/api/models/meta.ts b/Foxnouns.Frontend/src/lib/api/models/meta.ts index 28ea494..56f31c9 100644 --- a/Foxnouns.Frontend/src/lib/api/models/meta.ts +++ b/Foxnouns.Frontend/src/lib/api/models/meta.ts @@ -10,7 +10,6 @@ export type Meta = { }; members: number; limits: Limits; - notice: { id: string; message: string } | null; }; export type Limits = { diff --git a/Foxnouns.Frontend/src/lib/api/models/moderation.ts b/Foxnouns.Frontend/src/lib/api/models/moderation.ts deleted file mode 100644 index 689e9b8..0000000 --- a/Foxnouns.Frontend/src/lib/api/models/moderation.ts +++ /dev/null @@ -1,123 +0,0 @@ -import type { Member } from "./member"; -import type { AuthMethod, PartialMember, PartialUser, User } from "./user"; - -export type CreateReportRequest = { - reason: ReportReason; - context: string | null; -}; - -export enum ReportReason { - Totalitarianism = "TOTALITARIANISM", - HateSpeech = "HATE_SPEECH", - Racism = "RACISM", - Homophobia = "HOMOPHOBIA", - Transphobia = "TRANSPHOBIA", - Queerphobia = "QUEERPHOBIA", - Exclusionism = "EXCLUSIONISM", - Sexism = "SEXISM", - Ableism = "ABLEISM", - ChildPornography = "CHILD_PORNOGRAPHY", - PedophiliaAdvocacy = "PEDOPHILIA_ADVOCACY", - Harassment = "HARASSMENT", - Impersonation = "IMPERSONATION", - Doxxing = "DOXXING", - EncouragingSelfHarm = "ENCOURAGING_SELF_HARM", - Spam = "SPAM", - Trolling = "TROLLING", - Advertisement = "ADVERTISEMENT", - CopyrightViolation = "COPYRIGHT_VIOLATION", -} - -export type Report = { - id: string; - reporter: PartialUser; - target_user: PartialUser; - target_member?: PartialMember; - status: "OPEN" | "CLOSED"; - reason: ReportReason; - context: string | null; - target_type: "USER" | "MEMBER"; - snapshot: User | Member | null; -}; - -export type AuditLogEntry = { - id: string; - moderator: AuditLogEntity; - target_user?: AuditLogEntity; - target_member?: AuditLogEntity; - report?: PartialReport; - type: AuditLogEntryType; - reason: string | null; - cleared_fields?: string[]; -}; - -export type AuditLogEntity = { id: string; username: string }; - -export enum AuditLogEntryType { - IgnoreReport = "IGNORE_REPORT", - WarnUser = "WARN_USER", - WarnUserAndClearProfile = "WARN_USER_AND_CLEAR_PROFILE", - SuspendUser = "SUSPEND_USER", - QuerySensitiveUserData = "QUERY_SENSITIVE_USER_DATA", -} - -export type PartialReport = { - id: string; - reporter_id: string; - target_user_id: string; - target_member_id?: string; - reason: ReportReason; - context: string | null; - target_type: "USER" | "MEMBER"; -}; - -export type ReportDetails = { - report: Report; - user: User; - member?: Member; - audit_log_entry?: AuditLogEntry; -}; - -export type QueriedUser = { - user: User; - member_list_hidden: boolean; - last_active: string; - last_sid_reroll: string; - suspended: boolean; - deleted: boolean; - auth_methods?: AuthMethod[]; -}; - -export type WarnUserRequest = { - reason: string; - clear_fields?: ClearableField[]; - member_id?: string; - report_id?: string; -}; - -export type SuspendUserRequest = { - reason: string; - clear_profile: boolean; - report_id?: string; -}; - -export enum ClearableField { - DisplayName = "DISPLAY_NAME", - Avatar = "AVATAR", - Bio = "BIO", - Links = "LINKS", - Names = "NAMES", - Pronouns = "PRONOUNS", - Fields = "FIELDS", - Flags = "FLAGS", - CustomPreferences = "CUSTOM_PREFERENCES", -} - -export type Notification = { - id: string; - type: "NOTICE" | "WARNING" | "SUSPENSION"; - message?: string; - localization_key?: string; - localization_params: Record; - acknowledged: boolean; -}; diff --git a/Foxnouns.Frontend/src/lib/api/models/user.ts b/Foxnouns.Frontend/src/lib/api/models/user.ts index be9d961..6cd8e4c 100644 --- a/Foxnouns.Frontend/src/lib/api/models/user.ts +++ b/Foxnouns.Frontend/src/lib/api/models/user.ts @@ -28,7 +28,6 @@ export type MeUser = UserWithMembers & { timezone: string; suspended: boolean; deleted: boolean; - settings: UserSettings; }; export type UserWithMembers = User & { members: PartialMember[] | null }; @@ -41,7 +40,6 @@ export type UserWithHiddenFields = User & { export type UserSettings = { dark_mode: boolean | null; - last_read_notice: string | null; }; export type PartialMember = { diff --git a/Foxnouns.Frontend/src/lib/components/ClientPaginator.svelte b/Foxnouns.Frontend/src/lib/components/ClientPaginator.svelte index 7b08026..7f72ca2 100644 --- a/Foxnouns.Frontend/src/lib/components/ClientPaginator.svelte +++ b/Foxnouns.Frontend/src/lib/components/ClientPaginator.svelte @@ -5,11 +5,8 @@ currentPage: number; pageCount: number; center?: boolean; - listAllPages?: boolean; }; - let { currentPage = $bindable(), pageCount, center, listAllPages }: Props = $props(); - - let allPages = $derived(listAllPages === undefined || listAllPages); + let { currentPage = $bindable(), pageCount, center }: Props = $props(); let prevPage = $derived(currentPage > 0 ? currentPage - 1 : 0); let nextPage = $derived(currentPage < pageCount - 1 ? currentPage + 1 : pageCount - 1); @@ -24,27 +21,11 @@ (currentPage = prevPage)} /> - {#if allPages} - {#each new Array(pageCount) as _, page} - - (currentPage = page)}>{page + 1} - - {/each} - {:else} - {#if currentPage !== 0} - (currentPage = prevPage)}> - {currentPage} - - {/if} - - {currentPage + 1} + {#each new Array(pageCount) as _, page} + + (currentPage = page)}>{page + 1} - {#if currentPage !== pageCount - 1} - (currentPage = nextPage)}> - {currentPage + 2} - - {/if} - {/if} + {/each} (currentPage = nextPage)} /> diff --git a/Foxnouns.Frontend/src/lib/components/Error.svelte b/Foxnouns.Frontend/src/lib/components/Error.svelte index c9e2c0e..64f3bc7 100644 --- a/Foxnouns.Frontend/src/lib/components/Error.svelte +++ b/Foxnouns.Frontend/src/lib/components/Error.svelte @@ -12,22 +12,12 @@ {#if error.code === ErrorCode.BadRequest} {$t("error.bad-request-header")} - {:else if error.status === 404} - {$t("error.not-found-header")} {:else} {$t("error.generic-header")} {/if} {/if}

{errorDescription($t, error.code)}

-{#if error.error_id} -

- {$t("error.error-id")} - - {error.error_id} - -

-{/if} {#if error.errors}
{$t("error.extra-info-header")} diff --git a/Foxnouns.Frontend/src/lib/components/Footer.svelte b/Foxnouns.Frontend/src/lib/components/Footer.svelte deleted file mode 100644 index 857c07c..0000000 --- a/Foxnouns.Frontend/src/lib/components/Footer.svelte +++ /dev/null @@ -1,84 +0,0 @@ - - - diff --git a/Foxnouns.Frontend/src/lib/components/GlobalNotice.svelte b/Foxnouns.Frontend/src/lib/components/GlobalNotice.svelte deleted file mode 100644 index c8a55f1..0000000 --- a/Foxnouns.Frontend/src/lib/components/GlobalNotice.svelte +++ /dev/null @@ -1,50 +0,0 @@ - - -{#if renderNotice} - -{/if} diff --git a/Foxnouns.Frontend/src/lib/components/Navbar.svelte b/Foxnouns.Frontend/src/lib/components/Navbar.svelte index 2074347..68c1b14 100644 --- a/Foxnouns.Frontend/src/lib/components/Navbar.svelte +++ b/Foxnouns.Frontend/src/lib/components/Navbar.svelte @@ -8,39 +8,29 @@ NavLink, NavItem, } from "@sveltestrap/sveltestrap"; - import { page } from "$app/state"; + import { page } from "$app/stores"; import type { Meta, MeUser } from "$api/models/index"; import Logo from "$components/Logo.svelte"; import { t } from "$lib/i18n"; - type Props = { user: MeUser | null; meta: Meta; unreadNotifications?: boolean }; - let { user, meta, unreadNotifications }: Props = $props(); + type Props = { user: MeUser | null; meta: Meta }; + let { user, meta }: Props = $props(); let isOpen = $state(true); const toggleMenu = () => (isOpen = !isOpen); -{#if user && unreadNotifications} -
- {$t("nav.unread-notification-text")} -
- {$t("nav.unread-notification-link")} -
-{/if} - {#if user && user.deleted} {/if} @@ -61,26 +51,19 @@ @{user.username} - {#if user.role === "ADMIN" || user.role === "MODERATOR"} - - - Administration - - - {/if} - + {$t("nav.settings")} {:else} - + {$t("nav.log-in")} @@ -95,11 +78,6 @@ background-color: var(--bs-danger-bg-subtle); } - .notification-alert { - color: var(--bs-warning-text-emphasis); - background-color: var(--bs-warning-bg-subtle); - } - /* These exact values make it look almost identical to the SVG version, which is what we want */ #beta-text { font-size: 0.7em; diff --git a/Foxnouns.Frontend/src/lib/components/RequiredFieldMarker.svelte b/Foxnouns.Frontend/src/lib/components/RequiredFieldMarker.svelte deleted file mode 100644 index f67d9ef..0000000 --- a/Foxnouns.Frontend/src/lib/components/RequiredFieldMarker.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - -{#if required} - * -{:else} - {$t("form.optional")} -{/if} diff --git a/Foxnouns.Frontend/src/lib/components/URLAlert.svelte b/Foxnouns.Frontend/src/lib/components/URLAlert.svelte deleted file mode 100644 index 72689ab..0000000 --- a/Foxnouns.Frontend/src/lib/components/URLAlert.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -{#if key} -
- {$t(key)} -
-{/if} diff --git a/Foxnouns.Frontend/src/lib/components/admin/ActionForm.svelte b/Foxnouns.Frontend/src/lib/components/admin/ActionForm.svelte deleted file mode 100644 index 3c7f741..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/ActionForm.svelte +++ /dev/null @@ -1,73 +0,0 @@ - - -
- - {#if memberId} - - {/if} - {#if reportId} - - {/if} - - - - {#if reportId} - - - - {/if} - -
- {#each fields as field} -
- - -
- {/each} -
-
- -
-
- -
- - -
- -
-
- diff --git a/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntity.svelte b/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntity.svelte deleted file mode 100644 index 1f3645f..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntity.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - -{entity.username} ({entity.id}) diff --git a/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntryCard.svelte b/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntryCard.svelte deleted file mode 100644 index b1d777a..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/AuditLogEntryCard.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - -
-
- - - {#if entry.type === "IGNORE_REPORT"} - ignored a report - {:else if entry.type === "WARN_USER" || entry.type === "WARN_USER_AND_CLEAR_PROFILE"} - warned - {:else if entry.type === "SUSPEND_USER"} - suspended - {:else if entry.type === "QUERY_SENSITIVE_USER_DATA"} - looked up sensitive data of - {:else} - (unknown action {entry.type}) - {/if} - {#if entry.target_user} - - {/if} - {#if entry.target_member} - for member - {/if} - - - {date} -
- - {#if entry.type === "IGNORE_REPORT"} - {#if entry.report} -
- Report -
    -
  • From: {entry.report.reporter_id}
  • -
  • Target: {entry.report.target_user_id}
  • -
  • Reason: {entry.report.reason}
  • - {#if entry.report.context} -
  • Context: {entry.report.context}
  • - {/if} -
-
- {:else} -

(the ignored report has been deleted)

- {/if} - {/if} - - {#if reason} -
- Reason - - {@html reason} -
- {:else} -

(no reason given)

- {/if} -
diff --git a/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte b/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte deleted file mode 100644 index 589539f..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/ClosedReportAuditLog.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - -
-

- Closed by at - {idTimestamp(entry.id).toLocaleString(DateTime.DATETIME_MED)} -

-

- {#if entry.type === AuditLogEntryType.IgnoreReport} - Report was ignored - {:else if entry.type === AuditLogEntryType.WarnUser || entry.type === AuditLogEntryType.WarnUserAndClearProfile} - User was warned - {#if entry.cleared_fields && entry.cleared_fields.length > 0} -
Cleared fields: {entry.cleared_fields.join(", ")} - {/if} - {:else if entry.type === AuditLogEntryType.SuspendUser} - User was suspended - {/if} -

-

Reason

-

- {#if entry.reason} - - {@html renderMarkdown(entry.reason)} - {:else} - (no reason given) - {/if} -

-
diff --git a/Foxnouns.Frontend/src/lib/components/admin/DashboardCard.svelte b/Foxnouns.Frontend/src/lib/components/admin/DashboardCard.svelte deleted file mode 100644 index a6d04e4..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/DashboardCard.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -
-
-
-
{title}
-

- {@render children()} -

-
-
-
diff --git a/Foxnouns.Frontend/src/lib/components/admin/PartialProfileCard.svelte b/Foxnouns.Frontend/src/lib/components/admin/PartialProfileCard.svelte deleted file mode 100644 index 885ca82..0000000 --- a/Foxnouns.Frontend/src/lib/components/admin/PartialProfileCard.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - -
- - - -

- - @{user.username} - -

-

Created {createdAt}

-
diff --git a/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte index 288bcc5..e18c6b6 100644 --- a/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte +++ b/Foxnouns.Frontend/src/lib/components/editor/AvatarEditor.svelte @@ -1,8 +1,7 @@ @@ -86,41 +44,6 @@

- (cropperOpen = !cropperOpen)} -> - - - - - - - {#if meUser && meUser.username !== user} - {$t("profile.report-button")} - {/if} - diff --git a/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte b/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte index f1c7964..692146a 100644 --- a/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte +++ b/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte @@ -2,8 +2,8 @@ import { t } from "$lib/i18n"; import type { AuthMethod } from "$api/models"; - type Props = { method: AuthMethod; canRemove: boolean; showType?: boolean }; - let { method, canRemove, showType }: Props = $props(); + type Props = { method: AuthMethod; canRemove: boolean }; + let { method, canRemove }: Props = $props(); let name = $derived( method.type === "EMAIL" ? method.remote_id : (method.remote_username ?? method.remote_id), @@ -14,9 +14,6 @@
- {#if showType} - {method.type}: - {/if} {name} {#if showId}({method.remote_id}){/if}
diff --git a/Foxnouns.Frontend/src/lib/components/settings/Notification.svelte b/Foxnouns.Frontend/src/lib/components/settings/Notification.svelte deleted file mode 100644 index 796d60a..0000000 --- a/Foxnouns.Frontend/src/lib/components/settings/Notification.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - -
-
-
- -
-

- {#if notification.localization_key} - {$t(notification.localization_key, notification.localization_params)} - {:else} - {notification.message} - {/if} -

-
-
-
- -
diff --git a/Foxnouns.Frontend/src/lib/errorCodes.ts b/Foxnouns.Frontend/src/lib/errorCodes.ts index 8b8ef44..b97b71b 100644 --- a/Foxnouns.Frontend/src/lib/errorCodes.ts +++ b/Foxnouns.Frontend/src/lib/errorCodes.ts @@ -29,8 +29,6 @@ export default function errorDescription(t: TranslateFn, code: ErrorCode): strin return t("error.account-already-linked"); case ErrorCode.LastAuthMethod: return t("error.last-auth-method"); - case ErrorCode.PageNotFound: - return t("error.page-not-found"); case ErrorCode.Non204Response: return t("error.generic-error"); } diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json index 22428f7..2ede9a1 100644 --- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json +++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json @@ -5,13 +5,9 @@ "settings": "Settings", "suspended-account-hint": "Your account has been suspended. Your profile has been hidden and you will not be able to change any settings.", "appeal-suspension-link": "I want to appeal", - "deleted-account-hint": "You have requested deletion of your account.", + "deleted-account-hint": "You have requested deletion of your account. If you want to reactivate it, click the link below.", "reactivate-account-link": "Reactivate account", - "delete-permanently-link": "I want my account deleted permanently", - "reactivate-or-delete-link": "I want to reactivate my account or delete all my data", - "export-link": "I want to export a copy of my data", - "unread-notification-text": "You have an unread notification.", - "unread-notification-link": "Go to your notifications" + "delete-permanently-link": "I want my account deleted permanently" }, "avatar-tooltip": "Avatar for {{name}}", "profile": { @@ -22,10 +18,7 @@ "pronouns-header": "Pronouns", "default-members-header": "Members", "create-member-button": "Create member", - "back-to-user": "Back to {{name}}", - "copy-link-button": "Copy link", - "copy-short-link-button": "Copy short link", - "report-button": "Report profile" + "back-to-user": "Back to {{name}}" }, "title": { "log-in": "Log in", @@ -48,7 +41,7 @@ "remote-fediverse-account-label": "Your Fediverse account", "register-username-label": "Username", "register-button": "Register account", - "register-with-fediverse": "Register with a Fediverse account", + "register-with-mastodon": "Register with a Fediverse account", "log-in-with-fediverse-error-blurb": "Is your instance returning an error?", "log-in-with-fediverse-force-refresh-button": "Force a refresh on our end", "register-with-discord": "Register with a Discord account", @@ -79,17 +72,7 @@ "log-in-sign-up-link": "Sign up with email", "forgot-password-title": "Forgot password", "reset-password-title": "Reset password", - "password-changed-hint": "Your password has been changed!", - "link-email-header": "Link a new email address", - "unlink-email-header": "Unlink email address", - "unlink-fediverse-header": "Unlink fediverse account", - "unlink-tumblr-header": "Unlink Tumblr account", - "unlink-google-header": "Unlink Google account", - "unlink-discord-header": "Unlink Discord account", - "unlink-confirmation-1": "Are you sure you want to unlink {{username}} from your account?", - "unlink-confirmation-2": "You will no longer be able to use this account to log in. Please make sure at least one of your other linked accounts is accessible before continuing.", - "unlink-button": "Unlink account", - "log-in-3rd-party-desc-no-email": "You can use any of the following services to log in. You can add or remove others at any time." + "password-changed-hint": "Your password has been changed!" }, "error": { "bad-request-header": "Something was wrong with your input", @@ -122,10 +105,7 @@ "back-to-prev-page-button": "Go back to the previous page", "400-description": "Something went wrong with your request. This error should never land you on this page, so it's probably a bug.", "500-description": "Something went wrong on the server. Please try again later.", - "unknown-status-description": "Something went wrong, but we're not sure what. Please try again.", - "error-id": "If you report this error to the developers, please give them this ID:", - "page-not-found": "No page exists at this URL.", - "not-found-header": "That page could not be found" + "unknown-status-description": "Something went wrong, but we're not sure what. Please try again." }, "settings": { "general-information-tab": "General information", @@ -172,44 +152,7 @@ "flag-description-placeholder": "Description", "flag-name-placeholder": "Name", "flag-upload-success": "Successfully uploaded your flag! It may take a few seconds before it's saved.", - "custom-preferences-title": "Custom preferences", - "change-username-header": "Change your username", - "force-delete-button": "Delete my account permanently", - "force-delete-warning": "This is irreversible. Consider exporting a copy of your data before doing this.", - "force-delete-explanation": "Your account is currently pending deletion. If you want your data deleted permanently, use the button below.", - "reactivate-explanation": "Your account is currently pending deletion. If you want to cancel this and keep using your account, use the link below.", - "reactivate-header": "Reactivate your account", - "force-delete-header": "Permanently delete your account", - "reactivate-button": "Reactivate my account", - "reactivated-header": "Account reactivated", - "reactivated-explanation": "Your account has been reactivated!", - "force-delete-input-label": "To delete your account, type your username (@{{username}}), including the @, in the box below:", - "force-delete-export-hint": "If you haven't done so yet, we recommend you download an export of your data before continuing:", - "force-delete-export-link": "export your data", - "force-delete-irreversible": "This process is irreversible.", - "force-delete-username-available": "Your username will immediately be available for other users to take.", - "force-delete-immediate-delete": "This will immediately delete all of your profiles, including avatars.", - "force-delete-page-explanation": "Your account is currently pending deletion. If you want all your data deleted immediately, you can do so here.", - "force-delete-page-header": "Permanently delete your account", - "force-delete-checkbox-label": "Yes, I understand that my data will be permanently deleted and cannot be recovered.", - "force-delete-page-button": "Delete my account", - "account-is-deleted-header": "Your account has been deleted", - "account-is-deleted-permanently-description": "Your account has been deleted. Note that it may take a few minutes for all of your data to be removed.", - "account-is-deleted-close-page": "You may now close this page.", - "soft-delete-button": "Deactivate your account", - "soft-delete-hint": "If you want to delete your account, use the button below.", - "soft-delete-header": "Deactivate your account", - "force-delete-page-cancel": "I changed my mind, cancel", - "soft-delete-page-header": "Deactivate your account", - "soft-delete-page-explanation": "If you want to delete your account, you can do so here.", - "soft-delete-90-days": "Your account will be permanently deleted after 90 days.", - "soft-delete-can-reactivate": "If you change your mind, you can log in and go to the settings page at any time to reactivate your account.", - "soft-delete-keep-username": "You will keep your current username until your account is permanently deleted.", - "soft-delete-can-delete-permanently": "If you want to delete all your data early, you can do so by logging in and going to the settings page.", - "soft-delete-page-button": "Deactivate my account", - "soft-delete-input-label": "To deactivate your account, type your username (@{{username}}), including the @, in the box below:", - "account-is-deactivated-header": "Your account has been deactivated", - "account-is-deactivated-description": "Your account has been deactivated, and will be deleted in 90 days. If you change your mind, just log in again, and you will have the option to reactivate your account. If you want to delete your data immediately, you should also log in again, and you will be able to request immediate deletion." + "custom-preferences-title": "Custom preferences" }, "yes": "Yes", "no": "No", @@ -292,67 +235,7 @@ "custom-preference-size-small": "Small", "custom-preference-size": "Text size", "custom-preference-muted": "Show as muted text", - "custom-preference-favourite": "Treat like favourite", - "custom-preference-notice": "Want to edit your custom preferences?", - "custom-preference-notice-link": "Go to settings", - "crop-avatar-header": "Crop avatar", - "crop-avatar-button": "Crop", - "max-custom-preferences": "You have reached the maximum amount of custom preferences ({{current}}/{{max}}), and cannot add new ones." + "custom-preference-favourite": "Treat like favourite" }, - "cancel": "Cancel", - "report": { - "title": "Reporting {{name}}", - "totalitarianism": "Support of totalitarian regimes", - "hate-speech": "Hate speech", - "racism": "Racism or xenophobia", - "homophobia": "Homophobia", - "transphobia": "Transphobia", - "queerphobia": "Queerphobia (other)", - "exclusionism": "Queer or plural exclusionism", - "sexism": "Sexism or misogyny", - "ableism": "Ableism", - "child-pornography": "Child pornography", - "pedophilia-advocacy": "Pedophilia advocacy", - "harassment": "Harassment", - "impersonation": "Impersonation", - "doxxing": "Doxxing", - "encouraging-self-harm": "Encouraging self-harm or suicide", - "spam": "Spam", - "trolling": "Trolling", - "advertisement": "Advertising", - "copyright-violation": "Copyright or trademark violation", - "success": "Successfully submitted report!", - "reason-label": "Why are you reporting this profile?", - "context-label": "Is there any context you'd like to give us?", - "submit-button": "Submit report" - }, - "form": { - "optional": "(optional)", - "required": "Required" - }, - "alert": { - "auth-method-remove-success": "Successfully unlinked account!", - "auth-required": "You must log in to access this page.", - "notif-ack-successful": "Successfully marked notification as read!", - "notif-ack-fail": "Could not mark notification as read." - }, - "footer": { - "version": "Version", - "users": "users", - "members": "members", - "source": "Source code", - "status": "Status", - "terms": "Terms of service", - "privacy": "Privacy policy", - "changelog": "Changelog", - "donate": "Donate", - "about-contact": "About and contact" - }, - "notification": { - "suspension": "Your account has been suspended for the following reason: {{reason}}", - "warning": "You have been warned for the following reason: {{reason}}", - "warning-cleared-fields": "You have been warned for the following reason: {{reason}}\n\nAdditionally, the following fields have been cleared from your profile:\n{{clearedFields}}", - "mark-as-read": "Mark as read", - "no-notifications": "You have no notifications." - } + "cancel": "Cancel" } diff --git a/Foxnouns.Frontend/src/lib/index.ts b/Foxnouns.Frontend/src/lib/index.ts index 42d3314..fdf8885 100644 --- a/Foxnouns.Frontend/src/lib/index.ts +++ b/Foxnouns.Frontend/src/lib/index.ts @@ -9,10 +9,9 @@ export const setToken = (cookies: Cookies, token: string) => cookies.set(TOKEN_COOKIE_NAME, token, { path: "/" }); export const clearToken = (cookies: Cookies) => cookies.delete(TOKEN_COOKIE_NAME, { path: "/" }); +// TODO: change this to something we actually clearly have the rights to use +export const DEFAULT_AVATAR = "https://pronouns.cc/default/512.webp"; export const DEFAULT_FLAG = "/unknown_flag.svg"; export const idTimestamp = (id: string) => DateTime.fromMillis(parseInt(id, 10) / (1 << 22) + 1_640_995_200_000); - -export const alertKey = (url: URL): string | undefined => - url.searchParams.has("alert") ? "alert." + url.searchParams.get("alert") : undefined; diff --git a/Foxnouns.Frontend/src/lib/markdown.ts b/Foxnouns.Frontend/src/lib/markdown.ts index 9c4ff35..94a1a05 100644 --- a/Foxnouns.Frontend/src/lib/markdown.ts +++ b/Foxnouns.Frontend/src/lib/markdown.ts @@ -7,7 +7,11 @@ const md = new MarkdownIt({ linkify: true, }).disable(["heading", "lheading", "link", "table", "blockquote"]); -const unsafeMd = new MarkdownIt(); +const unsafeMd = new MarkdownIt({ + html: false, + breaks: true, + linkify: true, +}); export const renderMarkdown = (src: string | null) => (src ? sanitize(md.render(src)) : null); diff --git a/Foxnouns.Frontend/src/lib/pageUtils.svelte.ts b/Foxnouns.Frontend/src/lib/pageUtils.svelte.ts deleted file mode 100644 index 5f45815..0000000 --- a/Foxnouns.Frontend/src/lib/pageUtils.svelte.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { page } from "$app/state"; - -export const isActive = (path: string | string[], prefix: boolean = false) => - typeof path === "string" - ? prefix - ? page.url.pathname.startsWith(path) - : page.url.pathname === path - : prefix - ? path.some((p) => page.url.pathname.startsWith(p)) - : path.some((p) => page.url.pathname === p); diff --git a/Foxnouns.Frontend/src/lib/state.svelte.ts b/Foxnouns.Frontend/src/lib/state.svelte.ts deleted file mode 100644 index 8358bf3..0000000 --- a/Foxnouns.Frontend/src/lib/state.svelte.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { onMount, onDestroy } from "svelte"; -import { browser } from "$app/environment"; -import log from "./log"; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { Snapshot } from "@sveltejs/kit"; - -/** - * Store ephemeral state in sessionStorage to persist between navigations. - * Similar to {@link Snapshot}, but doesn't attach it to a history entry. - * @param key Unique key to use for this state. - * @param capture Function that returns the state to store. - * @param restore Function that takes the state that was stored previously and assigns it back to component variables. - */ -export default function ephemeralState( - key: string, - capture: () => T, - restore: (data: T) => void, -): void { - if (!browser) return; - - onMount(() => { - if (!("sessionStorage" in window)) return; - const rawData = sessionStorage.getItem("ephemeral-" + key); - if (!rawData) return; - - log.debug("Restoring data %s from session storage", key); - const data = JSON.parse(rawData) as T; - restore(data); - }); - - onDestroy(() => { - if (!("sessionStorage" in window)) return; - - log.debug("Saving data %s to session storage", key); - sessionStorage.setItem("ephemeral-" + key, JSON.stringify(capture())); - }); -} diff --git a/Foxnouns.Frontend/src/routes/+error.svelte b/Foxnouns.Frontend/src/routes/+error.svelte index e667611..ca116b9 100644 --- a/Foxnouns.Frontend/src/routes/+error.svelte +++ b/Foxnouns.Frontend/src/routes/+error.svelte @@ -1,6 +1,5 @@ -
-
- - {@render children?.()} -
-
-
+ + +{@render children?.()} diff --git a/Foxnouns.Frontend/src/routes/+page.svelte b/Foxnouns.Frontend/src/routes/+page.svelte index 4fd36dc..47ab0e5 100644 --- a/Foxnouns.Frontend/src/routes/+page.svelte +++ b/Foxnouns.Frontend/src/routes/+page.svelte @@ -1,5 +1,4 @@ - - diff --git a/Foxnouns.Frontend/src/routes/admin/+page.svelte b/Foxnouns.Frontend/src/routes/admin/+page.svelte deleted file mode 100644 index bf0c8f7..0000000 --- a/Foxnouns.Frontend/src/routes/admin/+page.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - - - Admin dashboard • pronouns.cc - - -

Dashboard

- -
- - {data.meta.users.total.toLocaleString("en")} -
- ({data.meta.users.active_month.toLocaleString("en")} active in the last month) -
- {data.meta.members.toLocaleString("en")} - - {data.reportCount.toLocaleString("en")} -
- ({data.staleReportCount} older than 1 week) -
-
diff --git a/Foxnouns.Frontend/src/routes/admin/audit-log/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/audit-log/+page.server.ts deleted file mode 100644 index f48e334..0000000 --- a/Foxnouns.Frontend/src/routes/admin/audit-log/+page.server.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { apiRequest } from "$api"; -import { type AuditLogEntity, type AuditLogEntry } from "$api/models/moderation.js"; - -export const load = async ({ url, fetch, cookies }) => { - const type = url.searchParams.get("type"); - const before = url.searchParams.get("before"); - const after = url.searchParams.get("after"); - const byModerator = url.searchParams.get("by-moderator"); - let limit: number = 100; - if (url.searchParams.has("limit")) limit = parseInt(url.searchParams.get("limit")!); - - const params = new URLSearchParams(); - params.set("limit", limit.toString()); - if (type) params.set("type", type); - if (before) params.set("before", before); - if (after) params.set("after", after); - if (byModerator) params.set("by-moderator", byModerator); - - const entries = await apiRequest( - "GET", - `/moderation/audit-log?${params.toString()}`, - { - fetch, - cookies, - }, - ); - - const moderators = await apiRequest("GET", "/moderation/audit-log/moderators", { - fetch, - cookies, - }); - - let modFilter: AuditLogEntity | null = null; - if (byModerator) - modFilter = entries.find((e) => e.moderator.id === byModerator)?.moderator || null; - - return { entries, type, before, after, modFilter, url: url.toString(), moderators }; -}; diff --git a/Foxnouns.Frontend/src/routes/admin/audit-log/+page.svelte b/Foxnouns.Frontend/src/routes/admin/audit-log/+page.svelte deleted file mode 100644 index 0c1cf72..0000000 --- a/Foxnouns.Frontend/src/routes/admin/audit-log/+page.svelte +++ /dev/null @@ -1,115 +0,0 @@ - - - - Audit log • pronouns.cc - - -

Audit log

- -
- - - Filter by type - - - - Ignore report - - - Warn user - - - Warn user and clear profile - - - Suspend user - - - Query sensitive user data - - {#if data.type} - Remove filter - {/if} - - - - - Filter by moderator - - - {#each data.moderators as mod (mod.id)} - - {mod.username} - - {/each} - {#if data.modFilter} - Remove filter - {/if} - - -
- -{#if data.before} - Show newer entries -{/if} - -{#each data.entries as entry (entry.id)} - -{:else} -

There are no entries matching your filter

-{/each} - -{#if data.entries.length === 100} - Show older entries -{/if} diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts deleted file mode 100644 index 90a284e..0000000 --- a/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { apiRequest } from "$api"; -import { redirect } from "@sveltejs/kit"; - -export const actions = { - default: async ({ request, fetch, cookies }) => { - const body = await request.formData(); - const query = body.get("query") as string; - const fuzzy = body.get("fuzzy") === "yes"; - - const users = await apiRequest>( - "POST", - "/moderation/lookup", - { - fetch, - cookies, - body: { - query, - fuzzy, - }, - }, - ); - - if (!fuzzy && users.length > 0) redirect(303, `/admin/lookup/${users[0].id}`); - - return { users }; - }, -}; diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte b/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte deleted file mode 100644 index b3c8a8d..0000000 --- a/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - Look up a user • pronouns.cc - - -

Look up a user

- -
-
- - -
-
- - -
-
- -
- {#each form?.users || [] as user (user.id)} - - {user.username} ({user.id}) - - {:else} -
No results
- {/each} -
diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts deleted file mode 100644 index 130ae90..0000000 --- a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { apiRequest } from "$api"; -import type { QueriedUser } from "$api/models/moderation"; - -export const load = async ({ params, fetch, cookies }) => { - const user = await apiRequest("GET", `/moderation/lookup/${params.id}`, { - fetch, - cookies, - }); - - return { user }; -}; diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte deleted file mode 100644 index e3cf389..0000000 --- a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte +++ /dev/null @@ -1,63 +0,0 @@ - - - - Looking up @{data.user.user.username} • pronouns.cc - - -

Basic profile

- - - - - -

Extra information

- - - - - - - - - - - - - - - - -
Created at{createdAt.toLocaleString(DateTime.DATETIME_MED)}
Last active{lastActive.toLocaleString(DateTime.DATETIME_MED)}
Last SID reroll{lastSidReroll.toLocaleString(DateTime.DATETIME_MED)}
- -{#if authMethods} -

Authentication methods

-
- {#each authMethods as method (method.id)} - - {/each} -
-{/if} diff --git a/Foxnouns.Frontend/src/routes/admin/reports/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/reports/+page.server.ts deleted file mode 100644 index c2149c1..0000000 --- a/Foxnouns.Frontend/src/routes/admin/reports/+page.server.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { apiRequest } from "$api"; -import type { Report } from "$api/models/moderation"; - -export const load = async ({ url, fetch, cookies }) => { - const before = url.searchParams.get("before"); - const after = url.searchParams.get("after"); - const byReporter = url.searchParams.get("by-reporter"); - const byTarget = url.searchParams.get("by-target"); - const includeClosed = url.searchParams.get("include-closed") === "true"; - - const params = new URLSearchParams(); - if (before) params.set("before", before); - if (after) params.set("after", after); - if (byReporter) params.set("by-reporter", byReporter); - if (byTarget) params.set("by-target", byTarget); - if (includeClosed) params.set("include-closed", "true"); - - const reports = await apiRequest("GET", `/moderation/reports?${params.toString()}`, { - fetch, - cookies, - }); - return { reports, url: url.toString(), includeClosed, byReporter, byTarget, before, after }; -}; diff --git a/Foxnouns.Frontend/src/routes/admin/reports/+page.svelte b/Foxnouns.Frontend/src/routes/admin/reports/+page.svelte deleted file mode 100644 index 5021846..0000000 --- a/Foxnouns.Frontend/src/routes/admin/reports/+page.svelte +++ /dev/null @@ -1,138 +0,0 @@ - - - - Reports • pronouns.cc - - -

Reports

- -
    - {#if data.byTarget} -
  • Filtering by target (clear)
  • - {/if} - {#if data.byReporter} -
  • Filtering by reporter (clear)
  • - {/if} - {#if data.includeClosed} -
  • Showing all reports (only show open reports)
  • - {:else} -
  • Showing open reports (show all reports)
  • - {/if} -
- -{#if data.before} - Show newer reports -{/if} - - - - - - - - - - - - - - - {#each data.reports as report (report.id)} - - - - - - - - - - {/each} - -
UserMemberReporterReasonContext?Created at
- - - Open report - - - @{report.target_user.username} - ( - {#if data.byTarget === report.target_user.id}{:else}{/if} - ) - - {#if report.target_member} - - {report.target_member.name} - - {:else} - (none) - {/if} - - {report.reporter.username} - ( - {#if data.byReporter === report.reporter.id}{:else}{/if} - ) - {report.reason} - {#if report.context} - {$t("yes")} - {:else} - {$t("no")} - {/if} - - {idTimestamp(report.id).toLocaleString(DateTime.DATETIME_SHORT)} -
- -{#if data.reports.length === 100} - Show older reports -{/if} diff --git a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts deleted file mode 100644 index 214049a..0000000 --- a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.server.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { apiRequest } from "$api"; -import type { ReportDetails } from "$api/models/moderation"; -import { createModactions } from "$lib/actions/modaction"; - -export const load = async ({ params, fetch, cookies }) => { - const resp = await apiRequest("GET", `/moderation/reports/${params.id}`, { - fetch, - cookies, - }); - return { - report: resp.report, - user: resp.user, - member: resp.member, - auditLogEntry: resp.audit_log_entry, - }; -}; - -export const actions = createModactions(); diff --git a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte deleted file mode 100644 index 8a1ae08..0000000 --- a/Foxnouns.Frontend/src/routes/admin/reports/[id]/+page.svelte +++ /dev/null @@ -1,99 +0,0 @@ - - - - Report on @{user.username} • pronouns.cc - - -{#if report.status === "CLOSED"} -
- This report has already been handled. See audit log entry -
-{/if} - -
-
-

Target user

- -
- {#if report.target_member} -
-

Target member

- -
- {/if} -
-

Reporter

- -
-
- -
-
-

Reason

-

{report.reason}

-
-
-

Context

-

- {#if report.context} - - {@html renderMarkdown(report.context)} - {:else} - (no context given) - {/if} -

-
-
- -{#if report.status === "OPEN"} -
-

Take action

- -
-{:else if report.status === "CLOSED" && auditLogEntry} - -{:else} -
-

Closed by an unknown moderator

-

- This should not happen! -

-
-{/if} - -{#if report.snapshot} -

Profile at time of report

-
- {#if report.target_type === "USER"} - {@const snapshot = report.snapshot as User} - - {:else} - {@const snapshot = report.snapshot as Member} - - {/if} -{/if} diff --git a/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.server.ts index b297e25..dc66812 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.server.ts @@ -1,3 +1,8 @@ import createCallbackLoader from "$lib/actions/callback"; +import createRegisterAction from "$lib/actions/register"; export const load = createCallbackLoader("discord"); + +export const actions = { + default: createRegisterAction("/auth/discord/register"), +}; diff --git a/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.svelte b/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.svelte index 10fec06..e82f0f1 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.svelte +++ b/Foxnouns.Frontend/src/routes/auth/callback/discord/+page.svelte @@ -1,11 +1,12 @@ @@ -16,7 +17,15 @@ {#if data.error}

{$t("auth.register-with-discord")}

- {:else} + {:else if data.isLinkRequest} + {:else} + {/if}
diff --git a/Foxnouns.Frontend/src/routes/auth/callback/google/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/callback/google/+page.server.ts index d3e1b93..49f963c 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/google/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/callback/google/+page.server.ts @@ -1,3 +1,8 @@ import createCallbackLoader from "$lib/actions/callback"; +import createRegisterAction from "$lib/actions/register"; export const load = createCallbackLoader("google"); + +export const actions = { + default: createRegisterAction("/auth/google/register"), +}; diff --git a/Foxnouns.Frontend/src/routes/auth/callback/google/+page.svelte b/Foxnouns.Frontend/src/routes/auth/callback/google/+page.svelte index eeff070..284806a 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/google/+page.svelte +++ b/Foxnouns.Frontend/src/routes/auth/callback/google/+page.svelte @@ -1,11 +1,12 @@ @@ -16,7 +17,15 @@ {#if data.error}

{$t("auth.register-with-google")}

- {:else} + {:else if data.isLinkRequest} + {:else} + {/if}
diff --git a/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.server.ts index c2d290e..b092b1e 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.server.ts @@ -1,5 +1,6 @@ import ApiError, { ErrorCode } from "$api/error"; import createCallbackLoader from "$lib/actions/callback"; +import createRegisterAction from "$lib/actions/register"; export const load = createCallbackLoader("fediverse", async ({ params, url }) => { const code = url.searchParams.get("code") as string | null; @@ -9,3 +10,7 @@ export const load = createCallbackLoader("fediverse", async ({ params, url }) => return { code: code || token, state, instance: params.instance! }; }); + +export const actions = { + default: createRegisterAction("/auth/fediverse/register"), +}; diff --git a/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.svelte b/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.svelte index fdc8d7a..99bd00c 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.svelte +++ b/Foxnouns.Frontend/src/routes/auth/callback/mastodon/[instance]/+page.svelte @@ -1,11 +1,12 @@ @@ -16,7 +17,15 @@ {#if data.error}

{$t("auth.register-with-mastodon")}

- {:else} + {:else if data.isLinkRequest} + {:else} + {/if} diff --git a/Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.svelte b/Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.svelte deleted file mode 100644 index 6d1b6fc..0000000 --- a/Foxnouns.Frontend/src/routes/auth/callback/register/[ticket]/+page.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - - {$t(`auth.register-with-${data.type}`)} • pronouns.cc - - -
- -
diff --git a/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.server.ts index 813f19e..49346f1 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.server.ts @@ -1,3 +1,8 @@ import createCallbackLoader from "$lib/actions/callback"; +import createRegisterAction from "$lib/actions/register"; export const load = createCallbackLoader("tumblr"); + +export const actions = { + default: createRegisterAction("/auth/tumblr/register"), +}; diff --git a/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.svelte b/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.svelte index 7a43261..c7c53e9 100644 --- a/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.svelte +++ b/Foxnouns.Frontend/src/routes/auth/callback/tumblr/+page.svelte @@ -1,11 +1,12 @@ @@ -16,7 +17,15 @@ {#if data.error}

{$t("auth.register-with-tumblr")}

- {:else} + {:else if data.isLinkRequest} + {:else} + {/if} diff --git a/Foxnouns.Frontend/src/routes/auth/log-in/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/log-in/+page.server.ts index 579ea67..9c6bf25 100644 --- a/Foxnouns.Frontend/src/routes/auth/log-in/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/log-in/+page.server.ts @@ -2,15 +2,15 @@ import { isRedirect, redirect } from "@sveltejs/kit"; import { apiRequest } from "$api"; import type { AuthResponse, AuthUrls } from "$api/models/auth"; -import { alertKey, setToken } from "$lib"; +import { setToken } from "$lib"; import ApiError, { ErrorCode } from "$api/error"; -export const load = async ({ fetch, parent, url }) => { +export const load = async ({ fetch, parent }) => { const parentData = await parent(); if (parentData.meUser) redirect(303, `/@${parentData.meUser.username}`); const urls = await apiRequest("POST", "/auth/urls", { fetch, isInternal: true }); - return { urls, alertKey: alertKey(url) }; + return { urls }; }; export const actions = { diff --git a/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte b/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte index 3efbfa0..c6c47a9 100644 --- a/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte +++ b/Foxnouns.Frontend/src/routes/auth/log-in/+page.svelte @@ -3,7 +3,6 @@ import { t } from "$lib/i18n"; import { enhance } from "$app/forms"; import ErrorAlert from "$components/ErrorAlert.svelte"; - import UrlAlert from "$components/URLAlert.svelte"; type Props = { data: PageData; form: ActionData }; let { data, form }: Props = $props(); @@ -14,7 +13,6 @@
-
{#if form?.error} @@ -50,13 +48,8 @@
{/if}
- {#if data.urls.email_enabled} -

{$t("auth.log-in-3rd-party-header")}

-

{$t("auth.log-in-3rd-party-desc")}

- {:else} -

{$t("title.log-in")}

-

{$t("auth.log-in-3rd-party-desc-no-email")}

- {/if} +

{$t("auth.log-in-3rd-party-header")}

+

{$t("auth.log-in-3rd-party-desc")}

{#if data.urls.discord} diff --git a/Foxnouns.Frontend/src/routes/auth/welcome/+page.server.ts b/Foxnouns.Frontend/src/routes/auth/welcome/+page.server.ts index 4b76df2..88baf97 100644 --- a/Foxnouns.Frontend/src/routes/auth/welcome/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/auth/welcome/+page.server.ts @@ -2,5 +2,5 @@ import { redirect } from "@sveltejs/kit"; export const load = async ({ parent }) => { const { meUser } = await parent(); - if (!meUser) redirect(303, "/auth/log-in?alert=auth-required"); + if (!meUser) redirect(303, "/auth/log-in"); }; diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts b/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts deleted file mode 100644 index 1d9e8fc..0000000 --- a/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { baseRequest } from "$api"; -import ApiError from "$api/error"; - -export const load = async ({ fetch, params }) => { - const resp = await baseRequest("GET", `/meta/page/${params.page}`, { fetch }); - if (resp.status < 200 || resp.status > 299) { - const err = await resp.json(); - if ("code" in err) throw new ApiError(err); - else throw new ApiError(); - } - - const pageText = await resp.text(); - return { page: params.page, text: pageText }; -}; diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte b/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte deleted file mode 100644 index 3af7b11..0000000 --- a/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - - {title} • pronouns.cc - - -
- - {@html md} -
diff --git a/Foxnouns.Frontend/src/routes/report/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/report/[id]/+page.server.ts deleted file mode 100644 index 5d36696..0000000 --- a/Foxnouns.Frontend/src/routes/report/[id]/+page.server.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { apiRequest, fastRequest } from "$api"; -import ApiError from "$api/error.js"; -import type { Member } from "$api/models/member.js"; -import { type CreateReportRequest, ReportReason } from "$api/models/moderation.js"; -import type { PartialUser, User } from "$api/models/user.js"; -import log from "$lib/log.js"; -import { redirect } from "@sveltejs/kit"; - -export const load = async ({ parent, params, fetch, cookies, url }) => { - const { meUser } = await parent(); - if (!meUser) redirect(303, "/"); - - let user: PartialUser; - let member: Member | null = null; - if (url.searchParams.has("member")) { - const resp = await apiRequest( - "GET", - `/users/${params.id}/members/${url.searchParams.get("member")}`, - { fetch, cookies }, - ); - - user = resp.user; - member = resp; - } else { - user = await apiRequest("GET", `/users/${params.id}`, { fetch, cookies }); - } - - if (meUser.id === user.id) redirect(303, "/"); - - return { user, member }; -}; - -export const actions = { - default: async ({ request, fetch, cookies }) => { - const body = await request.formData(); - - const targetIsMember = body.get("target-type") === "member"; - const target = body.get("target-id") as string; - const reason = body.get("reason") as ReportReason; - const context = body.get("context") as string | null; - - const url = targetIsMember - ? `/moderation/report-member/${target}` - : `/moderation/report-user/${target}`; - - try { - await fastRequest("POST", url, { - body: { reason, context }, - fetch, - cookies, - }); - - return { ok: true, error: null }; - } catch (e) { - if (e instanceof ApiError) return { ok: false, error: e.obj }; - log.error("error reporting user or member %s:", target, e); - throw e; - } - }, -}; diff --git a/Foxnouns.Frontend/src/routes/report/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/report/[id]/+page.svelte deleted file mode 100644 index a4ce0ac..0000000 --- a/Foxnouns.Frontend/src/routes/report/[id]/+page.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - - - {$t("report.title", { name })} • pronouns.cc - - -
- -

{$t("report.title", { name })}

- - - - -

{$t("report.reason-label")}

-
- {#each reasons as reason} -
-
- - -
-
- {/each} -
- -

- {$t("report.context-label")} - -

- - -
- - {$t("cancel")} -
- -
diff --git a/Foxnouns.Frontend/src/routes/settings/+layout.server.ts b/Foxnouns.Frontend/src/routes/settings/+layout.server.ts index 95228f0..fe2eaa3 100644 --- a/Foxnouns.Frontend/src/routes/settings/+layout.server.ts +++ b/Foxnouns.Frontend/src/routes/settings/+layout.server.ts @@ -2,7 +2,7 @@ import { redirect } from "@sveltejs/kit"; export const load = async ({ parent }) => { const data = await parent(); - if (!data.meUser) redirect(303, "/auth/log-in?alert=auth-required"); + if (!data.meUser) redirect(303, "/auth/log-in"); return { user: data.meUser!, token: data.token! }; }; diff --git a/Foxnouns.Frontend/src/routes/settings/+layout.svelte b/Foxnouns.Frontend/src/routes/settings/+layout.svelte index 8d660ea..6786e63 100644 --- a/Foxnouns.Frontend/src/routes/settings/+layout.svelte +++ b/Foxnouns.Frontend/src/routes/settings/+layout.svelte @@ -1,30 +1,26 @@ {$t("title.settings")} • pronouns.cc -{#if data.meta.notice} -
- -
-{/if} -